1.概述
利用計算機視覺技術對圖像進行處理,通常會用到圖像的比對,圖像比對是指圖像之間的比較,得到不同圖像之間的相似度,在機器識别的過程中把不同傳感器或同一傳感器在不同時間、不同成像條件下對同一景物獲得的兩幅或多幅圖像在空間上對準,或根據已知模式到另一幅圖中尋找對應的模式。比對方法大體分為基于灰階和基于特征兩類,其中基于特征的配準方法研究較多。
基于灰階的模闆比對方法原理簡單且在光照良好的條件下可以得到比較滿意的比對結果,故在本方案中根據輸入的模闆圖像從采集圖像中搜尋可進一步比對的目标可采用此方法。
基于特征的比對方法要先提取各個圖像中的特征再完成特征間的比對,通過比對的特征建立圖像間的映射關系求出比對圖像。一般而言提取特征點相對容易,能對圖像間的分辨率、旋轉、平移、光照變化等保持不變,故在利用模闆比對得到抓取的圖像後進一步進行特征比對。
基于特征比對的方法有很多種如:FAST、HARRIS、SIFT、SURF、SUSAN等。其中SIFT算法由D.G.Lowe于1999年提出,2004年完善總結。SIFT是一種魯棒性好的尺度不變特征描述方法,但SIFT算法計算資料量大、時間複雜度高、算法耗時長。
其中OpenCV也提供了很多圖像比對的方法,這篇文章将首先介紹一下基于圖像模闆進行圖像比對
2.模闆比對原理
模闆比對是通過模闆在采集到的原圖像進行滑動尋找與模闆圖像相似的目标。模闆比對不是基于直方圖的方式,而是基于圖像的灰階比對。其基本原理是逐像素的把一個以一定大小的實時圖像視窗的灰階矩陣與參考圖像的所有可能的序列槽灰階陣列,按照某種相似度量方法進行搜尋比較的比對方法,從理論上說就是采用圖像相關技術。

圖1模闆選取
圖2模闆比對
如圖1所示,為了利用模闆比對從源圖像中得到比對區域,從源圖像選取該區域作為進行比對的模闆。模闆從源圖像左上角開始每次以一個像素點為機關進行移動,每到達一個位置,就會計算模闆矩陣和源圖像目前位置矩陣比對的“好”“壞”程度即兩個矩陣的相似程度,如圖2所示。
模闆滑動與源圖像比對過程中,将模闆和目前模闆覆寫區域的矩陣的計算結果存儲在矩陣(R)中。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兩種方法來講,越小的值就有着更高的比對結果,而其餘的方法則是數值越大比對效果越好
3.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(): 圖像比對時用的掩膜闆,必須和模闆圖像有相同的資料類型和尺寸
minMaxLoc()
void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = ,
Point * minLoc = ,
Point * maxLoc = ,
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 = ;
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 -;
}
else
cout << "圖像加載成功..." << endl << endl;
namedWindow("原圖像", WINDOW_AUTOSIZE);
namedWindow("模闆圖像", WINDOW_AUTOSIZE);
imshow("原圖像", srcImage);
imshow("模闆圖像", templateImage);
//定義軌迹條參數
trackbar_method=;
char mathodName[];
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, );
waitKey();
return ;
}
void method(int, void*)
{
Mat display;
srcImage.copyTo(display);
//建立輸出矩陣
int dstImage_rows=srcImage.rows-templateImage.rows + ;
int dstImage_cols=srcImage.cols-templateImage.cols + ;
dstImage.create(dstImage_rows, dstImage_cols, srcImage.type());
matchTemplate(srcImage, templateImage, dstImage,trackbar_method); //模闆比對
normalize(dstImage, dstImage, , , 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(,,));
imshow("比對圖像", display);
}
程式運作結果如下