理論
模板匹配是在一個大圖里搜索和找模板圖像位置的方法霉赡。OpenCV有個函數(shù)cv2.matchTemplate()來做這個。它吧模板圖像在輸入圖像上滑動见妒,對比模板和在模板圖像下的輸入圖像塊鞋囊。它返回了一個灰度圖像,每個像素表示那個像素周圍和模板匹配的情況钠至。
如果輸入圖像大小是WxH而模板圖像大小是wxh葛虐,輸出圖像的大小是(W-w+1, H-h+1)棉钧。當你得到了結(jié)果屿脐,你可以用cv2.minMaxLoc()函數(shù)來找最大最小值。把它作為矩形左上角宪卿,w的诵,h作為矩形的寬和高。矩形是你的模板區(qū)域佑钾。
注意:
如果你用cv2.TM_SQDIFF作為比較方法西疤,最小值是最匹配。
OpenCV里的模板匹配
作為例子休溶,我們在照片里搜索messi的臉代赁。所以我做了這個模板:
我們會嘗試所有的比較方法
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread('messi5.jpg',0)
img2 = img.copy()
template = cv2.imread('template.jpg',0)
w, h = template.shape[::-1]# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR','cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
? ? img = img2.copy()
? ? method = eval(meth)? ? # Apply template Matching
? ? res = cv2.matchTemplate(img,template,method)
? ? min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)? ? # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
? ? if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
? ? ? ? top_left = min_loc
? ? else:
? ? ? ? top_left = max_loc
? ? bottom_right = (top_left[0] + w, top_left[1] + h)? ? cv2.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()
·cv2.TM_CCOEFF
·cv2.TM_CCOEFF_NORMED
·cv2.TM_CCORR
cv2.TM_CCORR_NORMED
cv2.TM_SQDIFF
cv2.TM_SQDIFF_NORMED
你可以看到cv2.TM_CCORR的結(jié)果不是我們想要的。
模板匹配多個目標
在前面我們搜索了messi的臉兽掰,目標只在圖像里出現(xiàn)了一次芭碍,假設(shè)你要搜的東西在圖像里出現(xiàn)多次,cv2.minMaxLoc()不會給你所有的位置孽尽。在這種情況下窖壕,我們會使用閾值,在這個例子里杉女,我們使用超級瑪麗的截圖來找金幣瞻讽。
import cv2
import numpy as np
from matplotlib import pyplot as pltimg_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
w, h = template.shape[::-1]res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
? ? cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)cv2.imwrite('res.png',img_rgb)
結(jié)果:
END