保存图像期间 PIL 中的“SystemError:tile 无法扩展到图像外部”

Posted

技术标签:

【中文标题】保存图像期间 PIL 中的“SystemError:tile 无法扩展到图像外部”【英文标题】:"SystemError: tile cannot extend outside image" in PIL during save image 【发布时间】:2017-08-24 14:46:36 【问题描述】:

我有这张图片 =>

这里是写在3.txt文件中的以上黄色框的所有坐标。

#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 

我的意图是裁剪这些框并将所有框保存为图像。我为此编写了一个代码,但出现错误。

这是我的代码 =>

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

我收到这些错误 =>

Traceback(最近一次调用最后一次):文件“reshape.py”,第 26 行,在 img2.save(name) 文件“/usr/lib/python2.7/dist-packages/PIL/Image.py”,第 1468 行,保存中 save_handler(self, fp, filename) 文件“/usr/lib/python2.7/dist-packages/PIL/PngImagePlugin.py”,第 624 行,在 _保存 ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)]) 文件 "/usr/lib/python2.7/dist-packages/ PIL/ImageFile.py", 第 462 行,在 _save e.setimage(im.im, b) SystemError: tile cannot extend outside image

我该如何解决这些问题?

【问题讨论】:

错误状态 * 瓦片不能延伸到图像之外*,这意味着您正在尝试裁剪超出图像尺寸的区域。检查文本文件是否包含正确的坐标。您可能会对图像的坐标系感到困惑(我认为)。在继续之前一定要复习一下…… 谢谢,我想你是 r8。 @JeruLuke 在这样做之后 => img2 = img.crop((int(ARR[0][0]), int(ARR[0][1]), int(ARR[0][0] ] + ARR[0][2]), int(ARR[0][1] + ARR[0][3]))) 它正在工作,谢谢@JeruLuke 太棒了!我在 OpenCV 中多次犯过同样的错误 【参考方案1】:

参考 cmets,错误是由于坐标传递给 PIL 的 crop() 函数不正确造成的。

如the documentation 中所述,该函数返回一个已拍摄四元组(xywidthheight)的图像。

在给定的文本文件中,第一列中提到了y 坐标,第二列中提到了x 坐标。但是,crop() 函数接受 x 坐标的值作为第一个参数,y 坐标作为第二个参数。

同样适用于 OpenCV

这里是ANOTHER POST 相同的。

【讨论】:

指出对我来说 AmirHosseins 的答案实际上是正确的。参数是imageScreenshot.crop((x, y, x + width, y + height)) 而不是imageScreenshot.crop((x, y, width, height)) Pillow doc says both are correct,虽然我发现上面的答案工作正常。 我在相应的文档中看不到此类信息。它说“四个坐标;左、上、右、下”。这意味着该函数采用区域的四个坐标。最后两个参数不是宽度和高度。相反,x+width 和 y+height 如文档中所述。也许人们会因为其他需要 (x,y,width,height) 的函数而感到困惑(例如 ImageDraw.rectangle)。【参考方案2】:

网上提到的方式是这样的:

imageScreenshot.crop((x, y, width, height))

但正确的做法是这样的:

imageScreenshot.crop((x, y, x + width, y + height))

这意味着您应该将x 添加到widthyheight。 这是一个简单的例子(driver 用于 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)

希望对你有帮助。

【讨论】:

【参考方案3】:

在我的情况下,问题是我指定了开始和结束坐标,其中开始 X 和开始 Y 并不总是小于结束 X 和 Y。你不能这样做。

例如,

开始:(0, 50) 结束: (50, 0)

这些坐标对我来说是有意义的,但实际上应该指定为:

开始:(0, 0) 结束: (50, 50)

视觉上相同的矩形,但后者是 Pillow 裁剪所必需的。

【讨论】:

【参考方案4】:

如果您使用 DeepLearning 软件来检测图像中的对象并且您正在尝试减少检测 - 您很可能会看到这种情况

我在使用ImageAI 检测图像中的对象时遇到了同样的错误。 我已经设法通过在我的虚拟环境中编辑 PIL 包中的 ImageFile.py 来解决它。

ImageFile 位于

\home\myuser\anaconda3\envs\envsName\lib\python3.7\site-packages\PIL\ImageFile.py

查找 _save 开头的函数行:

def _save(im, fp, tile, bufsize=0):

之后:

 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.

插入:

tile = [e for e in tile if e[1][2] > 0 and e[1][3]>0]

这将跳过保存图像(平铺)的宽度和高度尺寸不正确的所有检测,有时报告为 0,可能是因为检测到的对象仅部分显示在图像边缘。

------------

但是,例如,如果您知道所有图像都是 1920x1080 并且您想要丢弃所有未报告的尺寸大致相同的图像,那么您可以这样做。

tile = [e for e in tile if e[1][2] > 1720 and e[1][3]>880]

宽度和高度减少了 200 像素,以便保存更小、可能仍然正确的图像(图块),这将丢弃所有其他图像。

Source.

【讨论】:

以上是关于保存图像期间 PIL 中的“SystemError:tile 无法扩展到图像外部”的主要内容,如果未能解决你的问题,请参考以下文章

使用 PIL 保存图像

Django / PIL - 上传图像时保存缩略图版本

标签中的Python PIL图像自动调整大小

旋转后Python PIL保存图像

通过套接字发送pil图像而不保存python

markdown 使用PIL(枕头)模块读取和保存图像