最近在看opencv相关的知识,看到了模板匹配,记录下来方便日后使用
简单的模板匹配(单模板)
多模板匹配
带角度的模板匹配
头文件:
#include
#include
模板匹配的主要函数 匹配并不是基于直方图的,
参数1:待匹配图像
参数2:模板,要求尺寸小于原图像
参数3:比较结果的映射图像
参数4:图像匹配方式 共6种 计算量不同,匹配精度也不同。
函数作用:
归一化数据。该函数分为范围归一化与数据值归一化。
其实范围归一化和数值归一化可以归为一类,一般来说数值归一化是指将数值归一到[0,1]区间上,
而范围归一化则指将数值归一到[a,b]上,a,b为任意值。由此看出,数值归一化是范围归一化的特例,包含在范围归一化中。
参数说明:
从一个矩阵中找出全局的最大值和最小值。
QTime t = QTime::currentTime();
GetOneMinLoc(g_srcImage, g_tempalteImage, p, TM_SQDIFF_NORMED);
int elapse = t.msecsTo(QTime::currentTime());
QString filename = QFileDialog::getOpenFileName(this, QString("读取最后结果"),
QString("./file"),
QString("File(*.*)"));
g_srcImage = imread(filename.toStdString().c_str());
if (!g_srcImage.data) {
qDebug() << "原始图读取失败";
return ;
}
filename = QFileDialog::getOpenFileName(this, QString("读取最后结果"),
QString("./file"),
QString("File(*.*)"));
g_tempalteImage = imread(filename.toStdString().c_str());
if (!g_tempalteImage.data) {
qDebug() << "模板图读取失败";
return ;
}
调用:
{
Point p;
GetOneMinLoc(g_srcImage, g_tempalteImage, p, TM_SQDIFF_NORMED);
rectangle(g_srcImage, Rect(p.x, p.y, g_tempalteImage.cols, g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8);
imshow("src Window", g_srcImage);
waitKey(0);
}
/* GetOneMinLoc
* 函数说明:
* 进行单一化模板匹配
* 参数1:待匹配图片
* 参数2:模板图片
* 参数3:匹配的位置
* 参数4:匹配类型
*/
double GetOneMinLoc(Mat image, Mat tepl, Point& point, TemplateMatchModes method) {
int result_cols = image.cols - tepl.cols + 1;
int result_rows = image.rows - tepl.rows + 1;
Mat result = Mat( result_cols, result_rows, CV_32FC1 );
matchTemplate(image, tepl, result, method );
double minVal, maxVal, Value;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
if(method == TM_SQDIFF || method == TM_SQDIFF_NORMED) {
point = minLoc;
Value = minVal;
} else {
point = maxLoc;
Value = maxVal;
}
rectangle(result, Rect(point.x, point.y, tepl.cols, tepl.rows), Scalar(0, 0, 255), 2, 8);
imshow("resault Window", result);
return Value;
}
调用
{
vector<Point> P;//存储所有检测目标的坐标
GetAllMinLoc(g_srcImage, g_tempalteImage, 0.18, Scalar(0, 0, 0), &P);
//根据获取的全部坐标数据圈出待检测目标
qDebug() << "rect" << P.size();
for (int k = 0; k < P.size(); k++) {
Point loc = P[k];
rectangle(g_srcImage, Rect(loc.x, loc.y, g_tempalteImage.cols, g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8);
}
/*
/* GetAllMinLoc
* 参数说明:
* image:输入原图像
* templ:输入的模板图像
* sim: 相似度,0~1之间,越接近0越相似
* mask: 覆盖区颜色,一般情况下直接取黑色即可Scalar(0,0,0)
* *all_min_loc:所有匹配到的目标的坐标
*/
void GetAllMinLoc(Mat image, Mat templ, double sim, Scalar mask, vector<Point>* all_min_loc) {
int src_Width = image.cols, src_Height = image.rows;
int templ_Width = templ.cols, templ_Height = templ.rows;
double min_value, max_value;
Point min_Loc, max_Loc;
Mat img_result;
Mat img_clon = image.clone();
if (templ_Width > src_Width || templ_Height > src_Height) {
qDebug("模板尺寸大于原图像,请选择正确的模板\n");
}
while (1) {
matchTemplate(img_clon, templ, img_result, TM_SQDIFF_NORMED);
minMaxLoc(img_result, &min_value, &max_value, &min_Loc, &max_Loc);
if (min_value < sim) {
// 预期内
all_min_loc->push_back(min_Loc);
// 去掉已检测部分
rectangle(img_clon, Rect(min_Loc.x, min_Loc.y, templ_Width, templ_Height), mask, -1);
} else {
qDebug() << "超出预期的匹配程度";
break;
}
}
}
// 代码优化:
void GetAllMinLoc(Mat image, Mat templ, double sim, Scalar mask, vector<Point>* all_min_loc) {
Point p;
Mat srcImg = image.clone();
while(1) {
if(GetOneMinLoc(srcImg, templ, p, TM_SQDIFF_NORMED) < sim) {
all_min_loc->push_back(p);
rectangle(srcImg, Rect(p.x, p.y, templ.cols, templ.rows), mask, -1);//掩盖检测到的第一块区域
} else {
break;
}
}
}
识别优化:使用灰度图像进行识别代码运行速度会加快很多
在模板匹配中通常没有完全一样的图片,这样就需要匹配大小不同的图像。
这样的匹配有以下两种方式: