2009-11-30 46 views
39

我試圖比較圖像,以找出彼此是否不同。首先,我試圖對RGB值進行Pearson校正,除非圖片位移小一點,否則這種方法的效果也不錯。所以如果一個圖像100%完全相同,但有一個被移動一點,我會得到一個不好的相關值。圖像比較算法

任何建議更好的算法?

順便說一句,我說的是比較imgages千...

編輯: 這裏是我的照片的例子(微觀):

IM1:

enter image description here

im2:

enter image description here

IM3:

enter image description here

IM 1和IM是相同的,但一點點移動/板缺,IM3,應當確認爲完全地不同...

編輯: 問題是用Peter Hansen的建議解決!工作得很好!感謝所有的答案!一些結果可以在這裏找到 http://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

+1

如果您對哪種類型的照片更具特色,以及它們可以以何種方式變化(比例,旋轉,照明......),那麼給出一個好的答案和解決方案會容易得多。 – 2009-11-30 11:49:50

+0

這裏有很多這樣的問題。 http://stackoverflow.com/questions/336067/detecting-if-two-images-are-visually-identical http://stackoverflow.com/questions/189943/how-can-i-quantify-difference-between-two -images http://stackoverflow.com/questions/336067/detecting-if-two-images-are-visually-identical這也是關於顯微鏡,也是:http://stackoverflow.com/questions/967436/checking-image-功能對齊 – endolith 2009-12-01 19:14:45

+0

除了這些優秀的答案 - 通常最好比較真實世界中的HSV空間圖像,而不是RGB。 – 2009-12-07 15:20:15

回答

35

A similar question在一年前被問到,並且有很多回復,其中包括一個關於像素化圖像的內容,我至少會提出一個資格預審步驟(因爲它會很快排除非相似的圖像) 。

還有一些還有更多參考和良好答案的更早的問題的鏈接。

下面是一個使用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) 

所以比較注意與自己給出了一個得分42105,IM2與IM1相比已經不遠了這一點,但相比IM3與任何其他的下一半的值給出清楚,IM1。您必須嘗試其他圖片才能瞭解其效果如何,以及如何改進效果。

運行時間很長......在我的機器上運行幾分鐘。我會嘗試一些預過濾,以避免浪費時間比較非常不相似的圖像,可能與迴應其他問題時提及的「比較jpg文件大小」技巧或像素化。事實上,你有不同大小的圖像使事情複雜化,但是你沒有提供足夠的關於屠宰的可能性的信息,所以很難給出具體的答案。

+0

感謝您的執行!我正在試運行。如果它是成功的,我可以先考慮過濾。比較大小聽起來不錯,我也可以嘗試調整大小... – snowflake 2009-12-01 08:54:33

+2

這看起來像這種方法很好!我的積極控制得到了明確的結果! 隨着圖片大小調整到50%,我獲得了很多速度。 非常感謝! – snowflake 2009-12-01 16:52:04

+0

不客氣。我也嘗試過使用FFT,考慮到你對圖像的描述(「相同」,但可能是移位和/或剪切),我認爲如果僅使用幅度結果,FFT可能會表現良好。這次我將圖像剪裁到最小公共尺寸,對每個圖像執行scipy.fftpack.fft2和abs()以獲得f1,f2,f3,並且使用(f1-x)**對基線圖像進行了歸一化比較2/f1/x其中x是f1,f2,f3等,結果分別爲0,143,211。對於im1的亮度調整和版本化,我得到了146和1189個結果。運行時間只有1.2s ... – 2009-12-01 17:34:55

6

如果你的問題是關於移位像素,也許你應該比較頻率變換。

的FFT應該OK(numpy has an implementation for 2D matrices),但我總是聽到小波是這類任務的更好的^ _^

關於性能,如果所有的圖像的大小相同,如果我記得很清楚,FFTW軟件包爲每個FFT輸入大小創建了一個專門的函數,所以你可以獲得一個很好的性能提升,重用相同的代碼......我不知道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並再次進行比較,如果差值低於上一步驟,則可以沿梯度方向重複移動,然後減去直到差值低於某個閾值或再次增加。如果模糊內核的半徑大於圖像的移位,那麼這應該起作用。

此外,您可以嘗試使用攝影工作流程中常用的一些工具來混合多個展覽或進行全景拍攝,如Pano Tools

+0

這種方法的問題是(自然)照片通常具有非常相似的頻率內容。所以單單一個FFT很可能不會很好地工作。我會假設對於很多其他主題領域來說也是如此。 – 2009-11-30 11:42:12

+1

