【從零學習OpenCV 4】影像模板匹配
- 2019 年 12 月 24 日
- 筆記
經過幾個月的努力,小白終於完成了市面上第一本OpenCV 4入門書籍《從零學習OpenCV 4》。為了更讓小夥伴更早的了解最新版的OpenCV 4,小白與出版社溝通,提前在公眾號上連載部分內容,請持續關注小白。
前面我們通過影像直方圖反向投影的方式在影像中尋找模板影像,由於直方圖不能直接反應影像的紋理,因此如果兩張不同模板影像具有相同的直方圖分布特性,那麼在同一張圖中對這兩張模板影像的直方圖進行反向投影,最終結果將不具有參考意義。因此,我們在影像中尋找模板影像時,可以直接通過比較影像像素的形式來搜索是否存在相同的內容,這種通過比較像素灰度值來尋找相同內容的方法叫做影像的模板匹配。
模板匹配常用於在一幅影像中尋找特定內容的任務中。由於模板影像的尺寸小於待匹配影像的尺寸,同時又需要比較兩張影像中的每一個像素的灰度值,因此常採用在待匹配影像中選擇與模板相同尺寸的滑動窗口,通過比較滑動窗口與模板的相似程度,判斷待匹配影像中是否含有與模板影像相同的內容,其原理如圖4-11所示。
圖4-11 模板匹配示意圖
在圖4-11中,右側4×4的影像是模板影像,每個像素中的數字是該像素的灰度值,左側8×8影像是待匹配影像,模板匹配的流程如下:
Step1:在待匹配影像中選取與模板尺寸大小相同的滑動窗口,如圖4-11中的陰影區域所示。
Step2:比較滑動窗口中每個像素與模板中對應像素灰度值的關係,計算模板與滑動窗口的相似性。
Step3:將滑動窗口從左上角開始先向右滑動,滑動到最右邊後向下滑動一行,從最左側重新開始滑動,記錄每一次移動後計算的模板與滑動窗口的相似性。
Step4:比較所有位置的相似性,選擇相似性最大的滑動窗口作為備選匹配結果。
OpenCV 4中提供了用於影像模板匹配的函數matchTemplate(),該函數能夠實現模板匹配過程中影像與模板相似性的計算,在程式碼清單4-12中給出了函數原型。
程式碼清單4-12 matchTemplate()函數原型 1. void cv::matchTemplate(InputArray image, 2. InputArray templ, 3. OutputArray result, 4. int method, 5. InputArray mask = noArray() 6. )
- image:待模板匹配的原影像,影像數據類型為CV_8U和CV_32F兩者中的一個。
- templ:模板影像,需要與image具有相同的數據類型,但是尺寸不能大於image。
- result:模板匹配結果輸出影像,影像數據類型為CV_32F。如果image的尺寸為W×H,模板影像尺寸為w×h,則輸出影像的尺寸為(W-w+1)×(H-h+1)。
- method:模板匹配方法標誌,可選擇參數及含義在表4-3中給出。
- mask:匹配模板的掩碼,必須與模板影像具有相同的數據類型和尺寸,默認情況下不設置,目前僅支援在TM_SQDIFF和TM_CCORR_NORMED這兩種匹配方法時使用。
該函數同時支援灰度影像和彩色影像兩種影像的模板匹配。函數前兩個參數為輸入的原影像和模板影像,由於是在原影像中搜索是否存在與模板影像相同的內容,因此需要模板影像的尺寸小於原影像,並且兩者必須具有相同的數據類型。第三個參數為相似性矩陣,滑動窗口與模板的相似性係數存放在滑動窗口左上角第一個像素處,因此輸出的相似性矩陣尺寸要小於原影像的尺寸,如果image的尺寸為W×H,模板影像尺寸為w×h,則輸出影像的尺寸為(W-w+1)×(H-h+1)。因為在模板匹配中原影像不需要進行尺寸的外延,所以滑動窗口左上角可以移動的範圍要小於原影像的尺寸。無論輸入的是彩色影像還是灰度影像,函數輸出結果都是單通道矩陣。了解相似性係數記錄的方式便於尋找到與模板最相似的滑動窗口,繼而在原圖中標記出與模板相同的位置。函數第四個參數是滑動窗口與模板相似性係數的計算方式,OpenCV 4提供了多種計算方法,所有可以選擇的標誌參數在表4-3中給出,接下來對每一種方法進行詳細介紹。
表4-3 matchTemplate()函數模板匹配方法選擇標誌參數
標誌參數 |
簡記 |
作用 |
---|---|---|
TM_SQDIFF |
0 |
平方差匹配法 |
TM_SQDIFF_NORMED |
1 |
歸一化平方差匹配法 |
TM_CCORR |
2 |
相關匹配法 |
TM_CCORR_NORMED |
3 |
歸一化相關匹配法 |
TM_CCOEFF |
4 |
係數匹配法 |
TM_CCOEFF_NORMED |
5 |
歸一化相關係數匹配法 |
1
01
TM_SQDIFF
該方法名為平方差匹配法,計算的公式如式(6.9)所示,這種方法利用平方差來進行匹配,當模板與滑動窗口完全匹配時計算數值為0,兩者匹配度越低計算數值越大。
1
02
TM_SQDIFF_NORMED
該方法名為歸一化平方差匹配方法,計算公式如式(6.10)所示,這種方法是將平方差方法進行歸一化,使得輸入結果縮放到了0到1之間,當模板與滑動窗口完全匹配時計算數值為0,兩者匹配度越低計算數值越大。
(6.10)
1
03
TM_CCORR
該方法名為相關匹配法,計算公式如式(6.11)所示,這類方法採用模板和影像間的乘法操作,所以數值越大表示匹配效果越好,0表示最壞的匹配結果。
(6.11)
1
04
TM_CCORR_NORMED
該方法名為歸一化相關匹配法,計算公式如式(6.12)所示,這種方法是將相關匹配法進行歸一化,使得輸入結果縮放到了0到1之間,當模板與滑動窗口完全匹配時計算數值為1,兩者完全不匹配時計算結果為0。
(6.12)
1
05
TM_CCOEFF
該方法名為係數匹配法,計算公式如式(6.13)所示,這種方法採用相關匹配方法對模板減去均值的結果和原影像減去均值的結果進行匹配,這種方法可以很好的解決模板影像和原影像之間由於亮度不同而產生的影響。該方法中模板與滑動窗口匹配度越高計算數值越大,匹配度越低計算數值越小,並且該方法計算結果可以為負數。
(6.13)
其中:
(6.14)
1
05
TM_CCOEFF_NORMED
該方法名為歸一化係數匹配法,計算公式如式(6.15)所示,這種方法將係數匹配方法進行歸一化,使得輸入結果縮放到了1到-1之間,當模板與滑動窗口完全匹配時計算數值為1,當兩者完全不匹配時計算結果為-1。
(6.15)
了解不同的計算相似性方法時,重點需要知道在每種方法中最佳匹配結果的數值應該是較大值還是較小值,由於matchTemplate()函數的輸出結果是存有相關性係數的矩陣,因此需要通過minMaxLoc()函數去尋找輸入矩陣中的最大值或者最小值,進而確定模板匹配的結果。
通過尋找輸出矩陣的最大值或者最小值得到的只是一個像素點,需要以該像素點為矩形區域的左上角,繪製與模板影像同尺寸的矩形框,標記出最終匹配的結果。為了了解影像模板匹配相關函數的使用方法,在程式碼清單4-13中給出了在彩色影像中進行模板匹配的示常式序。程式中採用TM_CCOEFF_NORMED方法計算相關性係數,通過minMaxLoc()函數尋找相關性係數中的最大值,確定最佳匹配值的像素點坐標,之後在原圖中繪製出與模板最佳匹配區域的範圍,程式的運行結果在圖4-12中給出。
程式碼清單4-13 myMatchTemplate.cpp影像的模板匹配 1. #include <opencv2opencv.hpp> 2. #include <iostream> 3. 4. using namespace cv; 5. using namespace std; 6. 7. int main() 8. { 9. Mat img = imread("lena.png"); 10. Mat temp = imread("lena_face.png"); 11. if (img.empty() || temp.empty()) 12. { 13. cout << "請確認影像文件名稱是否正確" << endl; 14. return -1; 15. } 16. Mat result; 17. matchTemplate(img, temp, result, TM_CCOEFF_NORMED);//模板匹配 18. double maxVal, minVal; 19. Point minLoc, maxLoc; 20. //尋找匹配結果中的最大值和最小值以及坐標位置 21. minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); 22. //繪製最佳匹配區域 23. rectangle(img,cv::Rect(maxLoc.x,maxLoc.y,temp.cols,temp.rows),Scalar(0,0,255),2); 24. imshow("原圖", img); 25. imshow("模板影像", temp); 26. imshow("result", result); 27. waitKey(0); 28. return 0; 29. }
圖4-12 myMatchTemplate.cpp程式運行結果