我們在之前討論OpenCV的輪廓以及直方圖時已經接觸過類似的匹配,事實上,它們原理基本上差不多,都是用一幅模板圖像和原圖進行匹配,從而找到原圖中相應的地方,作為OpenCV中的一種最基本的目標識別的方法,模板匹配有其一定的作用,今天我們來具體的進行討論。
模板匹配是一種用於在較大圖像中搜索和查找模板圖像位置的方法。為此,OpenCV帶有一個函數cv.matchTemplate()。
它只是將模板圖像滑動到輸入圖像上(就像在2D卷積中一樣),然后在模板圖像下比較模板和輸入圖像的拼圖。
如果輸入圖像的大小為(WxH),而模板圖像的大小為(wxh),則輸出圖像的大小將為(W-w + 1,H-h + 1)。得到結果后,可以使用cv.minMaxLoc()函數查找最大/最小值在哪。將其作為矩形的左上角,並以(w,h)作為矩形的寬度和高度,該矩形是模板的區域。
現在我們來進行分析,先來看第一個函數:
result=cv.matchTemplate(image, templ, method[, result[, mask]])
參數image:待搜索的圖像(大圖)
參數temple:搜索模板,需要和原圖一樣的數據類型且尺寸不能大於源圖像
參數result:比較結果的映射圖像,其必須為單通道,32位浮點型圖像,如果原圖(待搜索圖像)尺寸為W*H,而temple尺寸為w*h,則result尺寸一定是
(W-w+1)*(H-h+1)
參數method:指定匹配方法,有如下幾種:
CV_TM_SQDIFF:平方差匹配法;
CV_TM_SQDIFF_NORMED:歸一化平方差匹配法;
CV_TM_CCORR:相關匹配法;
CV_TM_CCORR_NORMED:歸一化相關匹配法;
CV_TM_CCOEFF:系數匹配法;
CV_TM_CCOEFF_NORMED:化相關系數匹配法。
用T表示模板圖像,I表示待匹配圖像,切模板圖像的寬為w高為h,用R表示匹配結果,匹配過程如下圖所示:
上述6中匹配方法可用以下公式進行描述:
(1)TM_SQDIFF:
該方法名為平方差匹配法,計算的公式如式(6.9)所示,這種方法利用平方差來進行匹配,當模板與滑動窗口完全匹配時計算數值為0,兩者匹配度越低計算數值越大。
其中 表示模板圖像,
表示原圖像。
(2)TM_SQDIFF_NORMED:
該方法名為歸一化平方差匹配方法,計算公式如式(6.10)所示,這種方法是將平方差方法進行歸一化,使得輸入結果縮放到了0到1之間,當模板與滑動窗口完全匹配時計算數值為0,兩者匹配度越低計算數值越大。
(3)TM_CCORR:
該方法名為相關匹配法,計算公式如式(6.11)所示,這類方法采用模板和圖像間的乘法操作,所以數值越大表示匹配效果越好,0表示最壞的匹配結果。
(4)TM_CCORR_NORMED:
該方法名為歸一化相關匹配法,計算公式如式(6.12)所示,這種方法是將相關匹配法進行歸一化,使得輸入結果縮放到了0到1之間,當模板與滑動窗口完全匹配時計算數值為1,兩者完全不匹配時計算結果為0。
(5)TM_CCOEFF:
該方法名為系數匹配法,計算公式如式(6.13)所示,這種方法采用相關匹配方法對模板減去均值的結果和原圖像減去均值的結果進行匹配,這種方法可以很好的解決模板圖像和原圖像之間由於亮度不同而產生的影響。該方法中模板與滑動窗口匹配度越高計算數值越大,匹配度越低計算數值越小,並且該方法計算結果可以為負數。
其中:
(6)TM_CCOEFF_NORMED:
該方法名為歸一化系數匹配法,計算公式如式(6.15)所示,這種方法將系數匹配方法進行歸一化,使得輸入結果縮放到了1到-1之間,當模板與滑動窗口完全匹配時計算數值為1,當兩者完全不匹配時計算結果為-1。
再來看另一個函數:
minVal,maxVal,minLoc,maxLoc=cv.minMaxLoc(src [,mask])
函數功能:假設有一個矩陣a,現在需要求這個矩陣的最小值,最大值,並得到最大值,最小值的索引。咋一看感覺很復雜,但使用這個cv2.minMaxLoc()函數就可全部解決。函數返回的四個值就是上述所要得到的。
現在我們使用模板圖像:
原圖:
我們將嘗試所有比較方法,以便我們可以看到它們的結果如何(如果使用cv.TM_SQDIFF作為比較方法,則最小值提供最佳匹配,其余的方法使用最大值進行最佳匹配),我們來看代碼:
def template(): img = cv.imread('min.jpg', 0) img2 = img.copy() template = cv.imread('temp.jpg', 0) w, h = template.shape[::-1] # 列表中所有的6種比較方法 methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR', 'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED'] for meth in methods: img = img2.copy() method = eval(meth) # 應用模板匹配 res = cv.matchTemplate(img, template, method) min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res) # 如果方法是TM_SQDIFF或TM_SQDIFF_NORMED,則取最小值 if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]: top_left = min_loc else: top_left = max_loc bottom_right = (top_left[0] + w, top_left[1] + h) cv.rectangle(img, top_left, bottom_right, 255, 2) plt.subplot(121), plt.imshow(res, cmap='gray') plt.title('Matching Result'), plt.xticks([]), plt.yticks([]) plt.subplot(122), plt.imshow(img, cmap='gray') plt.title('Detected Point'), plt.xticks([]), plt.yticks([]) plt.suptitle(meth) plt.show()
來看結果,cv.TM_CCOEFF方法:
cv.TM_CCOEFF_NORMED:
cv. TM_CCORR:
cv.TM_CCORR_NORMED:
cv.TM_SQDIFF:
cv.TM_SQDIFF_NORMED:
由此我們完成了OpenCV的模板匹配,它屬於最簡單的目標識別,對圖像的要求比較高,當原圖進行了旋轉或者是縮放時,這種匹配方法經常會失效,這個大家可以自行實驗,將原圖放大或者是縮小,又或者是對圖像進行一定角度的旋轉,都會導致一定程度的失效,對於這種缺陷,我們在后面會介紹更為強大的特征匹配的方法。