给定两张图像:
image1.jpg
image2.jpg
在 Python 中,有什么快速方法可以检测它们在视觉上是否相同?例如,它们可能具有不同的 EXIF 数据,这会产生不同的校验和,即使图像数据相同)。
Imagemagick 有一个出色的工具“识别”,可以生成图像的视觉哈希,但它非常消耗处理器资源。
使用 PIL/枕头:
from PIL import Image
im1 = Image.open('image1.jpg')
im2 = Image.open('image2.jpg')
if list(im1.getdata()) == list(im2.getdata()):
print("Identical")
else:
print("Different")
我仍然提交我的方法来解决这个问题——即使OP说ImageMagick的方法过于处理器密集型(即使我的方法不涉及Python)......也许我的答案对其他人有用,通过搜索引擎到达此页面。
请注意,任何图像比较应该发现高分辨率图像中的精细差异,这比发现低分辨率图像中的巨大差异需要更多的处理器密集度,因为它必须比较很多更多像素。
这是一个 ImageMagick 命令,它比较两个(相同大小!)图像,并将所有不同的像素返回为红色,将相同的像素返回为白色。第一个将参考图像作为淡出背景图像,用于组成红白像素矩阵。
.img
可以是任何 IM 支持的格式(.png、.PnG、.pNG、.PNG、.jpg、.jpeg、.jPeG、.tif、.tiff、.ppm、.gif、.pdf、. ..):
compare reference.img similar.img delta.img
compare reference.img similar.img -compose src delta.img
默认情况下,比较是在 72 PPI 下进行的。如果您需要更高的分辨率(例如基于矢量的图像,例如 PDF 页面),您可以添加
-density
来提高分辨率。当然,处理时间也会相应增加:
compare -density 300 reference.img similar.img delta.img
如果添加模糊因子,您可以告诉 ImageMagick 将所有像素视为相同,且相距不超过一定的颜色距离:
compare -fuzz '3%' reference.img similar.img -compose src delta.img
最新版本的 ImageMagick 支持
phash
算法:
compare -metric phash reference.img similar.img -compose src delta.img
除了创建用于可视化的
delta.img
之外,这还将返回一个指示两个图像之间“差异”的数值。越接近0
,两幅图像比较就越相似。
创建一些小的 PDF 页面,其中有细微的差异。我正在使用 Ghostscript:
gs -o ref1.pdf -sDEVICE=pdfwrite -g1050x1350 \
-c "/Courier findfont 160 scalefont setfont 10.0 10.0 moveto (0) show showpage"
gs -o ref2.pdf -sDEVICE=pdfwrite -g1050x1350
-c "/Courier findfont 160 scalefont setfont 10.1 10.1 moveto (0) show showpage"
gs -o ref3.pdf -sDEVICE=pdfwrite -g1050x1350 \
-c "/Courier findfont 160 scalefont setfont 10.0 10.0 moveto (O) show showpage"
gs -o ref4.pdf -sDEVICE=pdfwrite -g1050x1350 \
-c "/Courier findfont 160 scalefont setfont 10.1 10.1 moveto (O) show showpage"
现在将
ref1.pdf
与默认分辨率 72 PPI 下的 ref3.pdf
进行比较:
compare -metric phash ref1.pdf ref3.pdf delta-ref1-ref3.pdf
7.61662
返回的 pHash 值为
7.61662
。这表明 ImageMagick 的compare
至少发现了一些差异。
让我们看一下可视化。我将创建三个 PDF/图像的并排可视化(如下所示):
convert \
-mattecolor blue \
\( ref1.pdf -frame 2x2 \) \
null: \
\( ref3.pdf -frame 2x2 \) \
null: \
\( delta-ref1-ref3.pdf -frame 2x2 \) \
+append \
ref1-ref3-delta.png
如您所见,
0
(数字“零”)和O
(字母o
,大写版本)的不同形状非常引人注目。
现在下一张:
ref1.pdf
与 ref2.pdf
进行比较,同样是在 72 PPI 下。
compare -metric phash ref1.pdf ref2.pdf delta-ref1-ref2.pdf
0
现在返回的pHash值是
0
。这表明ImageMagick没有发现任何差异!
创建三个 PDF/图像的并排可视化:
convert \
-mattecolor blue \
\( ref1.pdf -frame 2x2 \) \
null: \
\( ref2.pdf -frame 2x2 \) \
null: \
\( delta-ref1-ref2.pdf -frame 2x2 \) \
+append \
ref1-ref2-delta.png
如您所见,在 72 PPI 下,ImageMagick 没有发现两个 PDF 之间的差异(如红色像素所示)。根据 Ghostscript 命令,两者都显示数字
0
,但位置在 x 和 y 方向上相距 0.1 pt。所以实际上,在原始 PDF 中,存在 IS 的差异。但当以 72 PPI 渲染时,这种差异并不明显。
让我们尝试看看与
density 600
的区别:
compare \
-metric phash \
-density 600 \
ref1.pdf \
ref2.pdf \
ref1-ref2-at-density600-delta.png
0.00172769
现在在 600 PPI 时返回的 pHash 值为
0.00172769
。这接近于零,但仍然存在差异。差异小于 ref1.pdf
和 ref3.pdf
之间的差异。
现在在视觉比较中清楚地突出了差异,即使只有一条细线的红色像素:
使用 https://github.com/andrewekhalel/sewar 比较图像相似
> from sewar.full_ref import uqi
> uqi(img1,img2)
0.9586952304831419
在 Python/OpenCV 中实现此目的的一种方法是获取absdiff,然后获取整个absdiff图像的absdiff的平均值。
输入1(PNG):
输入2(JPG):
import cv2
import numpy as np
# read image 1
img1 = cv2.imread('lena.png')
# read image 2
img2 = cv2.imread('lena.jpg')
# do absdiff
diff = cv2.absdiff(img1,img2)
# get mean of absdiff
mean_diff = np.mean(diff)
# print result
print(mean_diff)
1.8992767333984375
只是因为还没有人提到过,Spatial CIELAB 是另一种有用的图像相似性度量。
这比听起来更简单:将两个图像模糊一定程度,模糊程度与观察者的敏锐度相关,然后找到 CIELAB 差异 (delta E)。您可以根据您的应用获取差异图像的峰值或平均值。
使用 pyvips,你可以写:
#!/usr/bin/python3
import sys
import pyvips
# the access hint means these images can be streamed in parallel rather
# than fully decoded
image1 = pyvips.Image.new_from_file(sys.argv[1], access="sequential")
image2 = pyvips.Image.new_from_file(sys.argv[2], access="sequential")
# blur by an amount related to the visual acuity of the observer -- this will
# help remove peaks caused by small alignment differences, then take the
# CIELAB76 colour difference
sigma = 3.0
# diff = image1.gaussblur(sigma).dE76(image2.gaussblur(sigma))
diff = image1.resize(1.0 / sigma).dE76(image2.resize(1.0 / sigma))
# compute the peak difference ... over perhaps 20 means a visible difference
print(f"peak difference of {diff.max()} visual units")
作为一个小的优化,调整大小而不是模糊可以减少计算色差所需的像素数量。
这台电脑将在大约 400 毫秒内计算一对 6k x 4k JPG 的差异。
$ vipsheader ~/pics/theo.jpg
/home/john/pics/theo.jpg: 6048x4032 uchar, 3 bands, srgb, jpegload
$ time ./try51.py ~/pics/theo2.jpg ~/pics/theo.jpg
peak difference of 0.0 visual units
real 0m0.396s
user 0m0.952s
sys 0m0.197s