1

我正在尝试比较两个图像,看看它们是否相同。它们应该具有相同的尺寸,可能具有相同的大小,但内容有时会发生变化,我希望能够检测到它。

在我的情况下,我有两种方法:一种是获取每个图像中的颜色数量。(在我的情况下,如果图像不同,颜色的数量会改变)

或者确实使用图像处理器比较文件。我选择使用ruby-vips8它是因为众所周知它比 快得多RMagick,而且在我的情况下,性能很重要。

我做了一些刮擦,ruby-vips8但我找不到比较两个图像或获取颜色数量的方法(所以我可以使用这种方法进行比较)。

有什么帮助吗?

ruby-vips8是 libvips 的包装

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

更新:

随着用户Aetherus的回答,我才意识到我什ruby-vips8至不需要做这样的任务。我将文件作为字符串进行比较(正如他所建议的那样)。它对我来说效果很好,而且速度也很快。

我没有将他的回答标记为最佳,因为我的问题是询问是否可以使用ruby-vips8. 是特定于 lib 的场景,因此在这种情况下user894763答案更合适。

4

2 回答 2

8

必须有数百种测量图像相似度的方法,这是一个巨大的领域。他们(主要)在他们试图考虑的图像的哪些特征方面有所不同。

正如斯科特所说,一系列相似性度量基于直方图。这些技术不考虑您的像素在空间上的排列方式,因此如果您的两个图像已旋转 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}"

在我的桌面上,一对 2k x 3k JPEG 图像的运行时间约为 0.5 秒。

许多匹配器是基于空间分布的。一个简单的方法是将图像划分为一个 8x8 的网格(如棋盘),取每个正方形的平均像素值,然后根据正方形的平均值是高于还是低于整个图像的平均值。这为图像提供了类似指纹的东西,您可以将其整齐地存储在 64 位 int 中。它对噪音、比例变化或小旋转等事物不敏感。

为了测试两个图像的相似性,对它们的指纹进行异或运算并计算结果中设置的位数。同样,0 将是一个完美的匹配,更大的数字会不太好。

在 ruby​​-vips 中,您可以将其编码为:

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]

同样,对于 2k x 3k JPEG,这大约需要 0.5 秒。

另一个家庭将基于相关性,请参阅spcor和朋友。它们对于查找图像的小区域可能更有用。

许多更高级的图像相似度度量将采用各种算法,将它们全部运行,并使用一组加权因子来计算整体相似度度量。

于 2016-04-11T13:05:28.720 回答
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 可能看起来相同,但它们几乎从不具有相同的像素阵列。即使两张图片是相同类型的,它们可能看起来相同,但实际上第二张图片与第一张相比偏移了一个像素,或者两张图片之间的饱和度有点不同,或者......

我从来没有这样做过,我不确定它是否可行。

于 2016-04-10T01:06:12.637 回答