第15章:模板匹配
第15章:模板匹配
- 一、模板匹配基礎:
- 1. cv2.matchTemplate()函數:
- 2. 匹配原理:
- 3. 查找最值:
- 二、多模版匹配:
- 1. 獲取匹配位置集合:
- 2. 循環:
- 3.調整坐標
- 4.標記匹配圖像的位置
? 模板匹配是指在當前圖像A內匹配與圖像B最相似的部分,一般將圖像A稱為輸入圖像,將圖像B稱為模板圖像。 模板匹配的方法是將模板圖像B在圖像A上滑動,逐個遍歷所有像素以完成匹配。
? 例如,下圖中,大圖像“lena”是輸入圖像,“眼睛”圖像是模板圖像。查找的方式是,將模板圖像在輸入圖像內從左上角開始滑動,逐個像素遍歷整幅輸入圖像,以查找與其最匹配的部分。
一、模板匹配基礎:
1. cv2.matchTemplate()函數:
在OpenCV內,通過函數cv2.matchTemplate()實現模板匹配。語法格式為:
-
result=cv2.matchTemplate(image,templ,method[,mask])
-
image:為原始圖像,必須是8位或者32位的浮點型圖像。
-
templ:為模板圖像。它的尺寸必須小于或等于原始圖像,并且與原始圖像具有同樣的類型。
-
method:為匹配方法。該參數通過TemplateMatchModes實現,有6種可能的值,如表所示。
其具體對應的計算公式:
-
mask: 為模板圖像掩模。它必須和模板圖像 templ 具有相同的類型和大小。通常情況下該值使用默認值即可。當前,該參數僅支持TM_SQDIFF和TM_CCORR_NORMED兩個值。
-
函數cv2.matchTemplate()的返回值result 是一個結果集。類型是單通道32位浮點型。是由每個位置的比較結果所構成的。
2. 匹配原理:
? 如果輸入圖像(原始圖像)尺寸是W * H,模板的尺寸是w * h,則返回值的大小為(W-w+1)*(H-h+1)。
在進行模板匹配時,模板在原始圖像內遍歷。在水平方向上:
- 遍歷的起始坐標是原始圖像左數第1個像素值(序號從1開始)。
- 最后一次比較是當模板圖像位于原始圖像的最右側時,此時其左上角像素點所在的位置是W-w+1。
因此,返回值result在水平方向上的大小是W-w+1(水平方向上的比較次數)。
在垂直方向上:
- 遍歷的起始坐標從原始圖像頂端的第1個像素開始。
- 最后一次比較是當模板圖像位于原始圖像的最下端時,此時其左上角像素點所在位置是H-h+1。
所以,返回值result在垂直方向上的大小是H-h+1(垂直方向上的比較次數)。
如果原始圖像尺寸是 W * H,模板的尺寸是w * h,則返回值的大小為(W-w+1)* (H-h+1)。也就是說,模板圖像要在輸入圖像內比較(W-w+1)*(H-h+1)次。
例如,在上圖中,左上方的2×2小方塊是模板圖像,右下方的10×10圖像是輸入圖像(原始圖像)。在進行模板匹配時:
- 首先將模板圖像置于輸入圖像的左上角。
- 模板圖像在向右移動時,最遠只能位于輸入圖像的最右側邊界處,此時模板圖像左上角的像素對應著輸入圖像的第9列(輸入圖像寬度-模板圖像寬度+1=10-2+1=9)。
- 模板圖像在向下移動時,最遠只能位于輸入圖像最下端的邊界處。此時模板圖像左上角的像素對應著輸入圖像的第9行(輸入圖像高度-模板圖像高度+1=10-2+1=9)。
根據上述分析可知,比較結果result的大小滿足(W-w+1)*(H-h+1),在上例中就是(10-2+1)×(10-2+1),即9×9。也就是說,模板圖像要在輸入圖像內總計比較9×9=81次,這些比較結果將構成一個9×9大小的二維數組。
需要注意的是,函數cv2.matchTemplate()通過參數method來決定使用不同的查找方法。對于不同的查找方法,返回值result具有不同的含義。例如:
- method的值為cv2.TM_SQDIFF和cv2.TM_SQDIFF_NORMED時,result值為0表示匹配度最好,值越大,表示匹配度越差。
- method 的值為 cv2.TM_CCORR、cv2.TM_CCORR_NORMED、cv2.TM_CCOEFF 和cv2.TM_CCOEFF_NORMED時,result的值越小表示匹配度越差,值越大表示匹配度越好。
查找方法不同,結果的判定方式也不同。在查找最佳匹配時,首先要確定使用的是何種method,然后再確定到底是查找最大值,還是查找最小值。
3. 查找最值:
查找最值(極值)與最值所在的位置,可以使用 cv2.minMaxLoc()函數實現。語法格式如下:
- minVal,maxVal,minLoc,maxLoc=cv2.minMaxLoc(src[,mask])
- src:為單通道數組。
- minVal:為返回的最小值,如果沒有最小值,則可以是NULL(空值)。
- maxVal:為返回的最大值,如果沒有最小值,則可以是NULL。
- minLoc:為最大值的位置,如果沒有最大值,則可以是NULL。
- maxLoc:為最大值的位置,如果沒有最大值,則可以是NULL。
- mask:為用來選取掩模的子集,可選項
函數 cv2.minMaxLoc()能夠查找整個數組內的最值及它們的位置,并且可以根據當前的掩模集來選取特定子集的極值。有關該函數的更多說明及實例,請參考第12章。
綜上所述,函數cv2.matchTemplate()返回值中的最值位置就是模板匹配的位置。
例如,當method的值為cv2.TM_SQDIFF和cv2.TM_SQDIFF_NORMED時,0表示最佳匹配,值越大,則表示匹配效果越差。當使用這兩種方法時,要尋找最小值所在的位置作為最佳匹配。如下語句能夠找到cv2.matchTemplate()函數返回值中最小值的位置:
-
minVal,maxVal,minLoc,maxLoc=cv2.minMaxLoc(matchTemplate函數的返回值)
topLeft=minLoc # 查找最小值所在的位置
以topLeft點為模板匹配位置的左上角坐標,結合模板圖像的寬度w和高度h可以確定匹配位置的右下角坐標,代碼如下所示:
- bottomRight=(topLeft[0]+w,topLeft[1]+h) #w和h是模板圖像的寬度和高度
當 method 的值為 cv2.TM_CCORR、cv2.TM_CCORR_NORMED、cv2.TM_CCOEFF 和cv2.TM_CCOEFF_NORMED時,cv2.matchTemplate()函數的返回值越小,表示匹配度越差,而返回值越大則表示匹配度越好。此時,要尋找最大值所在的位置作為最佳匹配。
通過上述方式,我們確定了模板匹配的矩形對角坐標位置,接下來可以借助函數cv2.rectangle()將該位置用白色標記出來。
函數cv2.rectangle的語法格式為:
- Img=cv.rectangle(img,pt1,pt2,color[,thickness])
- img:表示要標記的目標圖像。
- pt1:是矩形的頂點。
- pt2:是pt1的對角頂點。
- color:是要繪制矩形的顏色或灰度級(灰度圖像)。
- thickness:是矩形邊線的寬度。
因此,使用的標記語句為:cv2.rectangle(img,topLeft,bottomRight,255,2)
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../lena.bmp') template = cv2.imread('../template.bmp')th, tw = template.shape[:2] rv = cv2.matchTemplate(img, template, cv2.TM_SQDIFF) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(rv)top_left = min_loc bottom_right = (top_left[0] + tw, top_left[1] + th) new_img = img.copy() cv2.rectangle(new_img, top_left, bottom_right, 255, 2)plt.subplot(131) plt.imshow(template, cmap='gray') plt.title('template') plt.axis('off')plt.subplot(132) plt.imshow(rv, cmap='gray') plt.title('matcing result') plt.axis('off')plt.subplot(133) plt.imshow(new_img, cmap='gray') plt.title('result') plt.axis('off')plt.show()二、多模版匹配:
前面的例子中,我們在輸入圖像lena中搜索其眼部子圖,該子圖在整個輸入圖像內僅出現了一次。但是,有些情況下,要搜索的模板圖像很可能在輸入圖像內出現了多次,這時就需要找出多個匹配結果。而函數 cv2.minMaxLoc()僅僅能夠找出最值,無法給出所有匹配區域的位置信息。所以,要想匹配多個結果,使用函數 cv2.minMaxLoc()是無法實現的,需要利用閾值進行處理,來獲取所有匹配的集合。
1. 獲取匹配位置集合:
numpy模塊中的函數where()能夠獲取模板匹配位置的集合。對于不同的輸入,其返回的值是不同的。
- 當輸入(參數)是一維數組時,返回值是一維索引,只有一組索引數組。
- 當輸入是二維數組時,返回的是匹配值的位置索引,因此會有兩組索引數組表示返回值的位置。
例如:
# 當輸入數組是一維時 import numpy as npa=np.array([3,6,8,1,2,88]) b=np.where(a>5) print(b)# 輸出結果 (array([1,2,5],dtype=int64),) # 當輸入數組是二維時 import numpy as npam=np.array([[3,6,8,77,66],[1,2,88,3,98],[11,2,67,5,2]]) b=np.where(am>5) print(b)# 輸出結果 (array([0,0,0,0,1,1,2,2],dtype=int64), array([1,2,3,4,2,4,0,2],dtype=int64))綜上所述,函數 np.where()可以找出在函數 cv2.matchTemplate()的返回值中,哪些位置上的值是大于閾值threshold的。
具體實現時,可以采用的語句為:
- loc=np.where(res >=threshold)
- res:是函數cv2.matchTemplate()進行模板匹配后的返回值。
- threshold:是預設的閾值
- loc:是滿足“res >=threshold”的像素點的索引集合。
2. 循環:
處理多個值,通常需要用到循環。因此,在獲取匹配值的索引集合后,可以采用如下語句遍歷所有匹配的位置,對這些位置做標記:
for i in 匹配位置集合:
? 標記匹配位置。
在循環處理匹配位置的時候,可以在循環中使用函數zip():
函數zip()用可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表。
例如:
因此,如果希望循環遍歷由np.where()返回的模板匹配索引集合,可以采用的語句為:
for i in zip(*模板匹配索引集合):
? 標記處理
3.調整坐標
函數 numpy.where()可以獲取滿足條件的模板匹配位置集合,然后可以使用函數cv2.rectangle()在上述匹配位置繪制矩形來標注匹配位置。
使用函數numpy.where()在函數cv2.matchTemplate()的輸出值中查找指定值,得到的形式為“(行號,列號)”的位置索引。但是,**函數cv2.rectangle()中用于指定頂點的參數所使用的是形式為“(列號,行號)”的位置索引。**所以,在使用函數cv2.rectangle()繪制矩形前,要先將函數numpy.where()得到的位置索引做“行列互換”??梢允褂萌缦抡Z句實現loc內行列位置的互換:
- loc[::-1]
4.標記匹配圖像的位置
函數cv2.rectangle()可以標記匹配圖像的具體位置,分別指定要標記的原始圖像、對角頂點、顏色、矩形邊線寬度即可。
關于矩形的對角頂點:
-
其中的一個對角頂點A可以通過for循環語句從確定的滿足條件的“匹配位置集合”內獲取。
-
另外一個對角頂點,可以通過頂點A的位置與模板的寬(w)和高(h)進行運算得到。
因此,標記各個匹配位置的語句為:-
for i in 匹配位置集合:
? cv2.rectangle(輸入圖像,i, (i[0] + w, i[1] + h ), 255, 2)
-
總結
- 上一篇: 常用注入 Script 方法
- 下一篇: Jar包转成Dll的方式(带嵌套的jar