OpenCV人数统计项目重复计数问题求助:目标唯一ID分配方案
基于OpenCV的人数统计重复计数问题解决方案
问题说明
当前基于OpenCV的人数统计项目中,当目标的cx坐标处于line_value±offset区间时,现有计数逻辑会对同一目标重复统计。需要通过给每个目标分配唯一ID,确保同一目标在该区间内仅被计数一次。
核心解决思路
解决重复计数的关键是跟踪每个目标的唯一身份,记录已完成计数的目标状态,避免重复触发计数逻辑:
- 使用字典存储跟踪的目标,键为目标唯一ID,值包含目标的中心坐标、是否已计数等状态
- 对每帧检测到的轮廓,通过计算与已有跟踪目标的距离,匹配到对应的目标(距离阈值可根据实际场景调整)
- 仅当目标首次进入
line_value±offset区间且未被计数时,才执行计数操作,并标记该目标为已计数
修改后的完整代码
import cv2 import numpy as np video = cv2.VideoCapture(r"C:\Users\korha\OneDrive\Belgeler\Human Detection 1.0\videos\cut1.mp4") fgbg = cv2.bgsegm.createBackgroundSubtractorMOG() offset = 12 line_value = 230 kernel = np.ones((5,5),np.uint8) counter = 0 count_left = 0 count_right = 0 # 存储跟踪的目标:key是目标ID,value是{'cx': 中心x坐标, 'cy': 中心y坐标, 'counted': 是否已计数} tracked_objects = {} next_object_id = 0 # 目标匹配的距离阈值(可根据实际场景调整) distance_threshold = 50 def counter_method(objects): global counter, count_left, count_right for obj_id, data in objects.items(): cx = data['cx'] # 检查是否在计数区间内且未被计数 if (line_value - offset) < cx < (line_value + offset) and not data['counted']: # 获取目标之前的位置判断方向 prev_cx = tracked_objects[obj_id]['prev_cx'] if 'prev_cx' in tracked_objects[obj_id] else cx if cx > prev_cx: count_right += 1 counter += 1 else: count_left += 1 counter += 1 # 标记为已计数 tracked_objects[obj_id]['counted'] = True def line_method(frame): cv2.putText(frame, str(count_right), (205,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2) cv2.putText(frame, str(count_left), (190,60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2) cv2.putText(frame, 'Count right:', (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2) cv2.putText(frame, 'Count left:', (10,60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0), 2) def rect_method(frame, contours): global tracked_objects, next_object_id, distance_threshold current_objects = {} if len(contours) != 0: for contour in contours: if cv2.contourArea(contour) > 50000: x,y,w,h = cv2.boundingRect(contour) cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 3) cx = x + w/2 cy = y + h/2 cv2.circle(frame, (int(cx), int(cy)), 1, (0,0,255), 2) # 尝试匹配已有跟踪目标 matched_id = None for obj_id, data in tracked_objects.items(): # 计算当前中心与已有目标中心的欧氏距离 dist = np.sqrt((cx - data['cx'])**2 + (cy - data['cy'])**2) if dist < distance_threshold: matched_id = obj_id break if matched_id is not None: # 更新已跟踪目标的位置,保留前一次位置用于方向判断 tracked_objects[matched_id]['prev_cx'] = tracked_objects[matched_id]['cx'] tracked_objects[matched_id]['cx'] = cx tracked_objects[matched_id]['cy'] = cy current_objects[matched_id] = tracked_objects[matched_id] else: # 新增目标 tracked_objects[next_object_id] = { 'cx': cx, 'cy': cy, 'counted': False } current_objects[next_object_id] = tracked_objects[next_object_id] next_object_id += 1 # 移除不再出现的目标(可选,避免内存占用) tracked_objects = {k:v for k,v in tracked_objects.items() if k in current_objects} return current_objects def main(): while True: ret, frame = video.read() if ret is True: fgmask = fgbg.apply(frame) fgmask = cv2.erode(fgmask, kernel=kernel, iterations=1) fgmask = cv2.dilate(fgmask, kernel=kernel, iterations=1) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel) contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) start_point = (line_value,50) end_point = (line_value,800) cv2.line(frame, start_point, end_point, (0,0,255), 2) # 获取当前帧的跟踪目标 current_objects = rect_method(frame, contours) # 执行计数逻辑 counter_method(current_objects) # 绘制计数文本 line_method(frame) cv2.imshow('frame', frame) # 按q键退出,原代码waitKey(0)会暂停每帧,改为1按正常速度播放 if cv2.waitKey(1) & 0xFF == ord('q'): break else: break video.release() cv2.destroyAllWindows() main()
代码说明
- 目标跟踪模块:
rect_method中通过计算轮廓中心与已有目标的距离实现目标匹配,为新目标分配唯一ID,更新已有目标的位置 - 计数逻辑优化:
counter_method仅对首次进入计数区间且未被标记的目标计数,标记后不再重复统计 - 方向判断:通过目标的前一次位置与当前位置对比,判断移动方向(左/右)
内容的提问来源于stack exchange,提问作者user18540930
相关产品推荐
相关产品推荐

