2016-04-10 90 views
0

我試圖比較兩個圖像,看看它們是否相同。它們應該具有相同的尺寸,可以具有相同的尺寸,但內容有時會發生變化,我希望能夠檢測到它。是否有可能使用ruby-vips8檢測兩個圖像是否相同?

我有兩種方法來做我的情況:一是獲取每個圖像的顏色數量。 (在我的情況下,如果圖像不同,顏色的數量會發生變化)

或者確實使用圖像處理器比較文件。 我選擇使用ruby-vips8,因爲它比RMagick快很多,在我的情況下,性能是一件事情。

我對ruby-vips8做了一些修改,但我無法找到比較兩幅圖像或獲取顏色數量的方法(所以我可以使用此方法進行比較)。

任何幫助?

ruby-vips8libvips的包裝。

http://www.rubydoc.info/gems/ruby-vips8/0.1.0/Vips/ http://www.vips.ecs.soton.ac.uk/index.php?title=VIPS

UPDATE:

隨着用戶的答案Aetherus我才意識到我甚至都不需要ruby-vips8做這樣的工作。我比較文件作爲字符串(如他建議)。它對我很好,而且速度也非常快。

我沒有標記他的答案是最好的,因爲我的問題是否可以使用ruby-vips8這樣做。是一個lib特定的情況,所以在這種情況下,user894763答案更加適當。

+0

它看起來像vips支持直方圖,並比較直方圖是比較圖像的一種方法https://stackoverflow.com/questions/6499491/comparing-two-histograms。 OpenCV可以提供更復雜的方式來比較圖像https://stackoverflow.com/questions/11541154/checking-images-for-similarity-with-opencv –

回答

4

必須有數百種測量圖像相似性的方式,這是一個巨大的領域。它們(主要)在他們試圖考慮的圖像的特徵中有所不同。正如斯科特所說,一組相似性度量是基於直方圖的。這些技術沒有考慮像素在空間上的排列方式,因此如果旋轉了45度,那麼您的兩幅圖像可能會被視爲相同。它們也很快,因爲找到直方圖很快。

一個簡單的直方圖匹配器可能是:找到兩個輸入圖像的直方圖,歸一化(所以兩個主題有相同的區域...這消除了圖像大小的差異),減去,平方和和。現在少數意味着一個好的搭配,數字越大意味着越差的搭配。

ruby-vips這將是:

require 'vips' 

a = Vips::Image.new_from_file ARGV[0], access: :sequential 
b = Vips::Image.new_from_file ARGV[1], access: :sequential 

# find hists, normalise, difference, square 
diff_hist = (a.hist_find.hist_norm - b.hist_find.hist_norm) ** 2 

# find sum of squares ... find the average, then multiply by the size of the 
# histogram 
similarity = diff_hist.avg * diff_hist.width * diff_hist.height 

puts "similarity = #{similarity}" 

在我的桌面上,這個運行在大約0.5秒的一對一個2K x 3K JPEG圖像。

許多匹配器都基於空間分佈。一個簡單的方法是將圖像分成8x8的網格(如棋盤),取每個平方的平均像素值,然後根據平方的平均值是高於還是低於平均值將該平方設置爲0或1整個圖像的平均值。這樣可以爲圖像提供類似指紋的圖像,您可以將它們整齊地存儲在64位整數中。它對噪音,尺度變化或小旋轉等不敏感。

要測試兩張圖像的相似度,請對它們的指紋進行XOR並對結果中設置的位數進行計數。再次,0將是完美的匹配,更大的數字會不太好。

在紅寶石貴賓,你可以爲這個代碼:

require 'vips' 

a = Vips::Image.new_from_file ARGV[0], access: :sequential 

# we need a mono image 
a = a.colourspace "b-w" 

# reduce to 8x8 with a box filter 
a = a.shrink(a.width/8, a.height/8) 

# set pixels to 0 for less than average, 255 for greater than average 
a = a > a.avg 

a.write_to_file ARGV[1] 

這再次運行在大約0.5秒爲一個2K x 3K JPEG。

另一個家庭將基於相關性,請參閱spcor和朋友。它們可能對找到圖像的一個小區域更有用。

許多更漂亮的圖像相似性度量將採用各種算法,將它們全部運行,並使用一組權重因子來計算整體相似性度量。

+0

非常好的解釋,謝謝。我會更新關於我的問題的帖子。但是你肯定有最好的(和正確的)答案。 – fschuindt

0

「是一樣的」還是「看起來一樣」是兩回事。

如果您想驗證2張圖片是否「相同」,那麼只需將它們讀入2個字符串並進行比較即可。

def same_image?(path1, path2) 
    return true if path1 == path2 
    image1 = File.read(path1, 'rb') 
    image2 = File.read(path2, 'rb') 
    image1 == image2 
end 

或者如果你的圖像很大,那麼只需逐字節讀取它們並進行比較。

def same_image?(path1, path2) 
    return true if path1 == path2 
    File.open(path1, 'rb') do |image1| 
    File.open(path2, 'rb') do |image2| 
     return false if image1.size != image2.size 
     while (b1 = image1.read(1024)) and (b2 = image2.read(1024)) 
     return false if b1 != b2 
     end 
    end 
    end 
    true 
end 

驗證2張圖像「看起來是否相同」是非常困難的工作。例如,PNG和JPG可能看起來完全相同,但它們幾乎不會有相同的像素陣列。即使是2張圖片也是同一類型的,它們可能看起來相同,但實際上第二張圖片與第一張圖片相比是一個像素的偏移量,或者兩張圖片之間的飽和度有點不同,或者...

我從來沒有這樣做過,我不確定它是否可行。

+0

謝謝,我實際上使用你的方法比較文件作爲字符串。事實證明,這對我來說效果更好。我會更新我的文章,解釋爲什麼我沒有使用你的文章作爲最佳答案。再次感謝你。 – fschuindt

相關問題