1.概述
圖像匹配是指圖像之間的比較,得到圖像之間的相似度,在機器識別的過程中把不同傳感器或者同一個傳感器在不同時間、不同成像條件下對同一景物獲得的兩幅或者多幅圖像在空間上對準,或者根據已知模式到另一幅圖像中尋找對應的模式。
匹配方法大體分爲兩類:基於灰度值的匹配,基於特徵的匹配。
基於灰度值的匹配方法:原理簡單且在光照良好的條件下可以得到比較滿意的匹配結果。
基於特徵的匹配方法:提取個圖像中的特徵再完成特徵間的匹配,通過匹配的特徵建立圖像間的映射關係求出匹配圖像。一般來說求取特徵點相對容易,能夠對圖像間的分辨率、旋轉、平移、光照變化保持不變,故在利用模板匹配得到抓取圖像後進一步進行特徵匹配。
基於特徵匹配的方法有很多中如:SIFT、SURF、HARRIS、FAST、SUSAN 等。(sift最早提出魯棒性好的尺度不變性特徵描述方法,但是SIFT算法計算數據量大、時間複雜度高、算法耗時長。)
模板匹配原理
模板匹配是通過滑框在採集到的原圖像上進行滑動尋找與模板圖像相似的目標。模板匹配不是基於直方圖的方式而是基於圖像的灰度值匹配。將滑框在圖像上以一定的像素步長滑動將窗口內的圖像灰度矩陣與參考模板按照設定的相似度度量算法進行搜索比較。
圖1模板選取
圖2模板匹配
如圖1所示,爲了利用模板匹配從源圖像中得到匹配區域,從源圖像選取該區域作爲進行匹配的模板。模板從源圖像左上角開始每次以一個像素點爲單位進行移動,每到達一個位置,就會計算模板矩陣和源圖像當前位置矩陣匹配的“好”“壞”程度即兩個矩陣的相似程度,如圖2所示。
模板滑動與源圖像匹配過程中,將模板和當前模板覆蓋區域的矩陣的計算結果存儲在矩陣®中。R中每一個位置(x, y)都包含了匹配矩陣的計算結果。在OpenCV中提供了6種匹配度量方法。
(1).平方差匹配法CV_TM_SQDIFF
(2)歸一化平方差匹配法CV_TM_SQDIFF_NORMED
(3)相關匹配法CV_TM_CCORR
(4)歸一化相關匹配法CV_TM_CCORR_NORMED
(5)係數匹配法CV_TM_CCOEFF
其中
(6)化相關係數匹配法CV_TMCCOEFF_NORMED
通常來講,隨着從簡單測量方法(平方差)到更復雜的測量方法(相關係數法),我們可以獲得越來越準確的匹配。然而這同時也會以越來越大的計算量爲代價。對於選取何種方法,針對不同的匹配情況進行對此分析比較,選取更適合自己應用場景同時兼顧速度和精度的最佳方案。
注意
值得注意的是對於方法SQDIFF和SQDIFF_NORMED兩種方式,其值越小就代表着更高的匹配結果,其餘的方法數值越大則匹配效果越好。
opencv中提供的API
OpenCV中提供了matchTemplate()並配合minMaxLoc()函數實現圖像的模板匹配過程。通過matchTemplate()函數根據輸入模板搜尋輸入圖像中與模板相似的地方,獲得匹配結果圖像。通過minMaxLoc()函數來找到最大值和最小值.
matchTemplate
void cv::matchTemplate ( InputArray image,
InputArray templ,
OutputArray result,
int method,
InputArray mask = noArray()
)
參數解釋:
InputArray Image: 待搜索的圖像,且圖像必須爲8-bit或32-bit的浮點型圖像
InputArray templ: 用於進行模板匹配的模板圖像,類型和原圖像一致,但是尺寸不能大於原圖像
OutputArray result: 模板搜索結果輸出圖像,必須爲單通道32-bit位浮點型圖像,如果圖像尺寸是WxH而template尺寸是wxh,則此參數result一定是(W-w+1)x(H-h+1)
int method: 模板匹配計算類型,在匹配原理中已經介紹過這六種方法了,這裏不再贅述
InputArray mask=noArray(): 圖像匹配時用的掩膜板,必須和模板圖像有相同的數據類型和尺寸
minMaxLos()
void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = 0,
Point * minLoc = 0,
Point * maxLoc = 0,
InputArray mask = noArray()
)
參數解釋:
InputArray src:輸入的單通道數組
*double minVal:double類型指針,返回最小值,如果沒有定義返回NULL
double maxVal:同上,返回最大值
Point minLoc=0:Point類型的指針,在二維圖像中返回最小值的位置座標,如果沒有定義返回NULL
*Point maxLoc=0: **Point同上,返回最大位置座標
InputArray mask=noArray():可選掩膜板
4.示例代碼
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
//定義全局變量
Mat srcImage, templateImage, dstImage;
const int trackbar_method_maxValue = 5;
int trackbar_method;
//定義回調函數
void method(int, void*);
int main()
{
srcImage=imread("src.jpg");
templateImage=imread("template.jpg");
//判斷文件是否加載成功
if(srcImage.empty() || templateImage.empty())
{
cout << "圖像加載失敗!" << endl;
return -1;
}
else
cout << "圖像加載成功..." << endl << endl;
namedWindow("原圖像", WINDOW_AUTOSIZE);
namedWindow("模板圖像", WINDOW_AUTOSIZE);
imshow("原圖像", srcImage);
imshow("模板圖像", templateImage);
//定義軌跡條參數
trackbar_method=1;
char mathodName[50];
namedWindow("匹配圖像", WINDOW_AUTOSIZE);
sprintf(mathodName, "匹配方式%d\n 0:SQDIFF\n 1:SQDIFF_NORMED\n 2:TM_CCORR\n 3:TM_CCORR_NORMEND\n 4:TM_COEFF\n 5:TM_COEFF_NORMED", trackbar_method_maxValue);
createTrackbar(mathodName, "匹配圖像",&trackbar_method, trackbar_method_maxValue,method);
method(trackbar_method, 0);
waitKey(0);
return 0;
}
void method(int, void*)
{
Mat display;
srcImage.copyTo(display);
//創建輸出矩陣
int dstImage_rows=srcImage.rows-templateImage.rows + 1;
int dstImage_cols=srcImage.cols-templateImage.cols + 1;
dstImage.create(dstImage_rows, dstImage_cols, srcImage.type());
matchTemplate(srcImage, templateImage, dstImage,trackbar_method); //模板匹配
normalize(dstImage, dstImage, 0, 1, NORM_MINMAX); //歸一化處理
//通過minMaxLoc定位最佳匹配位置
double minValue, maxValue;
Point minLocation, maxLocation;
Point matchLocation;
minMaxLoc(dstImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat());
//對於方法SQDIFF和SQDIFF_NORMED兩種方法來講,越小的值就有着更高的匹配結果
//而其餘的方法則是數值越大匹配效果越好
if(trackbar_method==CV_TM_SQDIFF||trackbar_method==CV_TM_SQDIFF_NORMED)
{
matchLocation=minLocation;
}
else
{
matchLocation=maxLocation;
}
rectangle(display, matchLocation, Point(matchLocation.x+templateImage.cols, matchLocation.y+templateImage.rows),Scalar(0,0,255));
imshow("匹配圖像", display);
}