@kigurai我對圖像進行了一些與自然內容相同的測試(兩種不同的核爆炸,他們很容易找到,在谷歌圖片中搜索「測試」)和另一張倫敦眼圖片,他們得分41583454和45014233在我的快速和骯髒的FFT測試中...其中一個爆炸向右移動了3個像素(填充白色)得分僅爲8749886(減少了4倍),而15像素移位仍然爲17325409(減少了2倍)。當然,圖像的分數爲0.所以,儘管您有異議,但平凡的FFT似乎是一種很好的比較方式。 – fortran 2009-11-30 13:25:02

+0

我在三個例子上試過你的代碼,它看起來相當有前途!我現在開始跑得太快了! 非常感謝! – snowflake 2009-11-30 16:17:58

0

我想你可以做這樣的事情:

  • 估計垂直/水平的參考圖像VS的比較圖像位移。一個簡單的SAD(絕對差之和)與運動矢量將做到。

  • 轉變比較像據此

  • 計算Pearson相關你試圖做

移測量並不困難。

  • 在比較圖像中取一個區域(比如約32x32)。
  • 將它沿水平方向移動x個像素,並在垂直方向移動y個像素。
  • 計算SAD(絕對差之和)w.r.t.原始圖像
  • 在小範圍內做此,x和y的幾個值(-10,+ 10)
  • 找到地方,差最小
  • 挑選一個值作爲移位運動矢量

注:

如果SAD來了非常高的X和Y,那麼你反正可以認爲圖像是非常不同的,並移測量的所有值是沒有必要的。

+0

圍繞着更復雜的運動估計(「Shift測量」)算法。如果您檢查的區域選擇不當,您的方法將失敗(本質上不是2D)。 – 2009-11-30 11:38:38

+0

供參考:「標準」運動估計算法之一是Lucas-Kanade跟蹤器。 – 2009-11-30 11:40:05

13

我有一個這樣做的圖像直方圖比較。我的基本算法是這樣的:

  1. 雙像成紅,綠,藍
  2. 創建紅色,綠色和藍色通道標準化的直方圖,並將它們連接成一個矢量​​其中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,他們更發散,距離越遠。

它對我的照片效果不錯,但在文字和徽標等圖形上失敗。

+3

只是爲了強調:即使兩個直方圖相等,它並不一定意味着生成它們的兩幅圖像在結構上相似。它們恰好具有相同的顏色分佈。舉一個例子,美國和英國的國旗可能會生成類似的直方圖。 – 2009-11-30 11:52:47

1

首先,相關性對於相似性而言是一個非常CPU密集而不準確的測量。如果單個像素之間存在差異,爲什麼不去求平方和?

一個簡單的解決方案,如果最大偏移是有限的:生成所有可能的移位圖像並找到最匹配的一個。確保僅在所有移位圖像中可匹配的像素子集上計算匹配變量(即相關性)。另外,你的最大移動幅度應該比圖像的大小要小得多。

如果你想使用一些更先進的圖像處理技術,我建議你看看SIFT這是一個非常強大的方法,(理論上來說)可以正確地匹配與平移,旋轉和縮放無關的圖像中的項目。

2

我早已做了一些圖像處理的過程,並記住,匹配時,我通常開始製作圖像灰度,然後銳化圖像的邊緣,以便只看到邊緣。你(軟件)可以移動和減去圖像,直到差異最小。

如果差異大於您設置的閾值,則圖像不相同,您可以繼續下一步。然後可以分析具有較小閾值的圖像。

我的確認爲充其量你可以從根本上消除可能的匹配,但需要親自比較可能的匹配以確定它們是否相等。

我真的不能顯示代碼,因爲它很久以前,我用Khoros /康塔塔的課程。

6

你確實需要更好地指出問題,但是看着這5張圖片,這些有機體似乎都以相同的方式定向。如果情況總是如此,您可以嘗試在兩幅圖像之間做一個normalized cross-correlation,並將峯值作爲相似度。我不知道在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) 

,因爲圖像作爲書面這將無法正常工作是不同的大小,並且輸出沒有加權或歸一化。

輸出的峯值位置表示兩幅圖像之間的偏移量,峯值的大小表示相似性。應該有一種方法來對它進行加權/歸一化,這樣你就可以分辨好匹配和差匹配之間的區別。

這不是我想要的答案,因爲我還沒有想出如何規範化它,但是如果我找出它,我會更新它,它會給你一個想法調查。

0

爲了讓進口在我的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 scipy as sp 
from scipy.ndimage import imread 
from scipy.signal.signaltools import correlate2d as c2d 

8年後,Snowflake的腳本爲我工作的真棒!