比较两个图像python / linux的方式

试图解决防止重复图像上传的问题。

我有两个JPG。 看着他们,我可以看到他们实际上是相同的。 但由于某种原因,他们有不同的文件大小(一个从备份中拉出来,另一个是另一个上传),所以他们有不同的md5校验和。

我怎样才能有效和自信地比较两幅图像,就像人类能够看到它们是完全一样的?

例如: http : //static.peterbe.com/a.jpg和http://static.peterbe.com/b.jpg

更新

我写了这个脚本:

import math, operator from PIL import Image def compare(file1, file2): image1 = Image.open(file1) image2 = Image.open(file2) h1 = image1.histogram() h2 = image2.histogram() rms = math.sqrt(reduce(operator.add, map(lambda a,b: (ab)**2, h1, h2))/len(h1)) return rms if __name__=='__main__': import sys file1, file2 = sys.argv[1:] print compare(file1, file2) 

然后,我下载了两个视觉相同的图像,并运行脚本。 输出:

 58.9830484122 

有谁能告诉我什么是合适的截止点?

更新II

a.jpg和b.jpg之间的区别是第二个已经保存了PIL:

 b=Image.open('a.jpg') b.save(open('b.jpg','wb')) 

这显然适用于一些非常非常轻质量的修改。 我现在已经解决了我的问题,通过应用相同的PIL保存到上传的文件,而不用做任何事情,它现在的作品!

有一个OSS项目使用WebDriver进行屏幕截图,然后比较图像以查看是否有任何问题( http://code.google.com/p/fighting-layout-bugs/); )。 它通过打开文件到一个stream然后比较每一个位来完成。

你也许可以做类似PIL的事情。

编辑:

经过更多的研究,我发现

 h1 = Image.open("image1").histogram() h2 = Image.open("image2").histogram() rms = math.sqrt(reduce(operator.add, map(lambda a,b: (ab)**2, h1, h2))/len(h1)) 

http://snipplr.com/view/757/compare-two-pil-images-in-python/和http://effbot.org/zone/pil-comparing-images.htm

从这里

判断两幅图像是否具有完全相同内容的最快捷方式是获得两幅图像之间的差异,然后计算该图像中非零区域的边界框。 如果图像相同,则差分图像中的所有像素都为零,并且边界框函数返回无。

 import ImageChops def equal(im1, im2): return ImageChops.difference(im1, im2).getbbox() is None 

我想你应该解码图像,并进行像素逐像素比较,看看他们是否合理相似。

用PIL和Numpy你可以很容易地做到这一点:

 import Image import numpy import sys def main(): img1 = Image.open(sys.argv[1]) img2 = Image.open(sys.argv[2]) if img1.size != img2.size or img1.getbands() != img2.getbands(): return -1 s = 0 for band_index, band in enumerate(img1.getbands()): m1 = numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size) m2 = numpy.array([p[band_index] for p in img2.getdata()]).reshape(*img2.size) s += numpy.sum(numpy.abs(m1-m2)) print s if __name__ == "__main__": sys.exit(main()) 

这将给你一个数值,如果图像是完全相同的,应该非常接近0。

请注意,移动/旋转的图像将被报告为非常不同,因为像素不会一一匹配。

使用ImageMagick,您可以简单地在您的shell中使用[或通过程序内的OS库调用]

 compare image1 image2 output 

这将创build一个标记差异的输出图像

 compare -metric AE -fuzz 5% image1 image2 output 

会给你5%的模糊系数来忽略小的像素差异。 更多的信息可以从这里采购

知道是什么使图像的某些特征比其他特征更重要的问题是整个科学计划。 我会build议一些替代品,取决于你想要的解决scheme:

  • 如果你的问题是看看你的JPEG中是否有翻转位,那么尝试对差异图像进行成像(本地可能是一个小的编辑?),

  • 要查看图像是否全球相同,请使用Kullback Leibler距离来比较您的直方图,

  • 看看你是否有一些合格的变化,在应用其他答案之前,使用下面的函数过滤你的图像来提高高级频率的重要性:

码:

 def FTfilter(image,FTfilter): from scipy.fftpack import fft2, fftshift, ifft2, ifftshift from scipy import real FTimage = fftshift(fft2(image)) * FTfilter return real(ifft2(ifftshift(FTimage))) #return real(ifft2(fft2(image)* FTfilter)) #### whitening def olshausen_whitening_filt(size, f_0 = .78, alpha = 4., N = 0.01): """ Returns the whitening filter used by (Olshausen, 98) f_0 = 200 / 512 /!\ you will have some problems at dewhitening without a low-pass """ from scipy import mgrid, absolute fx, fy = mgrid[-1:1:1j*size[0],-1:1:1j*size[1]] rho = numpy.sqrt(fx**2+fy**2) K_ols = (N**2 + rho**2)**.5 * low_pass(size, f_0 = f_0, alpha = alpha) K_ols /= numpy.max(K_ols) return K_ols def low_pass(size, f_0, alpha): """ Returns the low_pass filter used by (Olshausen, 98) parameters from Atick (p.240) f_0 = 22 c/deg in primates: the full image is approx 45 deg alpha makes the aspect change (1=diamond on the vert and hor, 2 = anisotropic) """ from scipy import mgrid, absolute fx, fy = mgrid[-1:1:1j*size[0],-1:1:1j*size[1]] rho = numpy.sqrt(fx**2+fy**2) low_pass = numpy.exp(-(rho/f_0)**alpha) return low_pass 

(从http://www.incm.cnrs-mrs.fr/LaurentPerrinet/Publications/Perrinet08spie无耻复制);

首先,我应该注意到它们完全相同。 b已经被重新压缩并失去了质量。 如果你仔细观察一个好的显示器,你可以看到这个。

为了确定它们在主观上是“相同的”,你将不得不像Fortran所build议的那样做一些事情,尽pipe你必须任意设定一个“相同性”的阈值。为了使图像大小独立,并且处理一些频道更明智的是,我会考虑在两个图像的像素之间的色彩空间中进行RMS(均方根)欧式距离。 我现在没有时间写代码,但基本上每个像素都要计算

 (R_2 - R_1) ** 2 + (G_2 - G_1) ** 2 + (B_2 - B_1) ** 2 

,join一个

(A_2 – A_1)** 2

如果图像具有alpha通道等,则结果是两个图像之间的色彩空间距离的平方。 find所有像素的平均值(平均值),然后取得得到的标量的平方根。 然后为这个值决定一个合理的阈值。

或者,您可能会决定使用不同有损压缩的相同原始图像的副本不是真正的“相同”,并坚持使用文件哈希。

我testing了这一个,它运作最好的所有方法和极快!

 def rmsdiff_1997(im1, im2): "Calculate the root-mean-square difference between two images" h = ImageChops.difference(im1, im2).histogram() # calculate rms return math.sqrt(reduce(operator.add, map(lambda h, i: h*(i**2), h, range(256)) ) / (float(im1.size[0]) * im1.size[1])) 

这里的链接供参考

您可以使用PIL (遍历图片的像素/片段并进行比较)比较它,也可以比较两个文件的MD5哈希值。