在Python中快速有效地检测两个图像在视觉上是否相同

问题描述 投票:0回答:5

给定两张图像:

image1.jpg
image2.jpg

在 Python 中,有什么快速方法可以检测它们在视觉上是否相同?例如,它们可能具有不同的 EXIF 数据,这会产生不同的校验和,即使图像数据相同)。

Imagemagick 有一个出色的工具“识别”,可以生成图像的视觉哈希,但它非常消耗处理器资源。

python imagemagick imagemagick-identify
5个回答
26
投票

使用 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")

15
投票

仍然提交我的方法来解决这个问题——即使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

pH哈希值差值

最新版本的 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 

Visualization of differences: <code>ref1.pdf</code>(右)、<code>ref3.pdf</code>(中)和 <code>ref1-ref3-delta.png</code>(右)

如您所见,

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 

Visualization of differences: <code>ref1.pdf</code>(右)、<code>ref2.pdf</code>(中)和 <code>ref1-ref2-delta.png</code>(右)

如您所见,在 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
之间的差异。

现在在视觉比较中清楚地突出了差异,即使只有一条细线的红色像素:


2
投票

使用 https://github.com/andrewekhalel/sewar 比较图像相似

> from sewar.full_ref import uqi
> uqi(img1,img2)
0.9586952304831419

2
投票

在 Python/OpenCV 中实现此目的的一种方法是获取absdiff,然后获取整个absdiff图像的absdiff的平均值。

输入1(PNG):

enter image description here

输入2(JPG):

enter image description here

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

1
投票

只是因为还没有人提到过,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
© www.soinside.com 2019 - 2024. All rights reserved.