我不会在这里使用ImageChops.difference,因为它无法处理不同的图像modes,参见
from PIL import Image, ImageChops
# Read images
img1 = Image.open('image.png').convert('L')
img2 = Image.open('image.png').convert('L').convert('F')
diff = ImageChops.difference(img1, img2)
虽然两个图像是相同的(w.r.t. 像素的强度),但我们得到以下ValueError:
Traceback (most recent call last):
File "...", line 7, in <module>
diff = ImageChops.difference(img1, img2)
File "...\lib\site-packages\PIL\ImageChops.py", line 102, in difference
return image1._new(image1.im.chop_difference(image2.im))
ValueError: images do not match
一般来说,我同意使用 NumPy 的矢量化能力来加速计算,但也可能有这种非常简单的 Pillow only 方法:
- 检查波段数。如果它们不匹配,则图像必须不同。
- 手动计算每个像素的绝对强度差异(即
ImageChops.difference 实际执行的操作),但请确保支持任意两种图像模式。这对于单通道和多通道图像略有不同。
- 按照之前的建议对所有像素求和。如果该总和大于
0,则图像必须不同。
那是我的代码:
from PIL import Image
# Read images
img1 = Image.open('path/to/your/image.png').convert('RGB')
img2 = Image.open('path/to/your/image.png').convert('RGB')
# Check for different number of channels
if img1.im.bands != img2.im.bands:
print('Images are different; number of channels do not match.')
exit(-1)
# Get image (pixel) data
imdata1 = list(img1.getdata())
imdata2 = list(img2.getdata())
# Calculate pixel-wise absolute differences, and sum those differences
diff = 0
if img1.im.bands == 1:
diff = sum([abs(float(i1) - float(i2)) for i1, i2 in zip(imdata1, imdata2)])
else:
diff = sum([abs(float(i1) - float(i2)) for i1, i2 in
zip([i for p in imdata1 for i in p],
[i for p in imdata2 for i in p])])
if diff > 0:
print('Images are different; pixel-wise difference > 0.')
exit(-1)
print('Images are the same.')
对于某些图像,代码原样返回:
Images are the same.
另外,对于开头提到的情况,我们会得到这个输出。然而,对于一些输入,如
img1 = Image.open('image.png').convert('L')
img2 = Image.open('image.png').convert('F')
最有可能的输出是:
Images are different; pixel-wise difference > 0.
直接转换为模式F 将导致单个强度值的一些小数部分,因此与普通转换为模式L 存在差异。
如果您有代码失败的用例,请告诉我。我很好奇,如果我在这里错过了一些边缘情况!
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
PyCharm: 2021.1.1
Pillow: 8.2.0
----------------------------------------