图像比较algorithm

我试图比较图像彼此,以确定它们是否不同。 首先,我试图对RGB值进行Pearson校正,除非图片被移位,否则这种方法的效果也不错。 所以如果有一个100%完全相同的图像,但有一点是移动,我得到一个不好的相关值。

任何build议更好的algorithm?

顺便说一下,我正在谈论比较数千imgages …

编辑:这是我的照片(微观)的一个例子:

IM1:

在这里输入图像说明

IM2:

在这里输入图像说明

IM3:

在这里输入图像说明

im1和im2是相同的,但有点移动/切割,im3应该被认为是完全不同的…

编辑: 问题是与彼得·汉森的build议解决! 工作得很好! 感谢所有的答案! 一些结果可以在这里findhttp://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

一年前,一个类似的问题被问到,并且有很多回应,其中包括一个关于图像像素化的问题,至less是资格预审阶段(因为它会很快排除非相似的图像)。

还有一些关于更早的问题,甚至更多的参考和良好的答案。

这是一个使用Scipy的一些想法的实现,使用上面的三个图像(分别保存为im1.jpg,im2.jpg,im3.jpg)。 最终的输出结果显示了im1与自身的比较,作为基线,然后将每个图像与其他图像进行比较。

>>> import scipy as sp >>> from scipy.misc import imread >>> from scipy.signal.signaltools import correlate2d as c2d >>> >>> def get(i): ... # get JPG image as Scipy array, RGB (3 layer) ... data = imread('im%s.jpg' % i) ... # convert to grey-scale using W3C luminance calc ... data = sp.inner(data, [299, 587, 114]) / 1000.0 ... # normalize per http://en.wikipedia.org/wiki/Cross-correlation ... return (data - data.mean()) / data.std() ... >>> im1 = get(1) >>> im2 = get(2) >>> im3 = get(3) >>> im1.shape (105, 401) >>> im2.shape (109, 373) >>> im3.shape (121, 457) >>> c11 = c2d(im1, im1, mode='same') # baseline >>> c12 = c2d(im1, im2, mode='same') >>> c13 = c2d(im1, im3, mode='same') >>> c23 = c2d(im2, im3, mode='same') >>> c11.max(), c12.max(), c13.max(), c23.max() (42105.00000000259, 39898.103896795357, 16482.883608327804, 15873.465425120798) 

所以注意到im1相比自己给出的分数是42105,im2与im1相比并不遥远,但是im3与其他任何一个相比都给出了一半以下的值。 你必须尝试其他图像,看看这可能会执行得如何,以及如何改善它。

运行时间很长…在我的机器上几分钟。 我会尝试一些预过滤,以避免浪费时间比较非常不相似的图像,也许与对另一个问题的回应中提到的“比较jpg文件大小”技巧,或与像素化。 事实上,你有不同大小的图像使事情复杂化,但是你没有提供足够的关于屠宰程度的信息,所以很难给出具体的答案。

我有一个这样做的图像直方图比较。 我的基本algorithm是这样的:

  1. 将图像分成红色,绿色和蓝色
  2. 为红色,绿色和蓝色通道创build归一化的直方图,并将它们连接成一个向量(r0...rn, g0...gn, b0...bn) ,其中n是“桶”的数量,256应该足够
  3. 从另一个图像的直方图中减去此直方图并计算距离

这里是一些代码与numpypil

 r = numpy.asarray(im.convert( "RGB", (1,0,0,0, 1,0,0,0, 1,0,0,0) )) g = numpy.asarray(im.convert( "RGB", (0,1,0,0, 0,1,0,0, 0,1,0,0) )) b = numpy.asarray(im.convert( "RGB", (0,0,1,0, 0,0,1,0, 0,0,1,0) )) hr, h_bins = numpy.histogram(r, bins=256, new=True, normed=True) hg, h_bins = numpy.histogram(g, bins=256, new=True, normed=True) hb, h_bins = numpy.histogram(b, bins=256, new=True, normed=True) hist = numpy.array([hr, hg, hb]).ravel() 

如果你有两个直方图,你可以得到像这样的距离:

 diff = hist1 - hist2 distance = numpy.sqrt(numpy.dot(diff, diff)) 

如果两幅图像相同,距离为0,则它​​们越分散,距离越大。

它为我的照片工作得很好,但失败的graphics像文本和标志。

