OpenCV模板匹配中如何返回匹配成功的模板可识别标识符
我们有如下函数,它的作用是在工作图像中找到匹配的模板。现在的需求是,如何得到一个可用于后续判断的输出结果(比如,如果匹配到的是绿色模板,就执行对应的操作)。
import cv2 red_template = cv2.imread('resources/temptest/red_template.png') yellow_template = cv2.imread('resources/temptest/yellow_template.png') blue_template = cv2.imread('resources/temptest/blue_template.png') green_template = cv2.imread('resources/temptest/green_template.png') work_image = cv2.imread('resources/temptest/work_image.png') all_templates = [red_template, yellow_template, blue_template, green_template] for template in all_templates: result = cv2.matchTemplate(work_image,template, method=cv2.TM_CCORR_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) threshold = 0.945 if max_val >= threshold: print('found it') break else: print('not found') continue
涉及的文件:
red template、yellow template、blue template、green template、work image
函数执行结果:
not found not found not found found it
目前代码运行正常,当循环到匹配的模板时会输出“found it”,但我的问题是:如何输出匹配成功的模板的标识符?我尝试过添加return result或return template,但这些都没法得到一个可用于比较的对象,还经常遇到ValueError: operands could not be broadcast together with shapes .的错误。
其实你不用直接返回模板本身(毕竟模板是NumPy数组对象,直接比较很容易因为形状或元素问题报错),只要把模板和对应的标识符(比如颜色名称)绑定在一起,就能轻松追踪到匹配的是哪个模板了。下面给你两个实用的解决方法:
方法一:用元组列表绑定模板与名称
把每个模板和它的名称打包成元组,循环时同时获取模板和名称,匹配成功后直接记录名称即可:
import cv2 # 将模板和对应名称绑定成元组,存入列表 template_list = [ (cv2.imread('resources/temptest/red_template.png'), "红色"), (cv2.imread('resources/temptest/yellow_template.png'), "黄色"), (cv2.imread('resources/temptest/blue_template.png'), "蓝色"), (cv2.imread('resources/temptest/green_template.png'), "绿色") ] work_image = cv2.imread('resources/temptest/work_image.png') threshold = 0.945 matched_name = None for template, name in template_list: result = cv2.matchTemplate(work_image, template, method=cv2.TM_CCORR_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) if max_val >= threshold: print(f'找到匹配模板:{name}') matched_name = name break else: print(f'未匹配到{name}模板') # 后续可根据匹配到的名称执行对应操作 if matched_name == "绿色": print("执行绿色模板对应的专属操作") elif matched_name == "红色": print("执行红色模板对应的专属操作")
方法二:用字典存储模板与名称
如果后续需要单独调用某个模板,用字典会更灵活,键为名称,值为模板对象:
import cv2 # 字典键为模板名称,值为模板对象 template_dict = { "红色": cv2.imread('resources/temptest/red_template.png'), "黄色": cv2.imread('resources/temptest/yellow_template.png'), "蓝色": cv2.imread('resources/temptest/blue_template.png'), "绿色": cv2.imread('resources/temptest/green_template.png') } work_image = cv2.imread('resources/temptest/work_image.png') threshold = 0.945 matched_name = None for name, template in template_dict.items(): result = cv2.matchTemplate(work_image, template, method=cv2.TM_CCORR_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) if max_val >= threshold: print(f'找到匹配模板:{name}') matched_name = name break else: print(f'未匹配到{name}模板') # 后续操作示例 if matched_name: print(f'接下来将针对{matched_name}模板执行后续逻辑')
为什么之前的方法会报错?
你之前尝试返回template(也就是图像的NumPy数组),当后续想比较两个数组时,Python会逐元素对比,得到一个布尔数组,而不是你预期的“是否是同一个模板”的判断;如果两个数组形状不同,还会直接触发广播错误。而用字符串作为标识符,不仅比较简单直观,也完全不会有形状不兼容的问题。
备注:内容来源于stack exchange,提问作者APizzy

