Python OpenCV實(shí)現(xiàn)圖像模板匹配詳解
1.什么是模板匹配及模板匹配方法matchTemplate()
介紹
提供一個(gè)模板圖像,一個(gè)目標(biāo)圖像,且滿(mǎn)足模板圖像是目標(biāo)圖像的一部分,從目標(biāo)圖像中尋找特定的模板圖像的過(guò)程,即為模板匹配。OpenCV提供了matchTemplate()方法幫助我們實(shí)現(xiàn)模板匹配。
該方法語(yǔ)法如下:
cv2.matchTemplate(image, templ, method, result=None, mask=None)
其中
image 即目標(biāo)圖像
templ 即模板圖像
method 是匹配的方式
mask 即掩模,可選。只有當(dāng)method為cv2.TM_SQDIFF或cv2.TM_CCORR_NORMED時(shí)才支持此參數(shù)。
method參數(shù)可以是以下值:
| 參數(shù)值 | 描述 |
|---|---|
| cv2.TM_SQDIFF | 差值平方和匹配,也稱(chēng)平方差匹配??梢岳斫鉃槭腔诓町惓潭鹊钠ヅ?,差異程度越小,匹配程度越高。完全匹配時(shí)值差值平方和為0。 |
| cv2.TM_SQDIFF_NORMED | 相關(guān)匹配。 可以理解為是基于相似程度的匹配,相似程度越高,計(jì)算結(jié)果越大,匹配程度就越高。 |
| cv2.TM_CCORR | 標(biāo)準(zhǔn)相關(guān)匹配。 規(guī)則同上。 |
| cv2.TM_CCORR_NORMED | 相關(guān)系數(shù)匹配 |
| cv2.TM_CCOEFF | 相關(guān)系數(shù)匹配。也是基于相似程度的匹配,計(jì)算結(jié)果是一個(gè)-1到1的浮點(diǎn)數(shù),1表示完全匹配,0表示毫無(wú)關(guān)系,-1表示兩張圖片亮度剛好相反。 |
| cv2.TM_CCOEFF_NORMED | 標(biāo)準(zhǔn)相關(guān)系數(shù)匹配,規(guī)則同上。 |
使用matchTemplate()方法,模板會(huì)將圖像中的每一塊區(qū)域都覆蓋一遍,并每次都使用所選的method方法進(jìn)行計(jì)算,每次的計(jì)算結(jié)果最后以一個(gè)二維數(shù)組的形式返回給我們。
素材準(zhǔn)備
為方便展示,特準(zhǔn)備以下圖片素材:
選擇世界名畫(huà)《三英戰(zhàn)呂布》(test.png),圖像shape為(738, 675, 3):

從中摳出一部分圖像元素作為下邊要用的模板素材。取材代碼如下( 不建議截圖,截圖摳出來(lái)的不一定能保證尺寸):
import cv2
img = cv2.imread("test.png")
print(img.shape)
# 電燈
img1 = img[20:220, 320:480, :]
# 虎牢關(guān)牌匾
img2 = img[75:150, 200:310, :]
# 青龍刀
img3 = img[170:530, 575:650, :]
# 關(guān)云長(zhǎng)
img4 = img[270:670, 160:330, :]
cv2.imshow("img0", img)
cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("img3", img3)
cv2.imshow("img4", img4)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('template_pic1.jpg', img1)
cv2.imwrite('template_pic2.jpg', img2)
cv2.imwrite('template_pic3.jpg', img3)
cv2.imwrite('template_pic4.jpg', img4)
取出的模板素材如下:
電燈

虎牢關(guān)牌匾

青龍刀

關(guān)云長(zhǎng)

2.單模板匹配
單模板匹配,即在匹配時(shí)中只使用到一個(gè)模板的匹配過(guò)程。具體又可以分為單目標(biāo)匹配和多目標(biāo)匹配。
2.1 單目標(biāo)匹配
單目標(biāo)匹配,即模板在目標(biāo)圖像中只匹配 匹配程度最高的一個(gè)匹配結(jié)果。
這需要找出這一次匹配結(jié)果所在位置的坐標(biāo)來(lái)確定其位置,
OpenCV提供了cv2.minMAXLoc()來(lái)實(shí)現(xiàn)。
該方法參數(shù)為matchTemplate()的返回值,會(huì)返回一個(gè)元組,元組中有四個(gè)值,分別是最小值、最大值、最小值時(shí)圖像左上角頂點(diǎn)坐標(biāo),最大值時(shí)圖像左上角頂點(diǎn)坐標(biāo)。
接下來(lái),使用 電燈(template_pic1) 圖片來(lái)匹配原圖,并用紅色的矩形在原圖像中圈出模板圖像,使用標(biāo)準(zhǔn)差值平方和的匹配方式,代碼如下:
import cv2
img = cv2.imread("test.png")
templ = cv2.imread("template_pic1.jpg")
height, width, c = templ.shape
results = cv2.matchTemplate(img, templ, cv2.TM_SQDIFF_NORMED)
# 獲取匹配結(jié)果中的最小值、最大值、最小值坐標(biāo)和最大值坐標(biāo)
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(results)
resultPoint1 = minLoc
resultPoint2 = (resultPoint1[0] + width, resultPoint1[1] + height)
cv2.rectangle(img, resultPoint1, resultPoint2, (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
如圖所示,成功標(biāo)出了模板圖。

如果要從多幅圖像中,找出與模板最匹配的結(jié)果,
以標(biāo)準(zhǔn)差值平方和的匹配方式為例,
則可以對(duì)這些圖像進(jìn)行遍歷,并比較每幅圖像對(duì)應(yīng)結(jié)果中的最小值,找出最小值中的最小值,則為最佳匹配項(xiàng)。
以?xún)煞鶊D像為例,將原圖翻轉(zhuǎn)一次,生成一張新的圖像(翻轉(zhuǎn)后結(jié)果與原圖較像,但差異巨大)
翻轉(zhuǎn)產(chǎn)生素材(test1.png)
import cv2
img = cv2.imread("test.png")
dst1 = cv2.flip(img, 1)
cv2.imshow("dst1", dst1)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('test1.png', dst1)????????
然后使用模板 關(guān)云長(zhǎng) (template_pic4.jpg)對(duì)兩幅圖像進(jìn)行匹配,輸出最佳匹配結(jié)果,并畫(huà)紅框展示:
import cv2
image = []
image.append(cv2.imread("test.png"))
image.append(cv2.imread("test1.png"))
templ = cv2.imread("template_pic4.jpg")
height, width, c = templ.shape
# 循環(huán)變量初始化
# 這里只是隨便設(shè)定一個(gè)值,該值并無(wú)意義,只是為了定義該變量
# 使用TM_SQDIFF_NORMED計(jì)算方法,計(jì)算出的結(jié)果通常是小于1的,所以minValue可以設(shè)置為1。如果是TM_SQDIFF計(jì)算方法,則就不行了,計(jì)算出來(lái)的值會(huì)很大。代碼就不再有效,需要把minMax設(shè)得更大,或者做其他修改。
index = -1
minValue = 1
minLoc1 = (0, 0)
# 遍歷每幅圖像
for i in range(0, len(image)):
results = cv2.matchTemplate(image[i], templ, cv2.TM_SQDIFF_NORMED)
min = cv2.minMaxLoc(results)[0]
if min < minValue:
minValue = min
minLoc1 = cv2.minMaxLoc(results)[2]
index = i
minLoc2 = (minLoc1[0] + width, minLoc1[1] + height)
cv2.rectangle(image[index], minLoc1, minLoc2, (0, 0, 255), 2)
cv2.imshow("result", image[index])
cv2.waitKey()
cv2.destroyAllWindows()
如圖,test.png中的關(guān)云長(zhǎng)與模板更為匹配。

2.2 多目標(biāo)匹配
多目標(biāo)匹配,即在目標(biāo)圖像中匹配出所有與模板圖像匹配的結(jié)果??梢允褂孟嚓P(guān)匹配或相關(guān)系數(shù)匹配。
素材準(zhǔn)備
還以原圖像"test.png"為參照,
為了產(chǎn)生方便我們做示例的圖像,我們?cè)谠搱D像的基礎(chǔ)上多加一盞電燈,生成"test2.png"
import cv2
img = cv2.imread("test.png")
templ = cv2.imread("template_pic1.jpg")
img[20:220, 30:190, :] = templ
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('test2.png', img)??????
多目標(biāo)匹配
多目標(biāo)匹配即對(duì)matchTemplate()匹配的總的結(jié)果,的計(jì)算情況數(shù)據(jù),使用for循環(huán)遍歷,并設(shè)定一個(gè)判斷標(biāo)準(zhǔn)。
如使用標(biāo)準(zhǔn)相關(guān)系數(shù)(cv2.TM_CCOEFF_NORMED)的方法判斷,如:如果計(jì)算值大于0.99,則我們認(rèn)為匹配成功了。
使用電燈模板"template_pic1.jpg",匹配圖像test2.png。并對(duì)匹配的結(jié)果用紅色的矩形框標(biāo)記。
代碼示例如下:
import cv2
img = cv2.imread("test2.png")
templ = cv2.imread("template_pic1.jpg")
height, width, c = templ.shape
# 按照標(biāo)準(zhǔn)相關(guān)系數(shù)匹配
results = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF_NORMED)
for y in range(len(results)):
for x in range(len(results[y])):
if results[y][x] > 0.99:
cv2.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
程序執(zhí)行結(jié)果如下,成功匹配出了兩盞燈。

