图像比较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是这样的:
- 将图像分成红色,绿色和蓝色
- 为红色,绿色和蓝色通道创build归一化的直方图,并将它们连接成一个向量
(r0...rn, g0...gn, b0...bn)
,其中n是“桶”的数量,256应该足够 - 从另一个图像的直方图中减去此直方图并计算距离
这里是一些代码与numpy
和pil
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年后,雪花的脚本为我工作了多么棒!