【问题标题】:Is possible to detect if two images are the same using ruby-vips8?是否可以使用 ruby​​-vips8 检测两个图像是否相同?
【发布时间】:2016-07-31 04:04:18
【问题描述】:

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

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

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

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

有什么帮助吗?

ruby-vips8libvips 的包装器。

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 答案更合适。

【问题讨论】:

标签: ruby image-processing vips


【解决方案1】:

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

正如 Scott 所说,一系列相似性度量基于直方图。这些技术不考虑您的像素在空间上的排列方式,因此如果您的两个图像已旋转 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 和朋友。它们对于查找图像的小区域可能更有用。

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

【讨论】:

  • 很好的解释,谢谢。我会更新关于我的问题的帖子。但你肯定有最好(和正确)的答案。
【解决方案2】:

“一样”和“看起来一样”是两个不同的东西。

如果您想验证 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 可能看起来相同,但它们几乎从不具有相同的像素阵列。即使两张图片属于同一类型,它们可能看起来相同,但实际上第二张图片与第一张相比偏移了一个像素,或者两张图片之间的饱和度略有不同,或者......

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

【讨论】:

  • 谢谢,我实际上是在使用您将文件作为字符串进行比较的方法。事实证明这对我来说效果更好。我将更新我的帖子,解释为什么我没有使用您的帖子作为最佳答案。再次感谢您。
猜你喜欢
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 2014-03-22
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 2015-08-24
相关资源
最近更新 更多