使用OpenCV进行模板匹配(原图-模板图)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用OpenCV进行模板匹配(原图-模板图)相关的知识,希望对你有一定的参考价值。

描述:采集被匹配原图,获取原图中的一块区域作为模板,用模板进行对不断采集的图像进行匹配;
问题:1、使用哪些算法 匹配的结果好;
2、算法的过程是什么?
3、能够对不同情况下的模板匹配都比较有效;
原图->图像处理(算法?),
模板->图像处理(算法?),
模板匹配?,
得到匹配结果坐标。

参考技术A 匹配算法有很多,比如最简单的对比原图和模板图的像素值。
但是这种方法稍微有一点旋转和光照变化结果就会很差。

为了改进这个,有了SAD算法。
然后SAD相似的SSD。
再然后是计算区域互相关性的NCC算法。
以上三种算法中,SAD算法最简单,因此当模板大小确定后,SAD算法的速度最快。NCC算法与SAD算法相比要复杂得多。

至于算法的过程,这三个算法都是很好理解的算法,我觉得还是自学比较好。追问

恩 谢谢啊~~~我使用的是NCC算法, 但是当原图中有旋转时,匹配不到。有什么好的解决方法吗?

追答

旋转的话匹配不到太正常了,因为NCC就不是为旋转设计的啊。
所以现在也有用旋转不变性做的。
比如SURF来匹配,虽然已经是关键点匹配的快速算法了,但是,但是,还是很慢。

追问

恩恩呢~~太感谢了啊!我查查surf算法。。。在匹配前,对原图和模板图做怎样的处理,匹配的效果会更好呢?

本回答被提问者采纳

使用 Open CV C++ 进行模板匹配

【中文标题】使用 Open CV C++ 进行模板匹配【英文标题】:Template Matching Using Open CV C++ 【发布时间】:2015-04-14 03:19:19 【问题描述】:

我正在尝试在货架图图像中执行模板匹配, 这是我的图片- 1 -

2 - 我的模板图像 -

   #include "stdio.h"
#include "opencv2/highgui/highgui.hpp"
#include "iostream"
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv/cv.h"

using namespace cv;
using namespace std;

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

/**
 * Function to perform fast template matching with image pyramid
 */

void fastMatchTemplate(cv::Mat& srca,  // The reference image
                       cv::Mat& srcb,  // The template image
                       cv::Mat& dst,   // Template matching result
                       int maxlevel)   // Number of levels

    std::vector<cv::Mat> refs, tpls, results;

    // Build Gaussian pyramid
    cv::buildPyramid(srca, refs, maxlevel);
    cv::buildPyramid(srcb, tpls, maxlevel);

    cv::Mat ref, tpl, res;

    // Process each level
    for (int level = maxlevel; level >= 0; level--)
    
        ref = refs[level];
        tpl = tpls[level];
        res = cv::Mat::zeros(ref.size() + cv::Size(1,1) - tpl.size(), CV_32FC1);

        if (level == maxlevel)
        
            // On the smallest level, just perform regular template matching
            cv::matchTemplate(ref, tpl, res, CV_TM_CCORR_NORMED);
        
        else
        
            // On the next layers, template matching is performed on pre-defined 
            // ROI areas.  We define the ROI using the template matching result 
            // from the previous layer.

            cv::Mat mask;
            cv::pyrUp(results.back(), mask);

            cv::Mat mask8u;
            mask.convertTo(mask8u, CV_8U);

            // Find matches from previous layer
            std::vector<std::vector<cv::Point> > contours;
            cv::findContours(mask8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

            // Use the contours to define region of interest and 
            // perform template matching on the areas
            for (int i = 0; i < contours.size(); i++)
            
                cv::Rect r = cv::boundingRect(contours[i]);
                cv::matchTemplate(
                    ref(r + (tpl.size() - cv::Size(1,1))), 
                    tpl, 
                    res(r), 
                    CV_TM_CCORR_NORMED
                );
            
        

        // Only keep good matches
        cv::threshold(res, res, 0.80, 1., CV_THRESH_TOZERO);
        results.push_back(res);
    

    res.copyTo(dst);



int main()

        /* string path;
     string path1;
    cout << "Please enter image template: ";
    cin >> path;
    cout << "Please enter image reference: ";
    cin >> path1;*/
    cv::Mat ref = cv::imread("E:\\CodeImage\\plan1.png");
    cv::Mat tpl = cv::imread("E:\\CodeImage\\t.png");
    if (ref.empty() || tpl.empty())
        return -1;

    cv::Mat ref_gray, tpl_gray;
    cv::cvtColor(ref, ref_gray, CV_BGR2GRAY);
    cv::cvtColor(tpl, tpl_gray, CV_BGR2GRAY);

    cv::Mat dst;
    fastMatchTemplate(ref_gray, tpl_gray, dst, 2);

    while (true)
    
        double minval, maxval;
        cv::Point minloc, maxloc;
        cv::minMaxLoc(dst, &minval, &maxval, &minloc, &maxloc);

        if (maxval >= 0.9)
        
            cv::rectangle(
                ref, maxloc, 
                cv::Point(maxloc.x + tpl.cols, maxloc.y + tpl.rows), 
                CV_RGB(0,255,0), 2
            );
            cv::floodFill(
                dst, maxloc, 
                cv::Scalar(0), 0, 
                cv::Scalar(.1), 
                cv::Scalar(1.)
            );
        
        else
        
         cout << "No match found ";
         break;
        
    

    cv::imshow("result", ref);
    cv::waitKey();
    return 0;
    getchar();

我的结果图像是 -

您可以在生成的图像中看到绿色矩形,但应该有 2 个匹配项,它只给出一个。

我怎样才能找到这两个图像,因为它们是相同的。

【问题讨论】:

【参考方案1】:

您的问题的解决方案可以在以下链接中找到:

Using OpenCV MatchTemplate On Blister Pack

【讨论】:

以上是关于使用OpenCV进行模板匹配(原图-模板图)的主要内容,如果未能解决你的问题,请参考以下文章

Opencv模板匹配

opencv 模板匹配,在图像中寻找物体

Python+OpenCV图像处理—— 模板匹配

Python+OpenCV图像处理—— 模板匹配

OpenCV探索之路:模板匹配

OpenCV基础之模板匹配与直方图