3.多模板匹配
多模板匹配,即進(jìn)行了n次單模板的匹配過(guò)程。
直接上示例:
在test.png中匹配電燈、青龍刀、虎牢關(guān)牌匾、關(guān)云長(zhǎng)四個(gè)圖像模板:
import cv2
def myMatchTemplate(img, templ):
height, width, c = templ.shape
results = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF_NORMED)
loc = list()
for i in range(len(results)):
for j in range(len(results[i])):
if results[i][j] > 0.99:
loc.append((j, i, j + width, i + height))
return loc
# 讀取原始圖像
img = cv2.imread("test.png")
# 模板列表
templs = list()
templs.append(cv2.imread("template_pic1.jpg"))
templs.append(cv2.imread("template_pic2.jpg"))
templs.append(cv2.imread("template_pic3.jpg"))
templs.append(cv2.imread("template_pic4.jpg"))
loc = list()
for t in templs:
loc += myMatchTemplate(img, t)
# 遍歷所有紅框的坐標(biāo)
for i in loc:
cv2.rectangle(img, (i[0], i[1]), (i[2], i[3]), (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
匹配效果如下:

以上就是Python OpenCV實(shí)現(xiàn)圖像模板匹配詳解的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV圖像模板匹配的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Python使用Opencv實(shí)現(xiàn)圖像特征檢測(cè)與匹配的方法
- Python+Opencv實(shí)現(xiàn)圖像匹配功能(模板匹配)
- opencv-python圖像配準(zhǔn)(匹配和疊加)的實(shí)現(xiàn)
- Opencv Python實(shí)現(xiàn)兩幅圖像匹配
- Python+Opencv實(shí)現(xiàn)圖像模板匹配詳解
- python計(jì)算機(jī)視覺(jué)opencv圖像金字塔輪廓及模板匹配
- python?OpenCV實(shí)現(xiàn)圖像特征匹配示例詳解
- Python應(yīng)用案例之利用opencv實(shí)現(xiàn)圖像匹配
相關(guān)文章
pycharm運(yùn)行pytest中文編碼格式錯(cuò)亂解決
這篇文章主要為大家介紹了pycharm運(yùn)行pytest中文編碼格式錯(cuò)亂的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Python 爬蟲(chóng)學(xué)習(xí)筆記之單線(xiàn)程爬蟲(chóng)
Python實(shí)現(xiàn)C#代碼生成器應(yīng)用服務(wù)于Unity示例解析

