admin管理员组

文章数量:1123058

opencv

项目描述

最近在看opencv相关的知识,看到了模板匹配,记录下来方便日后使用
简单的模板匹配(单模板)
多模板匹配
带角度的模板匹配

创作不易,点个关注呗 ^ _ ^

函数介绍

头文件:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

matchTemplate

模板匹配的主要函数 匹配并不是基于直方图的,
参数1:待匹配图像
参数2:模板,要求尺寸小于原图像
参数3:比较结果的映射图像
参数4:图像匹配方式 共6种 计算量不同,匹配精度也不同。

  • 平方差匹配(TM_SQDIFF):最好匹配为0,匹配越差值越大
  • 归一化平方差匹配(TM_SQDIFF_NORMED)
  • 相关匹配(TM_CCORR) 0最坏 值越大匹配越好
  • 归一化相关匹配(TM_CCORR_NORMED)
  • 系数匹配(TM_CCOEFF) 匹配相关性 1完美 -1糟糕 0无相关性
  • 化相关系数匹配(TM_CCOEFF_NORMED)

normalize

函数作用:
归一化数据。该函数分为范围归一化与数据值归一化。
其实范围归一化和数值归一化可以归为一类,一般来说数值归一化是指将数值归一到[0,1]区间上,
而范围归一化则指将数值归一到[a,b]上,a,b为任意值。由此看出,数值归一化是范围归一化的特例,包含在范围归一化中。
参数说明:

  • src 输入数组;
  • dst 输出数组,数组的大小和原数组一致;
  • alpha 用来规范值或者规范范围,并且是下限;
  • beta 只用来规范范围并且是上限,因此只在NORM_MINMAX中起作用;
  • norm_type 归一化选择的数学公式类型;
  • dtype 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同 的地方由dtype决定;
  • mark 掩码。选择感兴趣区域,选定后只能对该区域进行操作。

minMaxLoc

从一个矩阵中找出全局的最大值和最小值。

  • 参数1 src 输入单通道矩阵.
  • 参数2 minVal 返回最小值的指针; 如果不需要输入NULL.
  • 参数3 maxVal 返回最大值的指针; 如果不需要输入NULL.
  • 参数4 minLoc 返回最小值位置的指针 (二维情况下); 如果不需要输入NULL.
  • 参数5 maxLoc 返回最大值位置的指针 (二维情况下); 如果不需要输入NULL.
  • 参数6 mask 可选参数,用于选择一个子矩阵.

rectangle

  • 参数 img 输入图像。
  • 参数 pt1 矩形的顶点。
  • 参数 pt2 对应pt1的矩形的顶点。
  • 参数color 矩形颜色或亮度(灰度图像)。
  • 参数thickness 构成矩形的线条的厚度。负值,比如FILLED,意味着函数必须绘制一个填充矩形。
  • 参数lineType 线的类型. 参见 LineTypes
  • 参数shift 点坐标中的小数位数

测试代码运行时间

 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;}}
}

识别优化:使用灰度图像进行识别代码运行速度会加快很多

进阶

在模板匹配中通常没有完全一样的图片,这样就需要匹配大小不同的图像。
这样的匹配有以下两种方式:

  1. 改变模板图像的比例来适配
  2. 准备不同比例的模板来匹配
  3. 修改原来图像的比例来适配模板
    下面将对这些进行尝试和分析。

代码流程:

  1. 载入图像与模板;
  2. 将模板图像等比例放大或缩小
  3. 将不同的比例和图像适配
  4. 得到匹配区域的图片
  5. 将得到的ROI图片与原始模板进行相似性比较
  6. 筛选出相似性最好的ROI区域
  7. 在待测图片上进行框选
  8. 输出图片

本文标签: opencv