使用Python的cv2库检测不同尺度模板的多个实例遇阻
多尺度模板匹配的多实例检测问题
我正在用OpenCV的cv2库编写Python模板匹配脚本,已经实现不同尺度下单个模板实例的检测,但无法识别不同尺度下的多个模板实例。我尝试找到第一个匹配实例后遮挡它,再重新扫描,但第二次扫描无法正确匹配到模板。
相关参考图:
- 模板图
- 待检测原图
- 标注检测框后的图
- 目标查找图
以下是我运行的代码:
import numpy as np import imutils import glob import cv2 from imutils.object_detection import non_max_suppression imagen_a_detectar = r"C:\Users\OMEN\OneDrive\Documentos\TEC\PROYECTO RESIDEO\REPO\SCRUMsinCUM\software\Deteccion Iconos\flecha50.jpg" imagen_a_comparar = r"C:\Users\OMEN\OneDrive\Documentos\TEC\PROYECTO RESIDEO\REPO\SCRUMsinCUM\software\Deteccion Iconos\HomeAuto3.png" template = cv2.imread(imagen_a_detectar) template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) template = cv2.Canny(template, 50, 200) (tH, tW) = template.shape[:2] for imagePath in glob.glob(imagen_a_comparar): image = cv2.imread(imagePath) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) found = None threshold = 0.9 for scale in np.linspace(0.2, 1.0, 20)[::-1]: scalem = scale 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) result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) if found is None or max_val > found[0]: found = (max_val, max_loc, r) (_, max_loc, r) = found (startX, startY) = (int(max_loc[0] * r), int(max_loc[1] * r)) (endX, endY) = (int((max_loc[0] + tW) * r), int((max_loc[1] + tH) * r)) m1 = cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), -1) gray2 = cv2.cvtColor(m1, cv2.COLOR_BGR2GRAY) resized2 = imutils.resize(gray2, width = int(gray.shape[1] * scalem)) r2 = gray.shape[1] / float(resized.shape[1]) edged2 = cv2.Canny(resized2, 50, 200) result2 = cv2.matchTemplate(edged2, template, cv2.TM_CCOEFF_NORMED) min_val2, max_val2, min_loc2, max_loc2 = cv2.minMaxLoc(result2) found2 = (max_val2, max_loc2, r2) (_, max_loc2, r2) = found2 (startX2, startY2) = (int(max_loc2[0] * r2), int(max_loc2[1] * r2)) (endX2, endY2) = (int((max_loc2[0] + tW) * r2), int((max_loc2[1] + tH) * r2)) m2 = cv2.rectangle(m1, (startX2, startY2), (endX2, endY2), (0, 0, 255), -1) cv2.imshow("Image", m2) cv2.waitKey(0) print(str(endX) + ' ' +str(endY)+ ' ' +str(r))
解决思路与修正代码
你的问题核心在于仅用单一尺度重新检测,且遮挡重扫的逻辑存在漏洞。正确方案是在所有尺度下收集所有符合阈值的匹配结果,再用非极大值抑制(NMS)去除重叠/重复框,无需逐个遮挡扫描。
修正后的代码:
import numpy as np import imutils import cv2 from imutils.object_detection import non_max_suppression # 替换为你的文件路径 template_path = r"C:\Users\OMEN\OneDrive\Documentos\TEC\PROYECTO RESIDEO\REPO\SCRUMsinCUM\software\Deteccion Iconos\flecha50.jpg" image_path = r"C:\Users\OMEN\OneDrive\Documentos\TEC\PROYECTO RESIDEO\REPO\SCRUMsinCUM\software\Deteccion Iconos\HomeAuto3.png" # 预处理模板 template = cv2.imread(template_path) template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) template = cv2.Canny(template, 50, 200) (tH, tW) = template.shape[:2] # 读取待检测图像 image = cv2.imread(image_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) found_boxes = [] threshold = 0.7 # 可根据匹配效果调整阈值 # 遍历所有尺度,收集所有符合阈值的匹配框 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) result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF_NORMED) # 提取所有匹配度超过阈值的位置 loc = np.where(result >= threshold) for (x, y) in zip(loc[1], loc[0]): # 转换为原图中的坐标 startX = int(x * r) startY = int(y * r) endX = int((x + tW) * r) endY = int((y + tH) * r) found_boxes.append((startX, startY, endX, endY)) # 使用非极大值抑制去除重叠的重复检测框 boxes = np.array(found_boxes) if len(boxes) > 0: boxes = non_max_suppression(boxes) # 绘制所有有效检测框 for (startX, startY, endX, endY) in boxes: cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2) # 显示检测结果 cv2.imshow("检测结果", image) cv2.waitKey(0) cv2.destroyAllWindows()
关键改进点:
- 遍历所有尺度时,收集所有符合阈值的匹配框,而非仅保留最佳匹配
- 用
non_max_suppression过滤重叠框,避免同一目标被重复识别 - 移除低效的遮挡重扫逻辑,改用批量检测+NMS的可靠方案
内容的提问来源于stack exchange,提问作者Jorge Garcia
相关产品推荐
相关产品推荐

