简单快速地比较图像的相似性
computer-vision
image-processing
opencv
6
0

我需要一种简单快速的方法来比较两个图像的相似性。即,如果它们包含完全相同的内容,但背景可能略有不同,并且可能会移动/调整几个像素,则我希望获得较高的值。

(更具体的说,这很重要:一张图片是图标,另一张图片是屏幕截图的子区域,我想知道该子区域是否完全是图标。)

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

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

我还没有尝试过它如何运作,但是我想它已经足够了。这些图像已经非常相似(在我的用例中),因此我可以使用相当高的阈值。

我猜想有很多其他可行的解决方案或多或少会起作用(因为任务本身非常简单,我只想在相似性非常高的情况下才检测相似性)。你有什么建议?


关于从图像中获取签名/指纹/哈希,存在一些非常相关/相似的问题:

此外,我偶然发现了这些实现具有指纹功能的实现:

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


有点题外话:存在许多创建音频指纹的方法。 MusicBrainz是一项提供对歌曲进行基于指纹的查找的Web服务, 其Wiki中很好的概述 。他们现在正在使用AcoustID 。这是用于查找完全匹配(或几乎完全匹配)的匹配项。要查找类似的匹配项(或者如果您仅有一些片段或高噪音),请查看Echoprint 。一个相关的SO问题在这里 。因此,似乎音频已解决。所有这些解决方案都运行良好。

关于模糊搜索的一般问题在这里出现 。例如,存在局部敏感的哈希最近邻居搜索

参考资料:
Stack Overflow
收藏
评论
共 7 个回答
高赞 时间 活跃

如果可以确保模板(图标)与测试区域精确对齐,则任何旧的像素差异总和都可以使用。

如果对齐仅需要一点点时间,则可以在找到像素差之和之前,使用cv :: GaussianBlur对两个图像进行低通。

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

收藏
评论

屏幕截图是否仅包含图标?如果这样,两个图像的L2距离可能就足够了。如果L2距离不起作用,则下一步是尝试一些简单而完善的方法,例如: Lucas-Kanade 。我确定OpenCV中可用。

收藏
评论

如果要匹配相同的图像-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
}

快速。但不稳健的照明/视点变化等来源

收藏
评论

我最近也面临着同样的问题,要一劳永逸地解决这个问题(简单快速的算法来比较两个图像),我将img_hash模块贡献给opencv_contrib,您可以从此链接中找到详细信息。

img_hash模块提供了六种图像哈希算法,非常易于使用。

代码示例

起源莱娜起源莱娜

模糊莱娜模糊莱娜

调整莉娜调整莉娜

莱娜班莱娜班

#include <opencv2/core.hpp>
#include <opencv2/core/ocl.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/img_hash.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

void compute(cv::Ptr<cv::img_hash::ImgHashBase> algo)
{
    auto input = cv::imread("lena.png");
    cv::Mat similar_img;

    //detect similiar image after blur attack
    cv::GaussianBlur(input, similar_img, {7,7}, 2, 2);
    cv::imwrite("lena_blur.png", similar_img);
    cv::Mat hash_input, hash_similar;
    algo->compute(input, hash_input);
    algo->compute(similar_img, hash_similar);
    std::cout<<"gaussian blur attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after shift attack
    similar_img.setTo(0);
    input(cv::Rect(0,10, input.cols,input.rows-10)).
            copyTo(similar_img(cv::Rect(0,0,input.cols,input.rows-10)));
    cv::imwrite("lena_shift.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"shift attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after resize
    cv::resize(input, similar_img, {120, 40});
    cv::imwrite("lena_resize.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"resize attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;
}

int main()
{
    using namespace cv::img_hash;

    //disable opencl acceleration may(or may not) boost up speed of img_hash
    cv::ocl::setUseOpenCL(false);

    //if the value after compare <= 8, that means the images
    //very similar to each other
    compute(ColorMomentHash::create());

    //there are other algorithms you can try out
    //every algorithms have their pros and cons
    compute(AverageHash::create());
    compute(PHash::create());
    compute(MarrHildrethHash::create());
    compute(RadialVarianceHash::create());
    //BlockMeanHash support mode 0 and mode 1, they associate to
    //mode 1 and mode 2 of PHash library
    compute(BlockMeanHash::create(0));
    compute(BlockMeanHash::create(1));
}

在这种情况下,ColorMomentHash给我们最好的结果

  • 高斯模糊攻击:0.567521
  • 转移攻击:0.229728
  • 调整攻击强度:0.229358

每种算法的优缺点

不同攻击下的性能

img_hash的性能也不错

与PHash库进行速度比较(来自ukbench的100张图像) 计算性能 比较表现

如果您想了解这些算法的建议阈值,请查看此帖子( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html )。如果您对如何测量img_hash模块的性能(包括速度和其他攻击)感兴趣,请检查此链接( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html )。

收藏
评论

屏幕截图或图标可以变形(缩放,旋转,倾斜...)吗?我头顶上有很多方法可以帮助您:

  • @carlosdc提到的简单欧氏距离 (不适用于转换后的图像,您需要一个阈值)。
  • (归一化)互相关 -一个简单的指标,可用于比较图像区域。它比简单的欧式距离更健壮,但不适用于转换后的图像,因此您将再次需要一个阈值。
  • 直方图比较 -如果使用归一化的直方图,此方法效果很好,并且不受仿射变换的影响。问题是确定正确的阈值。它还对颜色变化(亮度,对比度等)非常敏感。您可以将其与前两个结合使用。
  • 显着点/区域的检测器 -例如MSER(最大稳定末端区域)SURFSIFT 。这些算法非常健壮,对于您的简单任务而言可能过于复杂。好消息是,您不必具有仅一个图标的确切区域,这些检测器功能强大,可以找到正确的匹配项。本文对这些方法进行了很好的评估: 局部不变特征检测器:一项调查

其中大多数已在OpenCV中实现-例如,参见cvMatchTemplate方法(使用直方图匹配): http ://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html。突出点/区域检测器也可用-请参阅OpenCV特征检测

收藏
评论

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

它也在OpenCV中实现,并且可以通过GPU进行加速:具有GPU的OpenCV SSIM

收藏
评论

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

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号