作者:济南谷幽兰 | 来源:互联网 | 2023-09-17 18:03
导读
模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。
模板匹配实现简单(2~3行代码),计算效率高,不需要执行阈值化、边缘检测等操作来生成二值化图像。但是:如果输入图像中存在变化的因素,包括旋转、缩放、视角变化等,模板匹配很容易就会失效。除非:输入图像的旋转、缩放、视角变化在恒定的情况下,模板匹配也可以完美发挥作用。
你可能需要的文章:
- OpenCV笔记:cv2.matchTemplate()、cv2.minMaxLoc() 、cv2.rectangle() 方法介绍
- 关于:Python基础,爬虫,机器学习,常见异常和面试【篇】(专题汇总)
正文
OpenCV 为我们提供了函数: cv2.matchTemplate() 用于实现模板匹配,并使用 cv2.minMaxLoc() 计算匹配结果。
至于模板的匹配方法,这里不做详细介绍,需要的小伙伴可以查看:【导读】- 你可能需要的文章。
一、单模板匹配
1.1 图片准备
之前的教程里,我一直匹配“脸部”这种特征明显的图形,所以本讲换一个思路,匹配更容易混淆的衣服部分。玩个游戏吧,大家可以看看下面的图片取自哪里,看看是你快,还是机器学习快。
- 底图 image(博客首页的图),模板图片 templ 如下:
注意:模板图片要从模板图片中截出来使用,如果二者分辨率差距太大,很容易匹配失败。
1.2 代码展示
# _*_coding:utf-8_*_
# 作者: Java Punk
# 时间: 2022-10-09 14:49:45import cv2 as cv2# 单个模板匹配
def one_match(image, templ):img = cv2.imread(image)template = cv2.imread(templ)h, w = template.shape[:2]# 匹配模板res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)# 计算矩形左边top_left = max_locbottom_right = (top_left[0] + w, top_left[1] + h)# 画矩形cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 5)# 展示结果cv2.imshow('img_rgb', img)cv2.waitKey(0)passif __name__ == '__main__':print("———————————————————— start ————————————————————\n")# 图片路径自己设置,下面是我本地的路径,记得替换!!!one_match('../img/test/guimie_03.jpg', '../img/test/guimie_04.jpg')print("———————————————————— end ————————————————————\n")
1.3 效果展示
完美匹配到了,我的模板就是从这里接出来的。
二、多模板匹配
上面的单模板匹配使用了函数 cv2.minMaxLoc() 输出结果,特点是:只会输出一个匹配系数最大值,无法给出所有匹配区域的位置信息。但是,有些情况下,要搜索的模板图像很有可能在输入图像内出现了多次,这时就需要找出多个匹配结果。
多模板匹配引入了“匹配系数” - threshold,利用数学计算函数 numpy 删选出所有大于 threshold 的图形。
2.1 图片准备
2.2 代码展示
# _*_coding:utf-8_*_
# 作者: Java Punk
# 时间: 2022-10-09 14:49:45import cv2 as cv2
import numpy as np# 多个模板匹配
def more_match(image, templ):img = cv2.imread(image)img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)template = cv2.imread(templ, 0)h, w = template.shape[:2]res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)# 取匹配程度大于%90的坐标threshold = 0.9# np.where返回的坐标值(x,y)是(h,w),注意h,w的顺序loc = np.where(res >= threshold)for pt in zip(*loc[::-1]):bottom_right = (pt[0] + w, pt[1] + h)cv2.rectangle(img, pt, bottom_right, (255, 0, 0), 1)print(pt, bottom_right)cv2.imshow('img_rgb', img)cv2.waitKey(0)passif __name__ == '__main__':print("———————————————————— start ————————————————————\n")# 图片路径自己设置,下面是我本地的路径,记得替换!!!more_match('../img/test/zhipai_03.jpg', '../img/test/zhipai_04.jpg')print("———————————————————— end ————————————————————\n")
2.3 效果展示
要知道,即使是从原图上截取的图片,在做视觉匹配的时候有没有100%匹配的说法,只能是无限接近于100%。代码中 threshold = 0.9,即:90%以上匹配,尝试将匹配系数慢慢增大,看看会发生什么?
注:为了让每个菱形有区别,我特意倾斜了一定角度拍摄了纸牌的照片,多少能展示出一点效果。
当 threshold = 0.99 的时候,结果只有一个(的确就是我取的截图),即:输出最匹配的结果,在原理上与 函数 cv2.minMaxLoc() 有异曲同工之妙。