我需要一个简单而快速的方法来比较两个图像的相似性。也就是说,如果它们包含完全相同的内容,但可能有一些略微不同的背景,并且可能被移动/调整了几个像素,我想要得到一个高值。

(更具体地说,如果这很重要的话:一张图片是一个图标,另一张图片是截图的一个子区域,我想知道这个子区域是否就是图标。)

我手头有OpenCV,但我仍然不太习惯它。

到目前为止,我想到的一种可能是:将两张图片分成10x10的单元格,对于这100个单元格中的每一个,比较颜色直方图。然后我可以设置一些虚构的阈值,如果我得到的值高于该阈值,我就假设它们是相似的。

我还没有试过它的效果如何,但我想它应该足够好了。图像已经非常相似(在我的用例中),所以我可以使用一个相当高的阈值。

我猜还有其他几十种可能的解决方案,它们或多或少会起作用(因为任务本身很简单,因为我只想检测相似性,如果它们真的非常相似)。你有什么建议吗?


关于从图像中获取签名/指纹/散列,有几个非常相关/相似的问题:

如何生成图像哈希/指纹/签名的描述符? 图像指纹可以比较多个图像的相似度 近重复图像检测 OpenCV:指纹图像和比对数据库。 更多,更多,更多,更多,更多,更多

此外,我偶然发现了这些实现,它们有这样的功能来获取指纹:

pHash 基于imgSeek (GitHub repo) (GPL)的快速多分辨率图像查询 图像匹配。跟我一直在找的东西很像。类似于pHash,基于任何类型图像的图像签名,Goldberg等人。使用Python和Elasticsearch。 iqdb ImageHash。支持pHash。 Image重复数据删除器(imagededup)。支持CNN, PHash, DHash, WHash, AHash。

关于知觉图像哈希的一些讨论:这里


有点跑题:有很多方法可以创建音频指纹。MusicBrainz,一个提供基于指纹的歌曲查找的网络服务,在他们的维基中有一个很好的概述。他们现在正在使用AcoustID。这是为了找到精确的(或大部分精确的)匹配。为了找到相似的匹配(或者如果你只有一些片段或高噪音),看看echopprint。这里有一个相关的SO问题。音频问题似乎解决了。所有这些解决方案都很有效。

这里有一个关于模糊搜索的更一般的问题。例如,有位置敏感哈希和最近邻居搜索。


当前回答

如果您想获得关于两张图片相似性的索引,我建议您从SSIM索引的指标中获得。它更符合人眼。这里有一篇关于它的文章:结构相似指数

它也在OpenCV中实现,并且可以使用GPU进行加速:OpenCV SSIM with GPU

其他回答

在双重库中使用哈希函数来检测(接近)相同的图像(免责声明:我也是作者)。这是一种简单而快速的方法来比较两个或多个图像的相似性。它使用预处理图像(灰度化、归一化和缩放)、计算图像哈希以及基于阈值对图像进行分组的多步过程来工作。

胡不变矩是比较两幅图像非常有力的工具

如果用于匹配相同的图像-代码L2距离

// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity( const Mat A, const Mat B ) {
if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) {
    // Calculate the L2 relative error between images.
    double errorL2 = norm( A, B, CV_L2 );
    // Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
    double similarity = errorL2 / (double)( A.rows * A.cols );
    return similarity;
}
else {
    //Images have a different size
    return 100000000.0;  // Return a bad value
}

快。但对光线/视点等的变化不稳定。 源

如果你想比较图像的相似性,我建议你使用OpenCV。在OpenCV中,特征匹配和模板匹配很少。在特征匹配方面,有SURF、SIFT、FAST等检测仪。你可以用它来检测、描述和匹配图像。之后,您可以使用特定的索引来查找两个图像之间的匹配数。

如果可以确保模板(图标)与测试区域的精确对齐,那么任何旧的像素差之和都可以工作。

如果对齐只会有一点点偏差,那么你可以在找到像素差的和之前,用cv::GaussianBlur低通两个图像。

如果对齐的质量可能很差,那么我会建议使用定向梯度直方图或OpenCV方便的关键点检测/描述符算法(如SIFT或SURF)。