使用PIL处理被截断的图像

5

我正在尝试让Python 2.7的PIL库能够处理仅作为流从HDD镜像中获取且不完整的JPEG图像。

我已经设置了选项:

ImageFile.LOAD_TRUNCATED_IMAGES = True

尽可能加载流数据(更确切地说,只要我能够100%确定这个数据仍然是图像,而不是其他文件类型)。我已经尝试了不同的方法,根据我的测试(对于JPEG),只有在发现0xFFDA(扫描开始标记)时,PIL才将其作为有效的JPEG图像接受。以下是我加载数据的简短示例:

from PIL import Image
from StringIO import StringIO

ImageFile.LOAD_TRUNCATED_IMAGES = True

with open("/path/to/image.raw", 'rb') as fp:
    fp.seek("""jump to position in image where JPEG starts""")
    data = fp.read("""number of bytes I know that those belong to that jpeg""")
    img = Image.open(StringIO(data)) # This would throw exception if the data does 
                                     # not contain the 0xffda marker
    pixel = img.load()               # Would throw exception if LOAD_TRUNCATED_IMAGES = false

    height,width = img.size
    for i in range(height):
        for j in range(width):
            print pixel[i,j]

在最后一行,我期望(或者希望)至少会显示读取的像素数据。但对于每个像素,它都返回了(0,0,0)
问题是:我在这里尝试的方式可能使用PIL无法实现吗?
几周前,我使用编辑器剪切数据,从而自己截断了一个图像文件。 对于可用的像素数据,它可以工作。 一旦到达我切掉的像素,程序就会抛出异常(我将在今天晚些时候再次尝试,以确保我没有记错)。
如果有人想知道我为什么要这样做:我需要确保hdd映像中的图像/图片位于连续块/簇中,并且不是碎片化的。 为确保这一点,我想使用像素匹配。
编辑: 我已经再次尝试过了,这就是我所看到的。
- 我在GIMP中打开了一个截断的图像,它向我展示了上部的几行像素,但是PIL无法至少给我这些像素的RGB值。 它总是返回(0,0,0)。 - 我将图像稍微放大,使得下面的四分之四不可见,但这足以让PIL向我显示可用的RGB值。 其他一切都是(0,0,0)。
我仍然不确定是否可以使用PIL显示RGB值,即使只有部分像素数据可用。

你能提供一个可运行的代码吗?例如,ImageFile未定义,seek没有数字等。 - Hugues Fontenelle
@HuguesFontenelle,StringIO也被PIL文档使用。我认为如果没有文件存在,这将是打开图像数据流的正确方法。我今天稍后会添加一个带有示例图片的可运行代码。 - ap0
那么它应该是StringIO而不是StreamIO :-) 一开始看起来不像是打字错误,因为你确实想要流式传输.. - Hugues Fontenelle
Python 2.7已经超过两年的时间被EOLed,不再受支持。您似乎正在使用新代码 - 或者至少只是需要检索图像的代码。只需使用3.10即可。 - jsbueno
第一:如果GIMP可以读取图像中仍然可读的部分,您也可以使用Python自动化它。 (然后,是的,您将不得不使用Python 2- GIMP开发版本2.99支持Python 3,但目前处于粗糙状态) - jsbueno
3个回答

0
我建议使用未压缩格式,比如TGA格式来尝试。由于JPG是一种压缩格式,从不完整的图像中提取像素可能没有意义。实际上,JPEG存储描述图像的方程参数,而不是像素值。当您查询JPEG的像素值时,它会在该点评估方程并返回结果。

不幸的是,我必须找到一种使用JPEG格式完成这个任务的方法。 - ap0

0

我遇到了与 Pillow==9.2.0 相同的问题。

我们降级到 Pillow==8.3.2 就可以解决了。


-2

我并不是特别了解流式传输,但我认为你不能以同样的方式访问RGB值。 尝试:

rgb_im = img.convert('RGB')
r, g, b = rgb_im.getpixel((i, j))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接