学习c++/qt opencv 图像单模板多次匹配

一 学习函数

1.Mat类型转QImage类型

QImage PicMatch::MatToQImage(cv::Mat mtx)
{
    switch (mtx.type())
        {
        case CV_8UC1:
            {
                QImage img((const unsigned char *)(mtx.data), mtx.cols, mtx.rows, mtx.cols, QImage::Format_Grayscale8);
                return img;
            }
            break;
        case CV_8UC3:
            {
                QImage img((const unsigned char *)(mtx.data), mtx.cols, mtx.rows, mtx.cols * 3, QImage::Format_RGB888);
                return img.rgbSwapped();
            }
            break;
        case CV_8UC4:
            {
                QImage img((const unsigned char *)(mtx.data), mtx.cols, mtx.rows, mtx.cols * 4, QImage::Format_ARGB32);
                return img;
            }
            break;
        default:
            {
                QImage img;
                return img;
            }
        break;
    }
}

2.QImage类型转Mat类型

cv::Mat PicMatch::QImagetoMat(QImage image)
{
    cv::Mat mat;
        switch(image.format())
        {
        case QImage::Format_ARGB32:
        case QImage::Format_RGB32:
        case QImage::Format_ARGB32_Premultiplied:
            mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.bits(), image.bytesPerLine());
            break;
        case QImage::Format_RGB888:
            mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.bits(), image.bytesPerLine());
            cv::cvtColor(mat, mat, CV_BGR2RGB);
            break;
        case QImage::Format_Indexed8:
            mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.bits(), image.bytesPerLine());
            break;
        }
        return mat;
}

3.matchtemplate模板匹配函数

CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ,
                                 OutputArray result, int method );

//image 原图;
//temple 模板图;
//result 输出;
//method 匹配方式 0-5 六种

4.normalize函数

//函数原型:

    void normalize(InputArray src,OutputArraydst, double alpha = 1, double beta = 0, intnorm_type = NORM_L2, int dtype = -1, InputArray mask = noArray() )

//示例:

    cv::normalize(resultImage, resultImage, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

src:输入数组

dst:输出数组,支持原地运算

alpha:range normalization模式的最小值

beta :range normalization模式的最大值,不用于norm normalization(范数归一化)模式。

normType:归一化的类型,可以有以下的取值:

    NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。

    NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)

    NORM_L1 :  归一化数组的L1-范数(绝对值的和)

    NORM_L2: 归一化数组的(欧几里德)L2-范数

dtype:dtype为负数时,输出数组的type与输入数组的type相同;

否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).

mask:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。

        归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。首先归一化是为了后面数据处理的方便,其次是保证程序运行时收敛加快。归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。归一化有同一、统一和合一的意思。        

5.minMaxLoc函数

//函数原型: 
    void minMaxLoc( const Mat& src,  double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, const Mat& mask=Mat() );
//示例:
    cv::minMaxLoc(resultImage, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());

用于寻找距震中的最大值和最小值。 

        参数1:InputArray类型的src,输入单通道数组(图像)。
        参数2:double*类型的minVal,返回最小值的指针。若无须返回,此值置为NULL。
        参数3:double*类型的maxVal,返回最大值的指针。若无须返回,此值置为NULL。
        参数4:Point*类型的minLoc,返回最小位置的指针(二维情况下)。若无须返回,此值置为NULL。
        参数5:Point*类型的maxLoc,返回最大位置的指针(二维情况下)。若无须返回,此值置为NULL。
        参数6:InputArray类型的mask,用于选择子阵列的可选掩膜。

6.rectangle函数——画矩形框

//函数原型:
    void rectangle( InputOutputArray img, Point pt1, Point pt2,
                const Scalar& color, int thickness,
                int lineType, int shift )

//示例:
    cv::rectangle(srcImage, matchLoc, 
                     cv::Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), 
                    cv::Scalar(0, 255, 0), 2, 8, 0);

第一个参数(img):将要被操作的图像

第二个和第三个参数分别是一个矩形的对角点

第四个(color)参数是线条的颜色(RGB)

第五个参数(thickness):组成矩阵线条的粗细程度。

第六个参数(line_type):线条的类型,见cvLine的描述。

第七个参数shift:坐标点的小数点位数

二 源码

cv::Mat srcImage; //原图像
cv::Mat templateImage;//匹配图像
cv::Mat resultImage;//输出图像

srcImage = cv::imread("C:\\Users\\TST\\Desktop\\1012\\image.bmp");
templateImage = cv::imread("C:\\Users\\TST\\Desktop\\1012\\template.bmp");

