matchTemplate函数
- 使用OpenCV函數(shù)?matchTemplate?在模板塊和輸入圖像之間尋找匹配,獲得匹配結(jié)果圖像
- 使用OpenCV函數(shù)?minMaxLoc?在給定的矩陣中尋找最大和最小值(包括它們的位置).
原理
什么是模板匹配?
模板匹配是一項在一幅圖像中尋找與另一幅模板圖像最匹配(相似)部分的技術(shù).它是怎么實現(xiàn)的?
-
我們需要2幅圖像:
- 原圖像 (I):?在這幅圖像里,我們希望找到一塊和模板匹配的區(qū)域
- 模板 (T):?將和原圖像比照的圖像塊
-
為了確定匹配區(qū)域, 我們不得不滑動模板圖像和原圖像進行?比較?:
-
通過?滑動, 我們的意思是圖像塊一次移動一個像素 (從左往右,從上往下). 在每一個位置, 都進行一次度量計算來表明它是 “好” 或 “壞” 地與那個位置匹配 (或者說塊圖像和原圖像的特定區(qū)域有多么相似).
-
對于?T?覆蓋在?I?上的每個位置,你把度量值?保存?到?結(jié)果圖像矩陣?(R)?中. 在?R?中的每個位置??都包含匹配度量值:
上圖就是?TM_CCORR_NORMED?方法處理后的結(jié)果圖像?R?. 最白的位置代表最高的匹配. 正如您所見, 紅色橢圓框住的位置很可能是結(jié)果圖像矩陣中的最大數(shù)值, 所以這個區(qū)域 (以這個點為頂點,長寬和模板圖像一樣大小的矩陣) 被認為是匹配的.
-
實際上, 我們使用函數(shù)?minMaxLoc?來定位在矩陣?R?中的最大值點 (或者最小值, 根據(jù)函數(shù)輸入的匹配參數(shù)) .
我們的目標(biāo)是檢測最匹配的區(qū)域:
OpenCV中支持哪些匹配算法?
問得好. OpenCV通過函數(shù)?matchTemplate?實現(xiàn)了模板匹配算法. 可用的方法有6個:
這類方法利用平方差來進行匹配,最好匹配為0.匹配越差,匹配值越大.
標(biāo)準平方差匹配 method=CV_TM_SQDIFF_NORMED
相關(guān)匹配 method=CV_TM_CCORR
這類方法采用模板和圖像間的乘法操作,所以較大的數(shù)表示匹配程度較高,0標(biāo)識最壞的匹配效果.
標(biāo)準相關(guān)匹配 method=CV_TM_CCORR_NORMED
相關(guān)匹配 method=CV_TM_CCOEFF
這類方法將模版對其均值的相對值與圖像對其均值的相關(guān)值進行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示沒有任何相關(guān)性(隨機序列).
在這里
標(biāo)準相關(guān)匹配 method=CV_TM_CCOEFF_NORMED
通常,隨著從簡單的測量(平方差)到更復(fù)雜的測量(相關(guān)系數(shù)),我們可獲得越來越準確的匹配(同時也意味著越來越大的計算代價). 最好的辦法是對所有這些設(shè)置多做一些測試實驗,以便為自己的應(yīng)用選擇同時兼顧速度和精度的最佳方案.
代碼
-
在這程序?qū)崿F(xiàn)了什么?
- 載入一幅輸入圖像和一幅模板圖像塊 (template)
- 通過使用函數(shù)?matchTemplate?實現(xiàn)之前所述的6種匹配方法的任一個. 用戶可以通過滑動條選取任何一種方法.
- 歸一化匹配后的輸出結(jié)果
- 定位最匹配的區(qū)域
- 用矩形標(biāo)注最匹配的區(qū)域
-
下載代碼: 單擊?這里
-
看一下代碼:
代碼說明
定義一些全局變量, 例如原圖像(img), 模板圖像(templ) 和結(jié)果圖像(result) , 還有匹配方法以及窗口名稱:
Mat img; Mat templ; Mat result; char* image_window = "Source Image"; char* result_window = "Result window";int match_method; int max_Trackbar = 5;載入原圖像和匹配塊:
img = imread( argv[1], 1 ); templ = imread( argv[2], 1 );創(chuàng)建窗口,顯示原圖像和結(jié)果圖像:
namedWindow( image_window, CV_WINDOW_AUTOSIZE ); namedWindow( result_window, CV_WINDOW_AUTOSIZE );創(chuàng)建滑動條并輸入將被使用的匹配方法. 一旦滑動條發(fā)生改變,回調(diào)函數(shù)?MatchingMethod?就會被調(diào)用.
char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );一直等待,直到用戶退出這個程序.
waitKey(0); return 0;讓我們先看看回調(diào)函數(shù). 首先, 它對原圖像進行了一份復(fù)制:
Mat img_display; img.copyTo( img_display );然后, 它創(chuàng)建了一幅用來存放匹配結(jié)果的輸出圖像矩陣. 仔細看看輸出矩陣的大小(它包含了所有可能的匹配位置)
int result_cols = img.cols - templ.cols + 1; int result_rows = img.rows - templ.rows + 1;result.create( result_cols, result_rows, CV_32FC1 );執(zhí)行模板匹配操作:
matchTemplate( img, templ, result, match_method );很自然地,參數(shù)是輸入圖像?I, 模板圖像?T, 結(jié)果圖像?R?還有匹配方法 (通過滑動條給出)
我們對結(jié)果進行歸一化:
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );通過使用函數(shù)?minMaxLoc?,我們確定結(jié)果矩陣?R?的最大值和最小值的位置.
double minVal; double maxVal; Point minLoc; Point maxLoc; Point matchLoc;minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );函數(shù)中的參數(shù)有:
- result:?匹配結(jié)果矩陣
- &minVal?和?&maxVal:?在矩陣?result?中存儲的最小值和最大值
- &minLoc?和?&maxLoc:?在結(jié)果矩陣中最小值和最大值的坐標(biāo).
- Mat():?可選的掩模
對于前二種方法 ( CV_SQDIFF 和 CV_SQDIFF_NORMED ) 最低的數(shù)值標(biāo)識最好的匹配. 對于其他的, 越大的數(shù)值代表越好的匹配. 所以, 我們在matchLoc?中存放相符的變量值:
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ){ matchLoc = minLoc; } else{ matchLoc = maxLoc; }顯示原圖像和結(jié)果圖像. 再用矩形框標(biāo)注最符合的區(qū)域:
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );imshow( image_window, img_display ); imshow( result_window, result );結(jié)果
開始測試我們的程序,一幅輸入圖像:
還有一幅模版圖像:
產(chǎn)生了一下結(jié)果圖像矩陣 (第一行是標(biāo)準的方法 SQDIFF, CCORR 和 CCOEFF, 第二行是相同的方法在進行標(biāo)準化后的圖像). 在第1列, 最黑的部分代表最好的匹配, 對于其它2列, 越白的區(qū)域代表越好的匹配.
|
|
|
|
正確的匹配在下面顯示 (右側(cè)被矩形標(biāo)注的人臉). 需要注意的是方法 CCORR 和 CCOEFF 給出了錯誤的匹配結(jié)果, 但是它們的歸一化版本給出了正確的結(jié)果, 這或許是由于我們實際上僅僅考慮 “最匹配” 而沒考慮其他可能的高匹配位置.
總結(jié)
以上是生活随笔為你收集整理的matchTemplate函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matchShapes函数
- 下一篇: CornerEigenValsAndVe