欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV图像识别-模板匹配

程序员文章站 2022-04-01 07:58:20
...

模板匹配:

    利用单独的模式图像,遍历可能包含该模式的更大图像,应用统计学算法,获得大图像上每个区域与模式图像相似程度的实数度量值.

    在自动化设备中,机器视觉对象往往外形简单,光源稳定不变,几何失真也几乎可以忽略,于是,模板匹配就成为简易又非常实用的图像识别算法.

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