void PicMatch::on_pushButton_clicked()
{
/*   方法一:
    cv::Mat showImg = srcImage.clone();
    cv::Mat roi(templateImage,cv::Rect(58,17,30,40));  //模板图的某一个区域ROI
    int resultImage_rows = srcImage.rows - roi.rows + 1;
    int resultImage_cols = srcImage.cols - roi.cols + 1;

    resultImage.create(resultImage_cols,resultImage_rows, CV_32FC1);
    cv::matchTemplate(srcImage,roi,resultImage,CV_TM_CCOEFF_NORMED);
    //cv::matchTemplate(srcImage,templateImage,resultImage,CV_TM_CCOEFF);
    cv::normalize(resultImage, resultImage, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());


    cv::Mat midImg = resultImage.clone();
    double matchValue;
    int count0=0;
    int tempW=0, tempH=0;
    char matchRate[10];

    for(int i=0; i<resultImage_rows; i++)
    {
        for(int j=0; j<resultImage_cols; j++)
        {
            matchValue = resultImage.at<float>(i, j);
            sprintf(matchRate, "%0.2f", matchValue);
            if(matchValue >= 0.90 && (cv::abs(j - tempW)>5) && (cv::abs(i - tempH)>5) )
            {
                count0++;
                putText(showImg, matchRate, cv::Point(j-5, i-5), CV_FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 255), 1);
                rectangle(showImg, cv::Point(j, i), cv::Point(j + roi.cols, i + roi.rows), cv::Scalar(0, 255, 0), 1);
                tempW = j;
                tempH = i;
            }
        }
    }
    qDebug() <<"count="<<count0<<endl;

    imshow("dst", showImg);
    //showPic(MatToQImage(showImg),ui->Pic);
*/
    //方法二:
    cv::Mat showImg = srcImage.clone();
    //cv::Mat roi(templateImage,cv::Rect(58,17,30,40));
    int resultImage_rows = srcImage.rows - templateImage.rows + 1;
    int resultImage_cols = srcImage.cols - templateImage.cols + 1;

    resultImage.create(resultImage_cols,resultImage_rows, CV_32FC1);
    cv::matchTemplate(srcImage,templateImage,resultImage,CV_TM_CCOEFF_NORMED);
    //cv::matchTemplate(srcImage,templateImage,resultImage,CV_TM_CCOEFF);
    cv::normalize(resultImage, resultImage, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

    //cv::Mat midImg = resultImage.clone();
    double minValue, maxValue;
    cv::Point minLoc, maxLoc;
    cv::Point matchLoc;
    char matchRate[10];

    for(int i=0; i<25; i++)
    {
        // 20 为先将第一个最小值点附近模板宽度和高度的都设置为最大值防止产生干扰
        // 这个需要自己调试,有些是两倍,即加减模板图的宽高,但是可能我的模板图偏大,会导致错误
        int startX = maxLoc.x - 20;
        int startY = maxLoc.y - 20;
        int endX = maxLoc.x + 20;
        int endY = maxLoc.y + 20;
        if(startX<0 || startY<0)
        {
            startX = 0;
            startY = 0;
        }
         if(endX > resultImage.cols - 1 || endY > resultImage.rows - 1)
        {
            endX = resultImage.cols - 1;
            endY = resultImage.rows- 1;
        }
        //这两步不太懂,希望有大佬指点一下
         cv::Mat temp = cv::Mat::zeros(endX - startX, endY - startY, CV_32FC1);
         temp.copyTo(resultImage(cv::Rect(startX, startY, temp.cols, temp.rows)));
        //开始查找极值,即返回最差和最好的匹配度及其位置
         minMaxLoc(resultImage, &minValue, &maxValue, &minLoc, &maxLoc);
         if(maxValue<0.8)
             break;

         //qDebug() << "max_value= " << maxValue<<endl;
         //这两行是打印匹配度数值
         sprintf(matchRate, "%0.2f", maxValue);
         putText(showImg, matchRate, cv::Point(maxLoc.x - 5, maxLoc.y - 5), CV_FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 255), 1);
         //画出匹配的地方
         rectangle(showImg, maxLoc, cv::Point(maxLoc.x + templateImage.cols, maxLoc.y + templateImage.rows), cv::Scalar(0, 255, 0), 2);
    }
    imshow("midImg", midImg);
    imshow("resultImg", resultImage);
    imshow("dst", showImg);

    //showPic(MatToQImage(showImg),ui->Pic);
}

原链接:opencv学习之路(21)、模板匹配及应用 - 进击的小猴子 - 博客园

学习c++/qt opencv 图像单模板多次全方位旋转镜像匹配(二)_白嫖真香的博客-CSDN博客

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页
评论 1

打赏作者

跑路人员

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值