提问者:小点点

用OpenCV/C++计算两幅图像的相似率


我使用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转换为灰度。 所以我只剩下一个频道了。 (比较起来要容易得多)。

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()函数,也许我没有正确使用它。

如果有人能引导我度过难关,帮我解决这个问题,我会很感激的。

如果你需要更多的信息,告诉我:)。

谢谢。


共1个答案

匿名用户

我怀疑imggray1.at(rows,cols)应该改为imggray1.at(rows,cols)

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

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

  • 8位3通道镜像(CV_8UC3)-->; .at(行,列)
  • 8位单通道镜像(CV_8UC1)-->; .at(row,column)
  • 32位3通道映像(CV_32FC3)-->; .at(行,列)
  • 32位单通道映像(CV_32FC1)-->; .at(row,column)

因此,如果函数应该支持任意的cv::mat,则需要编写一组if-else子句,或者完全避免.at()。 在您的情况下,由于imggray1imggray2是“二进制化”的,我想知道是否可以使用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);

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(opencv|c++|计算|两|幅|图像|率)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?