前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。
PS:如有需要Python学习资料的小伙伴可以点击下方链接自行获取
Python免费学习资料、代码以及交流解答点击即可加入
简单来说模板匹配就是通过现有的模板去与图片进行比较找出图中所匹配的图像。
首先来看一下效果图:
左图是模板图片,中图是带测试的图片,右图是匹配的结果
程序将在“中图”中匹配“左图”的模板图片,如果中图中含有模板图片的话,则会在中图画出模板图片的位置(用蓝线圈出来)。
模板匹配是一种用于在较大图像中搜索和查找模板图像位置的方法。为此,OpenCV带有一个函数cv2.matchTemplate()。它只是将模板图像滑动到输入图像上(就像在2D卷积中一样),然后在模板图像下比较模板和输入图像的补丁。OpenCV中实现了几种比较方法。(您可以检查文档以了解更多详细信息)。它返回一个灰度图像,其中每个像素表示该像素的邻域与模板匹配多少。
如果输入图像的大小(WxH)和模板图像的大小(wxh),则输出图像的大小将为(W-w + 1,H-h + 1)。获得结果后,可以使用cv2.minMaxLoc()函数查找最大/最小值在哪里。将其作为矩形的左上角,并以(w,h)作为矩形的宽度和高度。该矩形是您模板的区域。
1.前提
2.两种方法实现
3.后记
程序运行之前先安装一下相关的库
cv2
imutils
报错1:
ModuleNotFoundError: No module named 'cv2' (安装cv2)
说明缺少opencv库
在命令提示符窗口中,执行下面的命令:
pip install opencv-python
如果觉得下载过慢的可以执行下面的命令:(使用了豆瓣源下载,结果和上面是一样的,只不过这个命令安装快一些)
pip install -i https://pypi.doubanio.com/simple/ opencv-python
模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在OpenCV里有6种,然后将每次的结果放入一个矩阵里,作为结果输出。假如原图形是AXB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
代码:
#模板匹配
import numpy as np
import cv2
def cv_show(name,image):
cv2.imshow(name,image)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("source.jpg")
template = cv2.imread("m.jpg")
# 转换为灰度图片
gray1 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 读取测试图片并将其转化为灰度图片
gray2 = cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
h,w = template.shape[:2]
#匹配
#TM_SQDIFF 匹配方法,归一化的方法更好用
res = cv2.matchTemplate(gray1,gray2,cv2.TM_SQDIFF)
#得到极值坐标
min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res)
top_left = min_loc
bottom_right = (top_left[0]+w,top_left[1]+h)
#画出标记点
cv2.rectangle(img,top_left,bottom_right,255,2)
cv_show("img",img)
运行结果:
多尺度模板匹配实现步骤
代码实现:
# coding=utf-8
# 导入python包
import numpy as np
import imutils
import cv2
# 读取模板图片
template = cv2.imread("m.jpg")
# 转换为灰度图片
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
# 读取测试图片并将其转化为灰度图片
image = cv2.imread('source.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 执行边缘检测
template = cv2.Canny(template, 50, 200)
(tH, tW) = template.shape[:2]
# 显示模板
#cv2.imshow("Template", template)
found = None
# 循环遍历不同的尺度
for scale in np.linspace(0.2, 1.0, 20)[::-1]:
# 根据尺度大小对输入图片进行裁剪
resized = imutils.resize(gray, width = int(gray.shape[1] * scale))
r = gray.shape[1] / float(resized.shape[1])
# 如果裁剪之后的图片小于模板的大小直接退出
if resized.shape[0] < tH or resized.shape[1] < tW:
break
# 首先进行边缘检测,然后执行模板检测,接着获取最小外接矩形
edged = cv2.Canny(resized, 50, 200)
#匹配
#TM_SQDIFF 匹配方法,归一化的方法更好用
result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
# 结果可视化
# 绘制矩形框并显示结果
clone = np.dstack([edged, edged, edged])
cv2.rectangle(clone, (maxLoc[0], maxLoc[1]), (maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)
#cv2.imshow("Visualize", clone)
#cv2.waitKey(0)
# 如果发现一个新的关联值则进行更新
if found is None or maxVal > found[0]:
found = (maxVal, maxLoc, r)
# 计算测试图片中模板所在的具体位置,即左上角和右下角的坐标值,并乘上对应的裁剪因子
(_, maxLoc, r) = found
(startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))
(endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))
# 绘制并显示结果
cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)
cv2.imshow("Image", image)
cv2.waitKey(0)
运行结果:
如果大家学会这种技术之后,再稍微改进一下,弄错一个小脚本,这样下次玩开心消消乐的那可以直接无敌了,再也不用担心找不到匹配的小方块了,哈哈哈哈。
在集体照的茫茫人海中,你还怕我找不到你???通过模板匹配,直接定位你的位置!