一、理论基础
- 基于相关的模板匹配技术可直接用于在一幅图像中,寻找某种子图像模式。对于大小为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实现》,这本书写的很基础,适合初学者和研究人员