OpenCV开发笔记(五十三):红胖子8分钟带你深刻了解模板匹配识别(图文并茂+浅显易懂+程序源码)

若该文为原创文章,未经容许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:http://www.javashuo.com/article/p-qpsdoqzi-ky.html
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么本身研究算法

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)数组

OpenCV开发专栏(点击传送门)

上一篇:OpenCV开发笔记(五十二):红胖子8分钟带你深刻了解直方图对比匹配(图文并茂+浅显易懂+程序源码)ide

下一篇:OpenCV开发笔记(五十四):红胖子8分钟带你深刻了解Haar级联分类器进行人脸检测(图文并茂+浅显易懂+程序源码)函数

 

前言

红胖子来也!!!ui

模板匹配识别是传统识别的方式之一,纯靠计算力去进行类似度匹配。.net

实际在使用模板匹配时可能要须要结合其余算法予以辅助,能提升识别的精度。code

 

Demo

 

模板匹配

概述

      模板匹配是在一幅图像中寻找另外一幅图模板图像的技术。视频

原理

      模板匹配的原理其实就是将模板在匹配的图像上,从上至下,从左至右按照一个像素点步进去匹配类似度,全部的东西遍历后,获得全部类似度。blog

此处,特别注意,类似度的匹配是有多种方式的,根据不一样的方式去匹配不一样的类似度,主要有如下方式:图片

平方差匹配法:TM_SQDIFF

这类方法是对每一个像素利用平方差来进行匹配,最好匹配为0,匹配越差匹配值则越大。

归一化平方差匹配法:TM_SQDIFF_NORMED

这类方法是先平方差后再归一化。

相关匹配法:TM_CCORR

这类方法采用模板和图像间的乘法操做,数值越大表示匹配程度越高,0表示最坏的匹配。

归一化相关匹配法:TM_CCORR_NORMED

系数匹配法:TM_CCOEFF

这类方法将模板对其均值的相对值与图像对其均值的相关知识进行匹配,1表示彻底匹配,-1表示不匹配,0表示没有任何相关性。

归一化系数匹配法:TM_CCOEFF_NORMED

模板匹配函数原型

void matchTemplate( InputArray image,
                    InputArray templ,
                    OutputArray result,
                    int method,
                    InputArray mask = noArray() );
  • 参数一:InputArray类型的image,运行搜索的图像。它必须是8位或32位浮点。;
  • 参数二:InputArray类型的templ,模板搜索模板。它不能大于源映像,而且具备相同的数据类型;
  • 参数三:OutputArray类型的result,比较结果的结果图,result图像中的每个点的值表明了一次类似度比较结果。它必须是单通道32位浮点,若是图像尺寸是W x H而templ尺寸是w x h,则此参数result必定是(W-w+1)x(H-h+1)。
  • 参数四:int类型的method,指定的匹配方法,以下表:

  • 参数五:InputArray类型的mask,默认noArray(),搜索模板的掩码。它必须与temp具备相同的数据类型和大小。它是默认不设置。目前,只支持规范化的方法。

获取单通道矩阵中最大点、最小点的值和下标

void minMaxLoc(const SparseMat& a,
               double* minVal,
               double* maxVal,
               int* minIdx = 0,
               int* maxIdx = 0);
void minMaxLoc(InputArray src,
               double* minVal,
               double* maxVal = 0,
               Point* minLoc = 0,
               Point* maxLoc = 0,
               InputArray mask = noArray());
  • 参数一:InputArray类型的src,实际输入是单通道mat;
  • 参数二:double*类型的minVal,返回最小值;
  • 参数三:double*类型的maxVal,返回最大值,容许为0则不输出;
  • 参数四:Point*类型的minIdx,返回最小值的点位置,容许为0则不输出;
  • 参数五:Point*类型的maxIdx,返回最大值的点位置,容许为0则不输出;
  • 参数六:InputArray类型的mask,掩码用于选择子数组的可选掩码;

 

Demo涉及其余相关技术

OpenCV操做视频,请查看博文:《OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储

OpenCV绘制图形,请查看博文:《OpenCV开发笔记(七):OpenCV基础图形绘制

 

Demo源码

