【问题标题】:Compute the similarity rate between two Images with opencv/c++使用 opencv/c++ 计算两个图像之间的相似率
【发布时间】:2020-07-22 14:05:50
【问题描述】:

我正在使用 OpenCV/C++ 来计算两个图像之间的相似率。我想告诉用户图片 A 看起来像图片 B 的百分比。

让我们看看下面的代码:

double getSimilarityRate(const cv::Mat A, const cv::Mat B){

    double cpt = 0.0;

    cv::Mat imgGray1, imgGray2;

    cv::cvtColor(A, imgGray1, CV_BGR2GRAY);
    cv::cvtColor(B, imgGray2, CV_BGR2GRAY);

    imgGray1 = imgGray1 > 128;
    imgGray2 = imgGray2 > 128;

    double total = imgGray1.cols * imgGray1.rows;

    if(imgGray1.rows > 0 && imgGray1.rows == B.rows && imgGray1.cols > 0 && imgGray1.cols == B.cols){

        for(int rows = 0; rows < imgGray1.rows; rows++){

            for(int cols = 0; cols < imgGray1.cols; cols++){

                if(imgGray1.at<int>(rows, cols) == imgGray2.at<int>(rows,cols)) cpt ++;
            }
        }

    }else{

        std::cout << "No similartity between the two images ... [EXIT]" << std::endl;
        exit(0);

    }

    double rate = cpt / total;


    return rate * 100.0;
}

int main(void)
{

/* ------------------------------------------ # ALGO GETSIMILARITY BETWEEN 2 IMAGES # -------------------------------------- */

    double rate;

    string fileNameImage1("C:\\Users\\hugoo\\Documents\\Prog\\NexterMU\\Qt\\OpenCV\\DetectionShapeProgram\\mire.jpg");
    cv::Mat image1 = imread(fileNameImage1);

    string fileNameImage2("C:\\Users\\hugoo\\Documents\\Prog\\NexterMU\\Qt\\OpenCV\\DetectionShapeProgram\\mire.jpg");
    cv::Mat image2 = imread(fileNameImage2);

    if(image1.empty() || image2.empty()){

        std::cout << "Images couldn't be loaded" << std::endl;
        exit(-1);

    }
    
    rate =  getSimilarityRate(image1, image2) ;

首先,我将矩阵从 BGR 转换为 GREY。所以我只剩下一个频道了。 (更容易比较)。

cv::Mat imgGray1, imgGray2;

cv::cvtColor(A, imgGray1, CV_BGR2GRAY);
cv::cvtColor(B, imgGray2, CV_BGR2GRAY);

然后我将它们设为二进制(255 或 0 --> 像素的白色或黑色):

imgGray1 = imgGray1 > 128;
imgGray2 = imgGray2 > 128;

在我的 for 循环中,我遍历每个像素并将他与第二张图像中的其他像素进行比较。 如果匹配,我增加一个变量(cpt ++)。

我计算比率并将其转换为 %,其中:

 double rate = cpt / total;
 return rate * 100.0;

问题是它似乎没有正确计算,因为它没有在控制台中返回我的速率值......

我认为问题来自 at() 函数,也许我没有正确使用它。

【问题讨论】:

  • 我没有看到您在代码中打印相似性的位置。
  • 如果图像 B 只是图像 A 的平移/缩放怎么办?你会认为这种情况类似吗?

标签: c++ opencv


【解决方案1】:

我怀疑imgGray1.at&lt;int&gt;(rows, cols) 应该是imgGray1.at&lt;uchar&gt;(rows, cols)

目前.at() 函数调用将int 作为模板参数,但通常cv::Matuchar 元素组成。你确定你的图片有int 元素吗?如果它确实包含uchar 元素,那么使用int 模板参数将导致访问超出图像对应的内存(基本上所有指针偏移量现在都应该是它们应该的4 倍)。

更一般的,如果你使用cv::Mat::at(),你需要根据cv::Mat::type()的输出使用不同的模板参数:

  • 8 位 3 通道图像 (CV_8UC3) --> .at&lt;cv::Vec3b&gt;(row, column)
  • 8 位 1 通道图像 (CV_8UC1) --> .at&lt;uchar&gt;(row, column)
  • 32 位 3 通道图像 (CV_32FC3) --> .at&lt;cv::Vec3f&gt;(row, column)
  • 32 位 1 通道图像 (CV_32FC1) --> .at&lt;float&gt;(row, column)

因此,如果一个函数应该支持任意的cv::Mat,要么需要编写一堆 if-else 子句,要么完全避免 .at()。在您的情况下,由于imgGray1imgGray2 是“二值化”的,我想知道rate 是否可以使用cv::norm 计算,可能像这样:

// NORM_INF counts the number of non-equal elements.
int num_non_equal = cv::norm(imgGray1, imgGray2, NORM_INF);
double rate = 1.0 - num_non_equal / static_cast<double>(total);

【讨论】:

  • 是的,就是这个原因。
  • 当我输入 imgGray1.at&lt;uchar&gt;(rows, cols) 而不是 imgGray1.at&lt;int&gt;(rows, cols) 时,它似乎有效。所以谢谢你。
  • 使用cv::norm(imgGray1, imgGray2, NORM_INF) 也可以,但速率值不同。对于使用第一种方法给出的 2 个不同图像,我得到 93.5% 的相似率。使用 cv::norm 的比率为 99 %。考虑到这两个矩阵,93.5 % 似乎比 99 % 准确得多。再次非常感谢您。
猜你喜欢
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 2014-03-13
  • 2017-08-22
  • 2012-03-11
  • 2011-05-27
相关资源
最近更新 更多