你真的需要更好地指出这个问题,但是从这5张图片看来,这些生物似乎都是以同样的方式定向的。 如果情况总是如此,您可以尝试在两幅图像之间进行归一化的互相关 ,并将峰值作为相似度。 我不知道Python中的规范化的互相关函数,但是有一个类似的fftconvolve()函数,你可以自己做循环互相关:

 a = asarray(Image.open('c603225337.jpg').convert('L')) b = asarray(Image.open('9b78f22f42.jpg').convert('L')) f1 = rfftn(a) f2 = rfftn(b) g = f1 * f2 c = irfftn(g) 

由于图像尺寸不同,这将不能像写入一样工作,并且输出不是加权或归一化的。

输出的峰值位置表示两幅图像之间的偏移量,峰值的大小表示相似度。 应该有一种方法来对它进行加权/归一化,这样你就可以分辨好匹配和差匹配。

这不是我想要的答案,因为我还没有想出如何规范化它,但是如果我弄明白,我会更新它,这会给你一个想法。

如果你的问题是关于移位像素,也许你应该比较频率变换。

FFT应该是OK的( numpy有2Dmatrix的实现 ),但是我总是听说小波对于这种types的任务更好。^ _ ^

关于性能,如果所有的图像都是相同的大小,如果我记得不错,FFTW软件包为每个FFTinput大小创build了一个专门的函数,所以你可以得到一个很好的性能提升重用相同的代码…我不'不知道numpy是否基于FFTW,但是如果不是这样的话,也许你可以试着在那里调查一下。

在这里,你有一个原型…你可以玩一点,看看哪个阈值适合你的图像。

 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.fft.fft2(numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size)) m2 = numpy.fft.fft2(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()) 

另一种进行的方法可能是模糊图像,然后从两幅图像中减去像素值。 如果差值不为零,则可以将每个方向上的一个图像移位1 px并再次进行比较,如果差值低于上一步骤,则可以沿梯度方向重复移动,然后减去差值低于一定的阈值或再次增加。 如果模糊内核的半径大于图像的移动,那么这应该起作用。

此外,您可以尝试使用摄影工作stream程中常用的一些工具来混合多个展览或进行全景拍摄,如Pano Tools 。

很久以前,我已经做了一些image processing的过程,记住当匹配的时候,我通常从图像的灰度开始,然后锐化图像的边缘,这样你只能看到边缘。 你(软件)可以移动和减去图像,直到差异最小。

如果这个差异大于你所设定的阈值,图像就不相同,你可以继续下一步。 然后可以分析具有较小阈值的图像。

我认为最好的情况是,你可以从根本上消除可能的比赛,但是需要亲自比较可能的比赛以确定它们是否相等。

我不能很好地展示代码,因为我很久以前就使用了Khoros / Cantata。

首先,相关性是相当CPU密集度而不准确的度量。 为什么不只是去个别像素之间的差异的平方和?

一个简单的解决scheme,如果最大的转变是有限的:生成所有可能的移动图像,并find最匹配的一个。 确保只在所有移位图像中可以匹配的像素子集上计算匹配variables(即相关性)。 另外,你的最大移动幅度应该比图像的大小要小得多。

如果你想使用一些更高级的image processing技术,我build议你看看SIFT这是一个非常强大的方法,(理论上来说)可以正确匹配图像中的项目,独立于平移,旋转和缩放。

我想你可以做这样的事情:

  • 估计参考图像与比较图像的垂直/水平位移。 一个简单的SAD(绝对差之和)与运动vector将做到。

  • 相应地移动比较图像

  • 计算您正在尝试执行的皮尔森相关性

换档测量并不困难。

  • 以比较的形象拍摄一个地区(比如约32×32)。
  • 在水平方向上移动x像素,在垂直方向移动y像素。
  • 计算原始图像的SAD(绝对差的总和)
  • 在小范围(-10,+10)
  • 找出差距最小的地方
  • select该值作为移动运动vector

注意:

如果SAD对于x和y的所有值都非常高,则无论如何都可以假设图像是非常不相似的,并且不需要移位测量。

为了让我的Ubuntu 16.04上的导入工作正常(截至2017年4月),我安装了python 2.7,它们是:

 sudo apt-get install python-dev sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk sudo apt-get install python-scipy sudo pip install pillow 

然后我改变了雪花的import到这些:

 import scipy as sp from scipy.ndimage import imread from scipy.signal.signaltools import correlate2d as c2d 

8年后,雪花的脚本为我工作了多么棒!