OpenCV图像识别-模板匹配
模板匹配:
利用单独的模式图像,遍历可能包含该模式的更大图像,应用统计学算法,获得大图像上每个区域与模式图像相似程度的实数度量值.
在自动化设备中,机器视觉对象往往外形简单,光源稳定不变,几何失真也几乎可以忽略,于是,模板匹配就成为简易又非常实用的图像识别算法.
OpenCV提供的模板匹配API:
void matchTemplate(
InputArray image, //待检测图像
InputArray templ, //模板图像
OutputArray result, //匹配结果
int method //匹配算法选择
);
将templ图像的左上角第一个像素与image重合,遍历image图像,并比较.
比较后的匹配程度,会以实数的形式记录在result图像中,记录位置与image对应,由于模板本身有体积,所以result图像会比image图像小一些.
method参数表示可选的匹配算法,可取以下枚举值:
CV_TM_SQDIFF 平方差匹配法 匹配越好,值越小,最佳为0.
CV_TM_CCORR 相关匹配法 匹配越好,值越大.
CV_TM_CCOEFF 相关系数匹配法 匹配越好,值越大,0为随机
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
经测试,其中,CV_TM_CCORR算法有严重偏离问题,简易不要使用.
其中平方差算法计算最简单,匹配准确度也最低,而相关系数匹配法计算最复杂,匹配准确度也最高.
在应用中,常使用归一化匹配方法,更容易设置阈值.
以下示例程序使用OpenCV自带的滑动条功能,调节阈值.
使用了归一化相关系数匹配法,设置阈值后,如果匹配成功,则用红色矩形圈出,如果匹配失败,则用蓝色矩形圈出.读者可以自选图像进行测试.
开发环境:win10+Visual Stdio 2015+OpenCV3.1.0
程序类型:win32控制台程序.
/*
功能:模板匹配选择匹配阈值的小测试.
*/
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat frame; //待检测图像
Mat templ; //模板图像
//当前阈值
int threshold_v = 900;
//将[0,1]部分,映射到[0,1000].
int threshold_max = 1000;
//窗口名称
const char* WindowTitle1 = "src";
const char* WindowTitle2 = "templ";
//滑动条回调函数
void TestCallback(int, void*);
int main(int argc,char* argv[])
{
//加载图片,创建窗口
frame = imread("F:/project/picture/pic3/2.bmp");
templ = imread("F:/project/picture/pic3/w8.bmp");
namedWindow(WindowTitle1, CV_WINDOW_NORMAL);
namedWindow(WindowTitle2, CV_WINDOW_NORMAL);
//创建滑动条,确定选择阈值
createTrackbar("Threshold Value:", WindowTitle1, &threshold_v, threshold_max, TestCallback);
TestCallback(0, 0);
waitKey(0);
}
void TestCallback(int, void*)
{
//模板本身也是有一定体积的,所以result的宽高只能是这样
int width = frame.cols - templ.cols + 1;
int height = frame.rows - templ.rows + 1;
//将各像素的匹配值也输出为图像
Mat result(width, height, CV_32FC1);
matchTemplate(frame, templ, result, CV_TM_CCOEFF_NORMED);
cv::Point minLoc;
cv::Point maxLoc;
double minValue, maxValue;
minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc, Mat());
cout << minValue << endl;
cout << maxValue << endl;
cout << minLoc << endl;
cout << maxLoc << endl;
double thresholdD = (double)threshold_v / 1000;
if (maxValue>thresholdD)
{
rectangle(frame, Rect(maxLoc.x, maxLoc.y, templ.cols, templ.rows), Scalar(0, 0, 255), 2, 8);
}
else
{
rectangle(frame, Rect(maxLoc.x, maxLoc.y, templ.cols, templ.rows), Scalar(255, 0, 0), 2, 8);
}
imshow(WindowTitle1, frame);
imshow(WindowTitle2, templ);
}