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

猜你喜欢

转载自blog.csdn.net/csm1972385274/article/details/79711908