OpenCV探索之路(九):模板匹配


模板匹配的作用在圖像識別領域作用可大了。那什么是模板匹配?

模板匹配,就是在一幅圖像中尋找另一幅模板圖像最匹配(也就是最相似)的部分的技術。

說的有點抽象,下面給個例子說明就很明白了。

在上面這幅全明星照中,我們想找出姚明頭像的位置,並把它標記出來,可以做到嗎?

可以,這就是模板匹配的要做的事情。

其實模板匹配實現的思想也是很簡單很暴力的,就是拿着模板圖片(姚明頭像)在原圖(全明星照)中從左上至右下依次滑動,直到遇到某個區域的相似度低於我們設定的閾值,那么我們就認為該區域與模板匹配了,也就是我們找到了姚明的位置,並把它標記出來。

OpenCV中是通過MtachTemplate函數完成。

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

int main()
{
	Mat img, templ, result;
	img = imread("nba.jpg");
	templ = imread("76.png");

	int result_cols = img.cols - templ.cols + 1;
	int result_rows = img.rows - templ.rows + 1;
	result.create(result_cols, result_rows, CV_32FC1);

	matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED);//這里我們使用的匹配算法是標准平方差匹配 method=CV_TM_SQDIFF_NORMED,數值越小匹配度越好
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

	double minVal = -1;
	double maxVal;
	Point minLoc;
	Point maxLoc;
	Point matchLoc;
	cout << "匹配度:" << minVal << endl;
	minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());


	cout << "匹配度:" << minVal << endl;

	matchLoc = minLoc;

	rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);

	imshow("img", img);
	waitKey(0);

	return 0;
}

結果看來,大姚的頭像位置確實被綠框標記出來了!很准!

我還在程序中特意打印出匹配度的最小值,因為我們知道這個算法是數值越小匹配度越高,由輸出的結果看來這個數值還真的很小,說明匹配度真的相當高!

既然我們可以取得匹配度的數值,那我們是不是也可以利用該數值進行閾值對比呢?比如我想把在閾值范圍之內的頭像都標記出來。可以這么做:

//閾值判別,小於0.01才認為匹配成功,才將頭像框出來
if (minVal < 0.001)
{
    	rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);
}

同理,如果是數值越大表明匹配度越大的算法,就使用maxVal來對比就可以了。

上面的模板匹配我們使用了標准平方差匹配 CV_TM_SQDIFF_NORMED算法,看起來效果還不錯,那還有其他算法嗎?

問得好。OpenCV通過函數 matchTemplate 實現了模板匹配算法。可用的方法有6個:

通常,隨着從簡單的測量(平方差)到更復雜的測量(相關系數),我們可獲得越來越准確的匹配(同時也意味着越來越大的計算代價)。
最好的辦法是對所有這些設置多做一些測試實驗,以便為自己的應用選擇同時兼顧速度和精度的最佳方案。

你想采用哪種算法,只需要將對應的傳進函數matchTemplate里就可以了。

下面給出利用trackbar顯示出多種模板那匹配算法的代碼。

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat g_srcImage, g_tempalteImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum = 5;


void on_matching(int, void*)
{
	Mat srcImage;
	g_srcImage.copyTo(srcImage);
	int resultImage_cols = g_srcImage.cols - g_tempalteImage.cols + 1;
	int resultImage_rows = g_srcImage.rows - g_tempalteImage.rows + 1;
	g_resultImage.create(resultImage_cols, resultImage_rows, CV_32FC1);

	matchTemplate(g_srcImage, g_tempalteImage, g_resultImage, g_nMatchMethod);
	normalize(g_resultImage, g_resultImage, 0, 2, NORM_MINMAX, -1, Mat());
	double minValue, maxValue;
	Point minLocation, maxLocation, matchLocation;
	minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation);

	if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == CV_TM_SQDIFF_NORMED)
	{
		matchLocation = minLocation;
	}
	else
	{
		matchLocation = maxLocation;
	}

	rectangle(srcImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);
	rectangle(g_resultImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);

	imshow("原始圖", srcImage);
	imshow("效果圖", g_resultImage);

}

int main()
{
	g_srcImage = imread("nba.jpg");
	if (!g_srcImage.data)
	{
		cout << "原始圖讀取失敗" << endl;
		return -1;
	}
	g_tempalteImage = imread("76.png");
	if (!g_tempalteImage.data)
	{
		cout << "模板圖讀取失敗" << endl;
		return -1;
	}

	namedWindow("原始圖", CV_WINDOW_AUTOSIZE);
	namedWindow("效果圖", CV_WINDOW_AUTOSIZE);
	createTrackbar("方法", "原始圖", &g_nMatchMethod, g_nMaxTrackbarNum, on_matching);

	on_matching(0, NULL);


	waitKey(0);

	return 0;
}

當然也會有一些算法匹配失敗的.

實驗證明,該段程序效果很不錯,但注意的是,模板配在原圖摳出模板圖的形式下准確率才比較高,不然的話可能准確度就不太高了。

那么模板匹配能在哪些項目有應用呢?我說一下我的經驗。

最近我在參與實驗室的一個項目,做的是發票的分類,分類的方法我首先采用的是模板匹配,也就是從一類發票中摳出一些特征區域,以此作為模板,自己設定閾值,低於閾值就是算是跟該類發票匹配了,就可以 對其進行分類。在我的測試看來,准確率還可以,不過也隱藏這一個比較大的隱患就是,一旦發票種類多了,比如100種,那么檢測時間就會指數上升,這是不可取的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM