"SystemError: tile cannot extend outside image" in PIL during save image
Question:
I have this Image =>
here is, all coordinates of above yellow boxes that is written in 3.txt
file.
#Y X Height Width
46 135 158 118
46 281 163 104
67 494 188 83
70 372 194 101
94 591 207 98
252 132 238 123
267 278 189 105
320 741 69 141
322 494 300 135
323 389 390 124
380 726 299 157
392 621 299 108
449 312 227 93
481 161 425 150
678 627 285 91
884 13 650 437
978 731 567 158
983 692 60 43
1402 13 157 114
My intension is to crop those boxes and save all boxes as Image. I have written a code for that but getting error.
Here is my code =>
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from os import listdir
#from scipy.misc import imsave
ARR = np.empty([1,4])
# print(ARR)
i = 0
k = 0
img = Image.open('3.png')
fo = open("3.txt", "r")
for line in fo:
if not line.startswith('#'):
for word in line.split():
ARR[0][i] = int(word)
print(int(word))
# ARR[0][i] = int(word)
i = i +1
img2 = img.crop((int(ARR[0][1]), int(ARR[0][0]), int(ARR[0][0] + ARR[0][2]), int(ARR[0][1] + ARR[0][3])))
name = "new-img" + str(k) + ".png"
img2.save(name)
k = k + 1
i = 0
I am getting these error =>
Traceback (most recent call last): File “reshape.py”, line 26, in
img2.save(name) File “/usr/lib/python2.7/dist-packages/PIL/Image.py”, line 1468, in save
save_handler(self, fp, filename) File “/usr/lib/python2.7/dist-packages/PIL/PngImagePlugin.py”, line 624, in
_save
ImageFile._save(im, _idat(fp, chunk), [(“zip”, (0,0)+im.size, 0, rawmode)]) File “/usr/lib/python2.7/dist-packages/PIL/ImageFile.py”,
line 462, in _save
e.setimage(im.im, b) SystemError: tile cannot extend outside image
How do I fix these?
Answers:
With reference to the comments, the error occurred due to improper passing of the coordinates to PIL’s crop()
function.
As mentioned in the documentation, the function returns an image having taken in a tuple of four (x
, y
, width
and height
).
In the given text file the y
coordinate is mentioned in the first column and x
coordinate in the second column. The crop()
function however accepts the value of x
coordinate as the first parameter and the y
coordinate as the second parameter.
The same applies for OpenCV as well.
In my case the issue was that I was specifying start and end coordinates where the start X and start Y were not always less than the end X and Y. You cannot do this.
For example,
Start: (0, 50)
End: (50, 0)
These coordinates make sense to me, but should actually be specified as:
Start: (0, 0)
End: (50, 50)
Visually the same rectangle, but the latter is required for Pillow to crop.
The mentioned way on the internet is like this:
imageScreenshot.crop((x, y, width, height))
But the correct way is this:
imageScreenshot.crop((x, y, x + width, y + height))
Meaning that you should add the x
to the width
and y
to the height
.
This is a simple example (driver
is for python selenium):
def screenShotPart(x, y, width, height) -> str:
screenshotBytes = driver.get_screenshot_as_png()
imageScreenshot = Image.open(BytesIO(screenshotBytes))
imageScreenshot = imageScreenshot.crop((x, y, x + width, y + height))
imagePath = pathPrefix + "_____temp_" + str(time.time()).replace(".", "") + ".png"
imageScreenshot.save(imagePath)
Hope it helps.
If you are using DeepLearning software to detect objects in image and you are trying to cut detections out – you will most likely see this
I had same error while using ImageAI for detecting objects in image.
I’ve manage to resolve it by editing ImageFile.py
from PIL
package in my virtual environment.
ImageFile is located in
homemyuseranaconda3envsenvsNamelibpython3.7site-packagesPILImageFile.py
Find _save function line that starts with:
def _save(im, fp, tile, bufsize=0):
After:
tile.sort(key=_tilesort)
# FIXME: make MAXBLOCK a configuration parameter
# It would be great if we could have the encoder specify what it needs
# But, it would need at least the image size in most cases. RawEncode is
# a tricky case.
Insert:
tile = [e for e in tile if e[1][2] > 0 and e[1][3]>0]
This will skip saving of all detections which have incorrect sizes for width and height of image (tile) which is sometimes reported to be 0, probably because detected object is only partially shown on edge of the image.
————
But if you for example have case where you know that all your images are 1920×1080 and you want to discard all images that are not reported with approximately same size than you can do something like this.
tile = [e for e in tile if e[1][2] > 1720 and e[1][3]>880]
width and height are reduced for 200px to allow smaller, maybe still correct images(tiles), to be saved and this will discard all other images.
i faced same issue during cropping objects based on annotation txt but the code was correct not as they said above that:
imageScreenshot.crop((x, y, width, height))
should be
imageScreenshot.crop((x, y, x + width, y + height))
the error was in annotation valuse was 0 I edited the value and solved the issue
my code was
tmp = [x1, y1, x2, y2]
img2 = img.crop(tmp)
sav_path = 'valid/result' + '/' + l[0] + '/' + str(linec) + img_name[1]
img2 = img2.save(sav_path)`
I have this Image =>
here is, all coordinates of above yellow boxes that is written in 3.txt
file.
#Y X Height Width
46 135 158 118
46 281 163 104
67 494 188 83
70 372 194 101
94 591 207 98
252 132 238 123
267 278 189 105
320 741 69 141
322 494 300 135
323 389 390 124
380 726 299 157
392 621 299 108
449 312 227 93
481 161 425 150
678 627 285 91
884 13 650 437
978 731 567 158
983 692 60 43
1402 13 157 114
My intension is to crop those boxes and save all boxes as Image. I have written a code for that but getting error.
Here is my code =>
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from os import listdir
#from scipy.misc import imsave
ARR = np.empty([1,4])
# print(ARR)
i = 0
k = 0
img = Image.open('3.png')
fo = open("3.txt", "r")
for line in fo:
if not line.startswith('#'):
for word in line.split():
ARR[0][i] = int(word)
print(int(word))
# ARR[0][i] = int(word)
i = i +1
img2 = img.crop((int(ARR[0][1]), int(ARR[0][0]), int(ARR[0][0] + ARR[0][2]), int(ARR[0][1] + ARR[0][3])))
name = "new-img" + str(k) + ".png"
img2.save(name)
k = k + 1
i = 0
I am getting these error =>
Traceback (most recent call last): File “reshape.py”, line 26, in
img2.save(name) File “/usr/lib/python2.7/dist-packages/PIL/Image.py”, line 1468, in save
save_handler(self, fp, filename) File “/usr/lib/python2.7/dist-packages/PIL/PngImagePlugin.py”, line 624, in
_save
ImageFile._save(im, _idat(fp, chunk), [(“zip”, (0,0)+im.size, 0, rawmode)]) File “/usr/lib/python2.7/dist-packages/PIL/ImageFile.py”,
line 462, in _save
e.setimage(im.im, b) SystemError: tile cannot extend outside image
How do I fix these?
With reference to the comments, the error occurred due to improper passing of the coordinates to PIL’s crop()
function.
As mentioned in the documentation, the function returns an image having taken in a tuple of four (x
, y
, width
and height
).
In the given text file the y
coordinate is mentioned in the first column and x
coordinate in the second column. The crop()
function however accepts the value of x
coordinate as the first parameter and the y
coordinate as the second parameter.
The same applies for OpenCV as well.
In my case the issue was that I was specifying start and end coordinates where the start X and start Y were not always less than the end X and Y. You cannot do this.
For example,
Start: (0, 50)
End: (50, 0)
These coordinates make sense to me, but should actually be specified as:
Start: (0, 0)
End: (50, 50)
Visually the same rectangle, but the latter is required for Pillow to crop.
The mentioned way on the internet is like this:
imageScreenshot.crop((x, y, width, height))
But the correct way is this:
imageScreenshot.crop((x, y, x + width, y + height))
Meaning that you should add the x
to the width
and y
to the height
.
This is a simple example (driver
is for python selenium):
def screenShotPart(x, y, width, height) -> str:
screenshotBytes = driver.get_screenshot_as_png()
imageScreenshot = Image.open(BytesIO(screenshotBytes))
imageScreenshot = imageScreenshot.crop((x, y, x + width, y + height))
imagePath = pathPrefix + "_____temp_" + str(time.time()).replace(".", "") + ".png"
imageScreenshot.save(imagePath)
Hope it helps.
If you are using DeepLearning software to detect objects in image and you are trying to cut detections out – you will most likely see this
I had same error while using ImageAI for detecting objects in image.
I’ve manage to resolve it by editing ImageFile.py
from PIL
package in my virtual environment.
ImageFile is located in
homemyuseranaconda3envsenvsNamelibpython3.7site-packagesPILImageFile.py
Find _save function line that starts with:
def _save(im, fp, tile, bufsize=0):
After:
tile.sort(key=_tilesort)
# FIXME: make MAXBLOCK a configuration parameter
# It would be great if we could have the encoder specify what it needs
# But, it would need at least the image size in most cases. RawEncode is
# a tricky case.
Insert:
tile = [e for e in tile if e[1][2] > 0 and e[1][3]>0]
This will skip saving of all detections which have incorrect sizes for width and height of image (tile) which is sometimes reported to be 0, probably because detected object is only partially shown on edge of the image.
————
But if you for example have case where you know that all your images are 1920×1080 and you want to discard all images that are not reported with approximately same size than you can do something like this.
tile = [e for e in tile if e[1][2] > 1720 and e[1][3]>880]
width and height are reduced for 200px to allow smaller, maybe still correct images(tiles), to be saved and this will discard all other images.
i faced same issue during cropping objects based on annotation txt but the code was correct not as they said above that:
imageScreenshot.crop((x, y, width, height))
should be
imageScreenshot.crop((x, y, x + width, y + height))
the error was in annotation valuse was 0 I edited the value and solved the issue
my code was
tmp = [x1, y1, x2, y2]
img2 = img.crop(tmp)
sav_path = 'valid/result' + '/' + l[0] + '/' + str(linec) + img_name[1]
img2 = img2.save(sav_path)`