必须有数百种测量图像相似度的方法,这是一个巨大的领域。他们(主要)在他们试图考虑的图像的哪些特征方面有所不同。
正如斯科特所说,一系列相似性度量基于直方图。这些技术不考虑您的像素在空间上的排列方式,因此如果您的两个图像已旋转 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和朋友。它们对于查找图像的小区域可能更有用。
许多更高级的图像相似度度量将采用各种算法,将它们全部运行,并使用一组加权因子来计算整体相似度度量。