2016-04-10 52 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

相关问题