OpenCV学习模板匹配

转载自 https://blog.csdn.net/Small_Munich/article/details/79437482

模板匹配算法介绍


模板匹配算法主要为模板图像在基准图上进行由左往右、由上到下进行相关运算,最后得到一个进行相关运算后的系数矩阵:系数矩阵中的参数值用来度量模板图像在基准图中的子区域相似程度。采用相关系数来进行评判,模板匹配算法主要有基于灰度值的模板匹配、梯度值的模板匹配、相位相关匹配等方法。 

灰度值匹配: 


模板图像未经过任何预处理,直接取其像素值在原始图像上进行相关运算,灰度匹配算法优点在于速度快,缺点是对光照、亮度变化敏感,匹配鲁棒性不强。 


梯度值匹配: 


针对模板匹配对光照、亮度变化敏感,有学者提出采取先对模板图和原始图分别计算其对应的梯度图。通过梯度图进行相关运算,匹配准确率得以大幅提高。 
模板匹配主要缺点: 
1 基于灰度匹配算法不能够解决匹配景物存在旋转的情况 
2 模板匹配算法耗时较大,相对于特征匹配效率低

模板匹配算法示例(图像数字化展示)
采取矩阵演示模式,假设基准图像矩阵G为:

模板图像为T(假设为基准图矩阵G的子区域复制版本):

计算T在G的匹配位置(相关运算):越界部分补零 
[模板T中心点5从矩阵G起点(0,0)由左往右从上往下依次进行运算] 
Gs(0, 0) = 0*1 + 0*2 + 0*3 + 0*4 + 0*5 + 0*6 + 0*7 + 0*8 + 1*9 = 9 
Gs(0, 1) = 0*1 + 0*2 + 0*3 + 0*4 + 0*5 + 0*6 + 0*7 + 1*8 + 2*9 = 26 
…… 
计算所有的相关系数矩阵Gs : 

通过相关系数矩阵Gs可以看出,矩阵中最大参数值为285,最大参数值对应模板匹配的中心位置点(坐标)[绿色线框标定匹配结果]。当然,模板匹配算法改进会添加归一化步骤,梯度图像或者相位图的匹配。

模板匹配算法实验代码

#include "stdafx.h"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

/// 全局变量声明
bool use_mask;
Mat img; Mat templ; Mat mask; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";

int match_method;
int max_Trackbar = 5;

void MatchingMethod(int, void*);

int main(int argc, char** argv)
{

    argv[1] = "..\\Histograms_Matching\\image\\lena.jpg";
    argv[2] = "..\\Histograms_Matching\\image\\template.jpg";
    // argv[3] = "..\\Histograms_Matching\\image\\template2.jpg";
    /// 加载模板图与基准图
    img = imread(argv[1], IMREAD_COLOR);
    templ = imread(argv[2], IMREAD_COLOR);

    if (argc > 3) {
        use_mask = true;
        mask = imread(argv[3], IMREAD_COLOR);
    }

    if (img.empty() || templ.empty() || (use_mask && mask.empty()))
    {
        cout << "Can't read one of the images" << endl;
        return -1;
    }

    /// 显示窗口创建
    namedWindow(image_window, WINDOW_AUTOSIZE);
    namedWindow(result_window, WINDOW_AUTOSIZE);

    /// 创建轨迹条
    /// SQDIFF: 差值平方和匹配    SQDIFF NORMED: 标准化差值平方和匹配
    /// TM_CORR: 相关匹配         TM_CORR NORMED: 标准(归一化)相关匹配
    /// TM_COEFF: 相关系数匹配        TM_COEFF NORMED: 标准相关系数匹配
    const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
    createTrackbar(trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod);

    MatchingMethod(0, 0);  /// 匹配参数入口函数

    /// [wait_key]
    waitKey(0);
    system("pause");

    return 0;
}
//// 匹配函数
void MatchingMethod(int, void*)
{
    /// 原始图像拷贝
    Mat img_display;
    img.copyTo(img_display);

    /// 创建匹配输出图像结果矩阵
    int result_cols = img.cols - templ.cols + 1;
    int result_rows = img.rows - templ.rows + 1;

    result.create(result_rows, result_cols, CV_32FC1);

    /// 模板匹配
    bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
    if (use_mask && method_accepts_mask)
    {
        matchTemplate(img, templ, result, match_method, mask);
    }
    else
    {
        matchTemplate(img, templ, result, match_method);
    }

    //! 归一化
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    /// 通过minMaxLoc来定位最佳匹配位置
    double minVal; double maxVal; Point minLoc; Point maxLoc;
    Point matchLoc;
    /// 寻找图像矩阵中最大最小像素点
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

    /// 对于SQDIFF与SQDIFF_NORMED方式, 最佳匹配在最小点. 相反其它模式,最佳匹配在最大点位置
    if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED)
    {
        matchLoc = minLoc;
    }
    else
    {
        matchLoc = maxLoc;
    }

    /// 绘制匹配区
    rectangle(img_display, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar::all(0), 2, 8, 0);
    rectangle(result, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar::all(0), 2, 8, 0);

    imshow(image_window, img_display);
    imshow(result_window, result);

    return;
}

匹配实验结果:

总结


模板匹配算法经过多年发展已近趋于成熟,基于图像灰度信息的模板匹配算法最先被提出与使用,通过计算模板图像与基准图像滑动的子区域的相关系数进行判决匹配位置。随后由于基于灰度的匹配方法鲁棒性较差:光照、亮度等影响;因此出现基于梯度图像的模板匹配算法,梯度图抗光照、噪声、亮度等较好。模板匹配进行相关运算时耗时较高,由于卷积与相关实际运算中较为接近(可以近似理解卷积运算就是相关运算过程中核函数(模板图像)旋转180°),可以通过FFT进行加速运算;由于模板匹配对于景象有旋转变化时失效,后期逐渐发展为局部特征模式下的匹配算法,如SIFT、SURF等代表的算法火热了前二十年。随着12年Alexnet网络分类性能在ImageNet上脱颖而出,经典的手工设计方式告一段落,基于深度学习模式下的图像识别已经成为当下最流行的技术。但是,经典手工设计核函数思想在卷积神经网络设计中启发:Ps 低层次语义特征到高层次的语义特征是否类似于尺度空间的思想,不同大小的卷积核函数代表着不同的感受野等等。

代码下载

环境:windows10 x64 + vs2015 + opencv3.3.1

百度网盘链接:https://pan.baidu.com/s/1c3CFoIk 密码:xnce

猜你喜欢

转载自blog.csdn.net/u010440456/article/details/83153787