若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106017605
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)
OpenCV开发专栏(点击传送门)
上一篇:《OpenCV开发笔记(五十二):红胖子8分钟带你深入了解直方图对比匹配(图文并茂+浅显易懂+程序源码)》
下一篇:《OpenCV开发笔记(五十四):红胖子8分钟带你深入了解Haar级联分类器进行人脸检测(图文并茂+浅显易懂+程序源码)》
前言
红胖子来也!!!
模板匹配识别是传统识别的方式之一,纯靠计算力去进行相似度匹配。
实际在使用模板匹配时可能要需要结合其他算法予以辅助,能提高识别的精度。
Demo
模板匹配
概述
模板匹配是在一幅图像中寻找另一幅图模板图像的技术。
原理
模板匹配的原理其实就是将模板在匹配的图像上,从上至下,从左至右按照一个像素点步进去匹配相似度,所有的东西遍历后,得到所有相似度。
此处,特别注意,相似度的匹配是有多种方式的,根据不同的方式去匹配不同的相似度,主要有以下方式:
平方差匹配法: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
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/106017605