图像处理中的模板匹配c++实现

一、理论基础

  • 基于相关的模板匹配技术可直接用于在一幅图像中,寻找某种子图像模式。对于大小为MxN的图像f(x,y)和大小为JxK的子图像模式w(x,y),f与w的相关可表示为:

这里写图片描述

  • 其种,x=0,1,2,…N-K,y=0,1,2,…M-J。此处
    的目的是寻找匹配而不是对f(x,y)进行滤波操作,因此w的原点被设置在子图像的左上角,
    并且式(11-3) 给出的形式也完全适用于J和K 为偶数的情况。

  • 计算相关c(x,y)的过程就是在图像f(x,y)中逐点地移动子图像w(x,小),使w 的原点和点
    (x,y)重合,然后计算w与f中被w覆盖的图像区域对应像素的乘积之和,以此计算结果作
    为相关图像c(x,)在(x,y)点的响应。

  • 相关可用于在图像f(x,y)中找到与子图像w(x,y)匹配的所有位置。实际上,当w 按照上
    段中描述的过程移过整幅图像f之后,最大的响应点(xo,yo)即为最佳匹配的左上角点。我们
    也可以设定一个阈值T,认为响应值大于该阈值的点均是可能的匹配位置。

  • 相关的计算是通过将图像元素和子模式图像元素联系起来获得的,将相关元素相乘后累
    加。我们完全可以将子图像w视为一个按行或按列存储的向量这里写图片描述,将计算过程中被w覆盖的图像区域视为另一个按照同样的方式存储的向量这里写图片描述.这样一来,相关计算就- 成了向量之间的点积运算。

两个向量的点积为:
这里写图片描述

  • 其中,Θ 为向量这里写图片描述这里写图片描述之间的夹角。显然,当这里写图片描述这里写图片描述具有完全相同的方向(平行) 时,这里写图片描述,从而式(11-4) 取得其最大值这里写图片描述,这就意味着当图像的局部区域类似于子图像模式时,相关运算产生最大的响应。然而,式(11-4) 最终的取值还与向量这里写图片描述这里写图片描述自身的模有关,这将导致按照式(11-4) 计算的相关响应存在着对f和w 的灰度幅值比较敏感的缺陷。这样一来,在f的高灰度区域,可能尽管其内容与子图像w的内容并不相近,但由于这里写图片描述自身较大而同样产生一个很高的响应。可通过对向量以其模值来归一化解决这一问题,即通过来计算。
    这里写图片描述

改进的用于匹配的相关计算公式如下:
这里写图片描述

二、代码部分

  • 看了脑疼的理论,下面看看让人愉快的代码吧。

TemplateMatch.h

#pragma once
#include<opencv2\opencv.hpp>
using namespace cv;
typedef unsigned char BYTE;
void TemplateMatch(Mat * pTo, Mat * pTemplate,Mat * src);

TemplateMatch.cpp

 #include"TemplateMatch.h"

void TemplateMatch(Mat * pTo, Mat * pTemplate, Mat * src)
{

    //循环变量
    int i, j, m, n;

    double dSumT; //模板元素的平方和
    double dSumS; //图像子区域元素的平方和
    double dSumST; //图像子区域和模板的点积    

                   //响应值
    double R;

    //记录当前的最大响应
    double MaxR;

    //最大响应出现位置
    int nMaxX;
    int nMaxY;

    int nHeight = src->rows;
    int nWidth = src->cols;
    //模板的高、宽
    int nTplHeight = pTemplate->rows;
    int nTplWidth = pTemplate->cols;

    //计算 dSumT
    dSumT = 0;
    for (m = 0; m < nTplHeight; m++)
    {
        for (n = 0; n < nTplWidth; n++)
        {
            // 模板图像第m行,第n个象素的灰度值
            int nGray =*pTemplate->ptr(m, n);

            dSumT += (double)nGray*nGray;
        }
    }

    //找到图像中最大响应的出现位置
    MaxR = 0;
    for (i = 0; i < nHeight - nTplHeight + 1; i++)
    {
        for (j = 0; j < nWidth - nTplWidth + 1; j++)
        {
            dSumST = 0;
            dSumS = 0;

            for (m = 0; m < nTplHeight; m++)
            {
                for (n = 0; n < nTplWidth; n++)
                {
                    // 原图像第i+m行,第j+n列象素的灰度值
                    int nGraySrc = *src->ptr(i + m, j + n);

                    // 模板图像第m行,第n个象素的灰度值
                    int nGrayTpl = *pTemplate->ptr(m, n);

                    dSumS += (double)nGraySrc*nGraySrc;
                    dSumST += (double)nGraySrc*nGrayTpl;
                }
            }

            R = dSumST / (sqrt(dSumS)*sqrt(dSumT));//计算相关响应

            //与最大相似性比较
            if (R > MaxR)
            {
                MaxR = R;
                nMaxX = j;
                nMaxY = i;
            }
        }
    }

    //将找到的最佳匹配区域复制到目标图像
    for (m = 0; m < nTplHeight; m++)
    {
        for (n = 0; n < nTplWidth; n++)
        {
            int nGray = *src->ptr(nMaxY + m, nMaxX + n);
            //pTo->setTo(nMaxX + n, nMaxY + m, RGB(nGray, nGray, nGray));
            pTo->at<BYTE>(nMaxY + m, nMaxX + n) = nGray;
        }
    }

}   

测试代码

#include"TemplateMatch.h"
#include<iostream>

using namespace std;
int main()
{
    Mat src = imread("./src.jpg", 0);
    Mat Template = imread("./template.jpg", 0);
    Mat pt=src;
    pt.data = new BYTE[src.cols*src.rows];
    memset(pt.data, 255, src.cols*src.rows);
    TemplateMatch(&pt, &Template, &src);
    imshow("S", src);
    imshow("T", Template);
    imshow("P", pt);

    imwrite("S.jpg", src);
    imwrite("T.jpg", Template);
    imwrite("P.jpg", pt);
    waitKey(0);
    return 0;
}

效果如下:
这里写图片描述

    下面给出这个工程的百度云连接:链接:http://pan.baidu.com/s/1jIuuT3w 密码:veto

写的不好的地方,还希望指正,O(∩_∩)O谢谢。
在这我要强烈推荐一本书:《数字图像处理与机器视觉 Visual C 与Matlab实现》,这本书写的很基础,适合初学者和研究人员

猜你喜欢

转载自blog.csdn.net/wu_lian_nan/article/details/77279108