CV入门:模板匹配中如何消除重复的位置检测点?
解决模板匹配中重复位置检测点的问题
嘿,看来你已经在模板匹配的路上走了一段了!要消除重复的检测点,**非极大值抑制(Non-Maximum Suppression, NMS)**是最常用的方案,它能帮你保留最匹配的结果,去掉那些重叠度太高的重复检测框。
我结合你的代码,给你完整的解决方案:
第一步:补全模板匹配的基础流程
先把模板匹配的核心步骤补全,拿到所有可能的匹配位置和对应得分:
import numpy as np import cv2 # 读取主图像和模板(直接把模板读成灰度图,省一步转换) inputImage = cv2.imread('Trolley_problem.jpg') inputImageGray = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY) humanTemplate = cv2.imread('h1.jpg', 0) templateH, templateW = humanTemplate.shape[:2] # 执行归一化模板匹配,得到匹配得分矩阵 result = cv2.matchTemplate(inputImageGray, humanTemplate, cv2.TM_CCOEFF_NORMED)
第二步:筛选候选检测框
设定一个匹配得分阈值(比如0.8,可根据实际效果调整),把得分高于阈值的位置都提取出来作为候选:
threshold = 0.8 # 提取所有得分达标位置的坐标,转换成(x,y)格式并带上对应得分 locations = np.where(result >= threshold) candidates = [] for (x, y) in zip(*locations[::-1]): # 每个候选框存储为(x1, y1, x2, y2, 匹配得分) candidates.append((x, y, x + templateW, y + templateH, result[y, x]))
第三步:实现非极大值抑制去重
NMS的核心逻辑是:先按匹配得分从高到低排序,保留得分最高的框,再去掉和它重叠度(IoU)超过阈值的重复框。咱们自己写一个简单的NMS函数:
def non_max_suppression(boxes, overlap_threshold): if len(boxes) == 0: return [] # 把候选框转换成numpy数组,方便计算 boxes = np.array(boxes) x1, y1, x2, y2, scores = boxes[:,0], boxes[:,1], boxes[:,2], boxes[:,3], boxes[:,4] # 计算每个框的面积,按得分降序排序 areas = (x2 - x1 + 1) * (y2 - y1 + 1) order = scores.argsort()[::-1] keep = [] while order.size > 0: # 保留当前得分最高的框 i = order[0] keep.append(boxes[i]) # 计算当前框与剩余框的重叠区域坐标 xx1 = np.maximum(x1[i], x1[order[1:]]) yy1 = np.maximum(y1[i], y1[order[1:]]) xx2 = np.minimum(x2[i], x2[order[1:]]) yy2 = np.minimum(y2[i], y2[order[1:]]) # 计算重叠区域的宽高和IoU(交并比) w = np.maximum(0, xx2 - xx1 + 1) h = np.maximum(0, yy2 - yy1 + 1) overlap = (w * h) / areas[order[1:]] # 只保留重叠度低于阈值的框 indices = np.where(overlap <= overlap_threshold)[0] order = order[indices + 1] return keep
第四步:应用NMS并绘制最终结果
把候选框传入NMS函数得到去重后的结果,再绘制到原图上:
# 应用非极大值抑制,重叠阈值设为0.3(可根据对象间距调整) filtered_boxes = non_max_suppression(candidates, overlap_threshold=0.3) # 绘制去重后的检测框和得分 for box in filtered_boxes: x1, y1, x2, y2, score = box cv2.rectangle(inputImage, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(inputImage, f"{score:.2f}", (int(x1), int(y1)-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) # 展示结果 cv2.imshow("Detected Objects", inputImage) cv2.waitKey(0) cv2.destroyAllWindows()
关键参数说明
threshold:匹配得分阈值,值越高筛选越严格,只有得分达标才会被视为候选。overlap_threshold:NMS重叠阈值,IoU超过这个值的框会被判定为重复,一般在0.2-0.5之间调整。
这样处理后,就不会再出现一堆重复的检测点啦,只会保留最匹配、最具代表性的检测框。
内容的提问来源于stack exchange,提问作者Rao208
相关产品推荐
相关产品推荐

