Image processing 一种简单快速的图像相似性比较方法

Image processing 一种简单快速的图像相似性比较方法,image-processing,opencv,computer-vision,Image Processing,Opencv,Computer Vision,我需要一个简单而快速的方法来比较两个图像的相似性。也就是说,如果它们包含完全相同的内容,但可能有一些稍微不同的背景,并且可能会移动/调整几个像素,我希望得到一个高值 (更具体地说,如果这很重要的话:一张图片是图标,另一张图片是屏幕截图的子区域,我想知道这个子区域是否就是图标。) 我手边有OpenCV,但我还不习惯 到目前为止,我考虑过一种可能性:将两张图片分成10x10个单元格,然后分别比较这100个单元格的颜色直方图。然后我可以设置一些虚构的阈值,如果我得到的值高于该阈值,我假设它们是相似的

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

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

我手边有OpenCV,但我还不习惯

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

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

我猜有几十种其他可能的解决方案,或多或少都会奏效(因为任务本身非常简单,因为我只想在它们非常相似的情况下检测相似性)。你有什么建议


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

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

  • ()(GPL)基于论文
  • 。和我要找的很相似。类似于pHash,基于。使用Python和Elasticsearch
  • 。支持pHash
  • 。支持CNN,PHash,DHash,WHash,AHash
关于感知图像散列的一些讨论:


有点离题:有很多方法可以创建音频指纹,提供基于指纹的歌曲查找的web服务具有。他们现在正在使用。这是为了找到精确(或大部分精确)的匹配。要查找类似的匹配项(或者如果只有一些片段或高噪声),请查看。一个相关的问题是。所以这似乎是解决了音频问题。所有这些解决方案都很有效


关于模糊搜索的一个更一般的问题是。例如,有和。

屏幕截图是否只包含图标?如果是这样,两幅图像的L2距离可能就足够了。如果L2距离不起作用,下一步是尝试一些简单且完善的方法,如:。我确信OpenCV中提供了这一功能。

屏幕截图或图标是否可以转换(缩放、旋转、倾斜…)?我脑子里有很多方法可以帮助你:

  • 简单欧几里德距离如@carlosdc所述(不适用于变换图像,您需要一个阈值)
  • -一个可用于图像区域比较的简单指标。它比简单的欧几里德距离更稳健,但对变换后的图像不起作用,您将再次需要一个阈值
  • 直方图比较-如果使用标准化直方图,此方法效果良好,不受仿射变换的影响。问题在于确定正确的阈值。它对颜色变化(亮度、对比度等)也非常敏感。您可以将其与前两个合并
  • 显著点/区域的探测器-例如,或。这些是非常健壮的算法,对于您的简单任务来说,它们可能过于复杂。好的是,你不必有一个只有一个图标的精确区域,这些探测器足够强大,可以找到正确的匹配。本文对这些方法进行了很好的评价

其中大部分已经在OpenCV中实现了——例如,请参见cvMatchTemplate方法(使用直方图匹配):。突出点/区域检测器也可用-请参阅。

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

如果对齐只差一点点,那么可以在找到像素差之和之前对两幅图像进行低通处理


如果对齐质量可能很差,那么我建议使用OpenCV的一种或一种方便的关键点检测/描述符算法(例如或)。

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

如果您想获得关于两幅图像相似性的索引,我建议您使用SSIM索引。它更符合人眼。以下是一篇关于它的文章:


它也在OpenCV中实现,并且可以使用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\u contrib贡献了一篇文章,您可以从中找到详细信息

img_散列模块提供六种图像散列算法,使用相当方便

代码示例

来历

模糊丽娜

调整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));
}
#包括
#包括
#包括
#包括
#包括
#包括
无效计算(cv::Ptr algo)
{
自动输入=cv::imread(“lena.png”);
cv::Mat相似的img;
//模糊攻击后的相似图像检测
GaussianBlur(输入,相似的{7,7},2,2);
简历:imwrite(“lena\u blur.png”,类似于img);
cv::Mat hash_inpu