OpenCV-Python中碰撞矩形合并问题修复求助
问题描述
我正在修复一个bug:视频中两个矩形框碰撞后,在碰撞持续的后续帧中会合并为一个大矩形,而非保持原本的两个独立矩形。
碰撞前效果:
碰撞后效果:
我希望即使在物体碰撞时,也能保留两个独立的矩形框。
核心循环代码片段:
while True: ret, frame = vid.read() if frame is None: break # TRESH_OTSU 在处理极暗物体时存在问题 bright_frame = cv2.addWeighted( frame, 4.3, np.zeros(frame.shape, frame.dtype), 0, 20 ) # 创建掩码以排除跟踪时的黑色背景 gray = cv2.cvtColor(bright_frame, cv2.COLOR_BGR2GRAY) _, mask = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 获取运动物体 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) detections = [] for obj in contours: area = cv2.contourArea(obj) if area > 50: # 过滤噪声 perimeter = cv2.arcLength(obj, True) approx = cv2.approxPolyDP(obj, 0.02 * perimeter, True) object_type = "rectangle" if len(approx) == 4 else "circle" x, y, w, h = cv2.boundingRect(obj) detections.append( DetectedObject( x, y, w, h, get_obj_color(frame, x, y, w, h), object_type ) ) rects = tracker.update(detections) for rect in rects: x, y, w, h, id, _, _, time = rect cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 255), 5) # cv2.putText( # frame, str(id), (x, y - 15), cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255) # ) print(rect) cv2.imshow("frame", frame) key = cv2.waitKey(10) # 按下ESC键终止循环 if key == 27: break
问题根源与修复方案
核心原因
当前代码使用cv2.RETR_EXTERNAL模式提取轮廓,该模式只保留最外层轮廓。当两个矩形碰撞重叠时,它们的像素区域会被合并成一个连通域,导致findContours将其识别为单个轮廓,后续检测和跟踪自然只会输出一个大矩形。
修复步骤
1. 调整轮廓提取模式
将cv2.RETR_EXTERNAL替换为cv2.RETR_CCOMP(提取所有层次轮廓),并通过轮廓层级信息筛选独立物体:
# 替换原轮廓提取代码 contours, hierarchy = cv2.findContours(mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) detections = [] for i, obj in enumerate(contours): area = cv2.contourArea(obj) if area > 50: # 只处理没有父轮廓的独立物体(层级数组第3位为-1表示无父轮廓) if hierarchy[0][i][3] == -1: perimeter = cv2.arcLength(obj, True) approx = cv2.approxPolyDP(obj, 0.02 * perimeter, True) object_type = "rectangle" if len(approx) == 4 else "circle" x, y, w, h = cv2.boundingRect(obj) detections.append( DetectedObject( x, y, w, h, get_obj_color(frame, x, y, w, h), object_type ) )
2. 基于颜色分割优化检测(可选)
如果两个物体颜色差异明显,可以用颜色掩码替代灰度阈值,从根源避免重叠时的轮廓合并:
# 替换原灰度阈值与轮廓提取步骤 hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 根据实际物体颜色调整范围(示例为红、蓝两色) color_ranges = [ ((0, 100, 100), (10, 255, 255)), ((110, 100, 100), (130, 255, 255)) ] detections = [] for lower, upper in color_ranges: mask = cv2.inRange(hsv_frame, lower, upper) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for obj in contours: area = cv2.contourArea(obj) if area > 50: perimeter = cv2.arcLength(obj, True) approx = cv2.approxPolyDP(obj, 0.02 * perimeter, True) object_type = "rectangle" if len(approx) == 4 else "circle" x, y, w, h = cv2.boundingRect(obj) detections.append(DetectedObject(x, y, w, h, get_obj_color(frame, x, y, w, h), object_type))
3. 跟踪器适配优化
如果使用的跟踪器(如Sort、DeepSORT)依赖稳定的检测特征,可以给DetectedObject增加颜色、长宽比等特征,让跟踪器通过多维度匹配关联帧间物体,避免碰撞时ID混淆。
内容的提问来源于stack exchange,提问作者banan
相关产品推荐
相关产品推荐