void OpenCVManager::testMatchTemplate()
{
    QString fileName1 = "E:/testFile/templ2.jpg";

    cv::Mat srcMat = cv::imread(fileName1.toStdString());

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(700, 900),
                                srcMat.type());

    cv::VideoCapture videoCapture;
    videoCapture.open("E:/testFile/test.avi");

    cv::Mat mat;
    cv::Mat dstMat;
    int currentIndex = 0;
    while(true)
    {
        // 刷新全图黑色
        windowMat = cv::Scalar(0, 0, 0);
        currentIndex = videoCapture.get(cv::CAP_PROP_POS_FRAMES);
        videoCapture >> mat;
        if(!mat.empty())
        {
            dstMat = mat.clone();

            // 模板头像
            mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);

            // 模板
            cv::Mat result;

            // 平方差匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_SQDIFF);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(minIdx.x,
                                       minIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(0, 0, 255));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 0,
                             0.5f,
                             0xFF0000,
                             "TM_SQDIFF minVal = %f",
                             minVal);
            }
            // 归一平方差匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_SQDIFF_NORMED);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(minIdx.x,
                                       minIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(0, 255, 0));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 1,
                             0.5f,
                             0x00FF00,
                             "TM_SQDIFF_NORMED minVal = %f",
                             minVal);
            }
            // 相关匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_CCORR);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(maxIdx.x,
                                       maxIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(255, 0, 0));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 2,
                             0.5f,
                             0x0000FF,
                             "TM_CCORR maxVal = %f",
                             maxVal);
            }
            // 归一相关匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_CCORR_NORMED);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(maxIdx.x,
                                       maxIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(255, 255, 0));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 3,
                             0.5f,
                             0x00FFFF,
                             "TM_CCORR maxVal = %f",
                             maxVal);
            }
            // 系数匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_CCOEFF);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(maxIdx.x,
                                       maxIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(255, 0, 255));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 4,
                             0.5f,
                             0xFF00FF,
                             "TM_CCOEFF maxVal = %f",
                             maxVal);
            }
            // 系数匹配法匹配法
            {
                cv::matchTemplate(dstMat, srcMat, result, cv::TM_CCOEFF_NORMED);
                // 获取结果中的最大值、最小值的下标和对应值
                double minVal, maxVal;
                cv::Point minIdx, maxIdx;
                cv::minMaxLoc(result, &minVal, &maxVal, &minIdx, &maxIdx);
                cv::rectangle(dstMat,
                              cv::Rect(maxIdx.x,
                                       maxIdx.y,
                                       srcMat.cols,
                                       srcMat.rows),
                              cv::Scalar(255, 255, 255));
                cvui::printf(windowMat,
                             srcMat.cols * 0,
                             srcMat.rows * 1 + dstMat.rows + 30 * 5,
                             0.5f,
                             0xFFFFFF,
                             "TM_CCOEFF_NORMED maxVal = %f",
                             maxVal);
            }

            // 视频复制
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 1 + dstMat.rows),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 0 + dstMat.cols));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);

        }

        qDebug() << __FILE__ << __LINE__ << currentIndex;
        // 更新
        cvui::update();
        // 显示
        cv::imshow(windowName, windowMat);
        // esc键退出
        int key = cv::waitKey(0);
        switch (key) {
        case 97:        // 'a' 往前一帧
            currentIndex--;
            if(currentIndex < 0)
            {
                currentIndex = 0;
            }
            videoCapture.set(cv::CAP_PROP_POS_FRAMES, currentIndex);
            break;
        case 115:       // ‘s’ 日后一帧
            break;
        default:
            break;
        }
        if(key == 27)
        {
            break;
        }
    }
}

 

工程模板:对应版本号v1.48.0

      对应版本号v1.48.0

 

上一篇:OpenCV开发笔记(五十二):红胖子8分钟带你深刻了解直方图对比匹配(图文并茂+浅显易懂+程序源码)

下一篇:OpenCV开发笔记(五十四):红胖子8分钟带你深刻了解Haar级联分类器进行人脸检测(图文并茂+浅显易懂+程序源码)

 

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:http://www.javashuo.com/article/p-qpsdoqzi-ky.html