简单而快速的方法来比较图像的相似性

我需要一种简单而快速的方式来比较两张图片的相似度。 也就是说,如果它们包含完全相同的东西,但可能会有一些稍微不同的背景,并且可能会被几个像素移动/调整大小,我希望获得高价值。

(更具体一点,如果这很重要:一张图片是一个图标,另一张图片是截图的一个分区,我想知道这个分区究竟是不是图标。)

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

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

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

我想有很多其他可能的解决方案可以或多或少地工作(因为任务本身非常简单,因为我只是想检测相似性,如果它们非常相似)。 你会建议什么?


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

  • OpenCV / SURF如何从描述符中生成图像哈希/指纹/签名?
  • 图像指纹比较许多图像的相似性
  • 近乎重复的图像检测
  • OpenCV:指纹图像并与数据库进行比较。
  • 更多,更多,更多,更多,更多,更多
  • 另外,我偶然发现了这些具有获取指纹功能的实现:

  • pHash
  • imgSeek(GitHub回购)(GPL)基于论文Fast Multiresolution Image Querying
  • 图像匹配。 非常类似于我正在寻找的东西。 类似于pHash,基于任何类型图像的图像签名,Goldberg等人 使用Python和Elasticsearch。
  • iqdb
  • ImageHash。 支持pHash。
  • 关于感知图像哈希的一些讨论:这里


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

    一般来说,关于模糊搜索的更通用的问题在这里。 例如存在局部敏感散列和最近邻居搜索。


    屏幕截图或图标是否可以转换(缩放,旋转,偏斜...)? 有很多方法可以帮助你:

  • @carlosdc提到的简单欧几里得距离 (不适用于转换后的图像,并且您需要一个阈值)。
  • (标准化)交叉相关 - 一个简单的指标,您可以用它来比较图像区域。 它比简单的欧几里德距离更加稳健,但不适用于转换后的图像,并且您将再次需要阈值。
  • 直方图比较 - 如果使用标准化直方图,此方法运行良好,不受仿射变换的影响。 问题是确定正确的阈值。 它也对颜色变化(亮度,对比度等)非常敏感。 你可以把它和前两个结合起来。
  • 显着点/区域的探测器 - 例如MSER(最大稳定极值区域),SURF或SIFT。 这些算法非常强大,对于您的简单任务来说它们可能太复杂。 好的是,你不必拥有一个只有一个图标的确切区域,这些探测器足够强大,可以找到正确的匹配。 本文对这些方法进行了很好的评估:局部不变特征探测器:一项调查。
  • 其中大部分已经在OpenCV中实现 - 例如参见cvMatchTemplate方法(使用直方图匹配):http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html。 显着点/区域检测器也可用 - 请参阅OpenCV特征检测。


    我最近面临同样的问题,为了解决这个问题(简单而快速的算法来比较两张图片),我贡献了一个img_hash模块来opencv_contrib,你可以从这个链接中找到细节。

    img_hash模块提供了六个图像哈希算法,相当容易使用。

    代码示例

    起源lena 起源lena

    模糊莱娜 模糊莱娜

    调整lena的大小 调整lena的大小

    转移lena 转移lena

    #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)。


    屏幕截图是否只包含图标? 如果是这样,那么这两个图像的L2距离就足够了。 如果L2距离不起作用,下一步就是尝试一些简单而完善的方法,如:Lucas-Kanade。 我确信在OpenCV中可以找到它。

    链接地址: http://www.djcxy.com/p/64023.html

    上一篇: Simple and fast method to compare images for similarity

    下一篇: order on a group of records in a database?