OpenCV3——matchTemplate影象模板匹配
參考文章:
其他:
1,功能介紹
matchTemplate函式主要應用於,尋找一張圖片在另一張圖片中的位置。
先看一個實際測試示例,在一張普通圖片中找到其中的水印位置。下圖依次為水印template圖——圖1,測試圖——圖2,在原圖中根據結果畫出的水印位置圖——圖3。
圖1:
圖2:
圖3:
2,函式分析
2.1引數分析
該函式第一個引數是源影象,第二個引數是模板影象,第三個引數是匹配的結果影象,第四個引數是用於指定比較的方法。
2.2實現原理
-
我們需要2幅影象:
- 原影象 (I): 在這幅影象裡,我們希望找到一塊和模板匹配的區域
- 模板 (T): 將和原影象比照的影象塊
我們的目標是檢測最匹配的區域:
-
為了確定匹配區域, 我們不得不滑動模板影象和原影象進行 比較 :
-
通過 滑動, 我們的意思是影象塊一次移動一個畫素 (從左往右,從上往下). 在每一個位置, 都進行一次度量計算來表明它是 “好” 或 “壞” 地與那個位置匹配 (或者說塊影象和原影象的特定區域有多麼相似).
-
對於 T 覆蓋在 I 上的每個位置,你把度量值 儲存 到 結果影象矩陣 (R) 中. 在 R 中的每個位置 都包含匹配度量值:
上圖就是 TM_CCORR_NORMED 方法處理後的結果影象 R . 最白的位置代表最高的匹配. 正如您所見, 紅色橢圓框住的位置很可能是結果影象矩陣中的最大數值, 所以這個區域 (以這個點為頂點,長寬和模板影象一樣大小的矩陣) 被認為是匹配的.
-
實際上, 我們使用函式 minMaxLoc 來定位在矩陣 R 中的最大值點 (或者最小值, 根據函式輸入的匹配引數) .
2.3 支援的演算法
OpenCV通過函式 matchTemplate 實現了模板匹配演算法. 可用的方法有6個。通常,隨著從簡單的測量(平方差)到更復雜的測量(相關係數),我們可獲得越來越準確的匹配(同時也意味著越來越大的計算代價). 最好的辦法是對所有這些設定多做一些測試實驗,以便為自己的應用選擇同時兼顧速度和精度的最佳方案.
1、cv::TM_SQDIFF:該方法使用平方差進行匹配,因此最佳的匹配結果在結果為0處,值越大匹配結果越差。
2、cv::TM_SQDIFF_NORMED:該方法使用歸一化的平方差進行匹配,最佳匹配也在結果為0處。
3、cv::TM_CCORR:相關性匹配方法,該方法使用源影象與模板影象的卷積結果進行匹配,因此,最佳匹配位置在值最大處,值越小匹配結果越差。
4、cv::TM_CCORR_NORMED:歸一化的相關性匹配方法,與相關性匹配方法類似,最佳匹配位置也是在值最大處。
5、cv::TM_CCOEFF:相關性係數匹配方法,該方法使用源影象與其均值的差、模板與其均值的差二者之間的相關性進行匹配,最佳匹配結果在值等於1處,最差匹配結果在值等於-1處,值等於0直接表示二者不相關。
在這裡
6、cv::TM_CCOEFF_NORMED:歸一化的相關性係數匹配方法,正值表示匹配的結果較好,負值則表示匹配的效果較差,也是值越大,匹配效果也好。
匹配方法的選取根據實際情況而定,這裡我們選擇的方法是cv::TM_CCOEFF_NORMED,源影象和匹配的相似度圖如下:
因此,我們若想找到最佳匹配位置,只需要找到匹配結果影象的最大值點即可,這裡我們使用cv::minMaxLoc()函式(具體請參考cv::Mat中最值和均值的求解)來找這個最大值點。找到結果後,將其繪製到原影象上,效果如下圖所示(圓等圖形的繪製請參考OpenCV3中的繪圖詳解),這裡注意匹配結果影象與原影象之間的大小關係,他們之間差了一個模板大小。
測試程式碼:
1.匹配單個物件
def MatchOne(image,template):
# w, h = template.shape[::-1]
h ,w = template.shape[0],template.shape[1]
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
print(type(res), res.shape)
# print(res)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(type(max_loc), type(max_val))
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(image, top_left, bottom_right, 255, 2)
cv2.imshow('res', res)
cv2.imshow('result', image)
cv2.waitKey(0)
if 0xFF == ord('q'):
cv2.destroyAllWindows()
2,匹配多個物件
def MultiObjMatch1(image,template):
print(type(image), image.shape)
print(type(template), template.shape)
# image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# template = cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
h, w = template.shape[0], template.shape[1]
# res = cv2.resize(res,(image.shape[1],image.shape[0]))
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print('maxval:',max_val,'max_loc_val:',res[max_loc[1]][max_loc[0]])
# print(len(res),len(res[0]))
print('type of res value:',type(res[0][0]), res.shape)
print('type of min_val:',type(min_val))
print('type of min_val convert to numpy:',type(np.float32(min_val)))
# print('min:', min_val, 'max:', max_val)
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(image, top_left, bottom_right, 255, 2)
res = (res - min_val) / (max_val - min_val)
for i in range(len(res)):
for j in range(len(res[i])):
if res[i][j] >0.95:
print(i,j,res[i][j])
top_left = (j,i)
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(image, top_left, bottom_right, 255, 2)
cv2.imshow('res', res)
cv2.imshow('compare', image)
res = res*255
cv2.imwrite('./images/fangmaskreslut_'+str(int(time.time()))+'.jpg',image)
cv2.imwrite('./images/fangmaskreslut_res_'+str(int(time.time()))+'.jpg',res)
cv2.waitKey(0)
if 0xFF == ord('q'):
cv2.destroyAllWindows()
pass
方法2
#將上一個max位置矩陣內的值都置為最小值,然後重新找最大值及其位置
def getNextMax(res,max_loc,min_val,h, w):
for i in range(max_loc[0],min(max_loc[0]+w,res.shape[1])):
for j in range(max_loc[1],min(max_loc[1]+h,res.shape[0])):
res[j][i]=min_val
# print('change value')
res = np.float32(res)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# print('max_val:',max_val)
return min_val, max_val, min_loc, max_loc,res
pass
def MultiObjMatch2(image,template):
print(type(image), image.shape)
print(type(template), template.shape)
# image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# template = cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
h, w = template.shape[0], template.shape[1]
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print('start while')
while max_val>0.6:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(image, top_left, bottom_right, 255, 2)
min_val, max_val, min_loc, max_loc ,res= getNextMax(res,max_loc,min_val,h, w)
print(max_val)
cv2.imshow('res', res)
cv2.imshow('compare', image)
# cv2.imwrite('./images/fangmaskreslut.jpg',image)
# cv2.imwrite('./images/fangmaskreslut_res.jpg',res)
cv2.waitKey(0)
if 0xFF == ord('q'):
cv2.destroyAllWindows()
pass
效果圖:
實景圖測試效果: