使用Pillow和OpenCV打开的图片不等同。

4
我从维基百科下载了一个测试图片(下面看到的树),用Python中的PillowOpenCV(使用cv2)进行比较。在感知上,这两个图像看起来相同,但它们各自的md5哈希值不匹配;如果我对两个图像进行减法操作,结果甚至远非纯黑色(原始图像下方显示的图像)。原始图像是JPEG格式。如果我先将其转换为PNG格式,则哈希值将匹配。
最后一张图片显示了像素值差异的频率分布情况。
正如Catree所指出的那样,我的减法操作导致整数溢出。我更新了代码,在减法操作之前将其转换为dtype=int(以显示负值),然后在绘制差异之前取绝对值。现在,差异图像在感知上是纯黑色的。
这是我使用的代码:
from PIL import Image
import cv2
import sys
import md5
import numpy as np

def hashIm(im):
    imP = np.array(Image.open(im))

    # Convert to BGR and drop alpha channel if it exists
    imP = imP[..., 2::-1]
    # Make the array contiguous again
    imP = np.array(imP)
    im = cv2.imread(im)

    diff = im.astype(int)-imP.astype(int)

    cv2.imshow('cv2', im)
    cv2.imshow('PIL', imP)
    cv2.imshow('diff', np.abs(diff).astype(np.uint8))
    cv2.imshow('diff_overflow', diff.astype(np.uint8))

    with open('dist.csv', 'w') as outfile:
        diff = im-imP
        for i in range(-256, 256):
            outfile.write('{},{}\n'.format(i, np.count_nonzero(diff==i)))

    cv2.waitKey(0)
    cv2.destroyAllWindows()

    return md5.md5(im).hexdigest() + '   ' + md5.md5(imP).hexdigest()

if __name__ == '__main__':
    print sys.argv[1] + '\t' + hashIm(sys.argv[1])

Original photo of a tree (from Wikipedia "Tree" article)

频率分布已更新,可显示负值。

Updated difference


在我实施Catree建议的更改之前,这就是我看到的。

Difference

Dist


我可能错了,但我认为你在这里可能遭受了舍入误差 np.array(Image.open(im)),并且如果我没记错的话,imshow会拉伸颜色以满足范围(查看 im-imP 的实际值,它们可能非常小)。 - Nullman
既然Joost能够无问题地运行它,也许你使用的库版本确实有所不同。你使用的是哪个版本? - Nullman
@Joost 很有趣... 当我将图像上传到 SO 时,它可能已被重新编码。如果你还没有尝试过,请问你能否使用原始图片 - chew socks
@Nullman 我使用的是Ubuntu 16.04操作系统,Python版本为2.7.12,opencv版本为2.4.9.1,opencv-python版本为3.4.0.12,numpy版本为1.14.2,Pillow版本为5.1.0。我在一个虚拟环境中工作,所以至少Python库应该是最新的。 - chew socks
我也运行了这段代码(这两行的顺序是反过来的!im = cv2.imread(im)imP = np.array(Image.open(im))),并且对我来说运行得很好。我在Win10上使用Python 3.6.3,cv2版本为3.3.0,pillow版本为4.3.0。 - Nullman
显示剩余5条评论
1个回答

5

原始图像是JPEG格式。

JPEG解码的结果会受到libjpeg版本、编译器优化、平台等因素的影响而产生不同的结果。

检查PillowOpenCV使用的libjpeg版本。

更多信息请参见此答案:JPEG images have different pixel values across multiple devices这里

顺便说一下,(im-imP)会导致uint8溢出(没有办法有这么高数量级的大像素差异而不在频率图表中看到它)。在进行频率计算之前,请尝试将其转换为int类型。


1
谢谢!我之前不知道关于JPEG的那个问题。我已经更新了我的频率图表,使用了int。结果发现所有的im-imP != 0的值都是负数。我还没有找到确切的版本,但我的OpenCV相当老,它正在使用内置源来处理libjpeg - chew socks

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