基于Python和OpenCV的人员计数系统跟踪问题求助
问题:楼宇人员计数系统人员跟踪失效
我用Python和OpenCV开发了一套楼宇人员计数系统,但目前人员跟踪功能存在严重问题:房间内实际有3人,系统却仅计数1人。我已经尝试调整maxDisappear、maxDistance以及confidence参数,但没能彻底解决问题。
相关代码
from mylib.centroidtracker import CentroidTracker from mylib.trackableobject import TrackableObject from imutils.video import VideoStream from imutils.video import FPS #from mylib.mailer import Mailer from mylib import config, thread import time, schedule, csv import numpy as np import argparse, imutils import time, dlib, cv2, datetime from itertools import zip_longest #from pykalman import KalmanFilter #python main.py --prototxt mobilenet_ssd/MobileNetSSD_deploy.prototxt --model mobilenet_ssd/MobileNetSSD_deploy.caffemodel --input videos/video.mp4 #kf = KalmanFilter(initial_state_mean=[0, 0], n_dim_obs=2) t0 = time.time() def is_above_boundary_line(x, y, slope, intercept): return y < (slope * x + intercept) def run(): ap = argparse.ArgumentParser() ap.add_argument("-p", "--prototxt", required=False, help="path to Caffe 'deploy' prototxt file") ap.add_argument("-m", "--model", required=True, help="path to Caffe pre-trained model") ap.add_argument("-i", "--input", type=str, help="path to optional input video file") ap.add_argument("-o", "--output", type=str, help="path to optional output video file") ap.add_argument("-c", "--confidence", type=float, default=1, help="minimum probability to filter weak detections") ap.add_argument("-s", "--skip-frames", type=int, default=4, help="# of skip frames between detections") args = vars(ap.parse_args()) CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"]) if not args.get("input", False): print("[INFO] Starting the live stream..") vs = VideoStream(config.url).start() time.sleep(2.0) else: print("[INFO] Starting the video..") vs = cv2.VideoCapture(args["input"]) writer = None W = None H = None ct = CentroidTracker(maxDisappeared=300, maxDistance=200) trackers = [] trackableObjects = {} totalFrames = 0 totalDown = 0 totalUp = 0 x = [] empty = [] empty1 = [] fps = FPS().start() if config.Thread: vs = thread.ThreadingClass(config.url) while True: frame = vs.read() frame = frame[1] if args.get("input", False) else frame if frame is None: break frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) frame = imutils.resize(frame, width=500) rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) if W is None or H is None: (H, W) = frame.shape[:2] x1, y1 = 0, int(H * 0.9) x2, y2 = int(W * 0.85), 0 boundary_line_slope = (y2 - y1) / (x2 - x1) boundary_line_intercept = y1 - boundary_line_slope * x1 if args["output"] is not None and writer is None: fourcc = cv2.VideoWriter_fourcc(*"MJPG") writer = cv2.VideoWriter(args["output"], fourcc, 30, (W, H), True) status = "Waiting" rects = [] if totalFrames % args["skip_frames"] == 0: status = "Detecting" trackers = [] blob = cv2.dnn.blobFromImage(frame, 0.007843, (W, H), 127.5) net.setInput(blob) detections = net.forward() for i in np.arange(0, detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.2: idx = int(detections[0, 0, i, 1]) if CLASSES[idx] != "person": continue box = detections[0, 0, i, 3:7] * np.array([W, H, W, H]) (startX, startY, endX, endY) = box.astype("int") tracker = dlib.correlation_tracker() rect = dlib.rectangle(startX, startY, endX, endY) tracker.start_track(rgb, rect) trackers.append(tracker) else: for tracker in trackers: status = "Tracking" tracker.update(rgb) pos = tracker.get_position() startX = int(pos.left()) startY = int(pos.top()) endX = int(pos.right()) endY = int(pos.bottom()) rects.append((startX, startY, endX, endY)) cv2.line(frame, (0, int(H * 0.9)), (int(W * 0.85), 0), (255, 0, 0), 3) objects = ct.update(rects) for (objectID, centroid) in objects.items(): to = trackableObjects.get(objectID, None) if to is None: to = TrackableObject(objectID, centroid) else: #y = [c[1] for c in to.centroids] #direction = centroid[1] - np.mean(y) to.centroids.append(centroid) if not to.counted: if len(to.centroids) > 1: prev_position = to.centroids[-2] if is_above_boundary_line(prev_position[0], prev_position[1], boundary_line_slope, boundary_line_intercept) and not is_above_boundary_line(centroid[0], centroid[1], boundary_line_slope, boundary_line_intercept): totalDown += 1 empty1.append(totalDown) to.counted = True elif not is_above_boundary_line(prev_position[0], prev_position[1], boundary_line_slope, boundary_line_intercept) and is_above_boundary_line(centroid[0], centroid[1], boundary_line_slope, boundary_line_intercept): totalUp += 1 empty.append(totalUp) to.counted = True trackableObjects[objectID] = to text = "ID {}".format(objectID) cv2.putText(frame, text, (centroid[0] - 10, centroid[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.circle(frame, (centroid[0], centroid[1]), 4, (0, 255, 0), -1) info = [ ("Exit", totalUp), ("Enter", totalDown), # ("Status", status), ] for (i, (k, v)) in enumerate(info): text = "{}: {}".format(k, v) cv2.putText(frame, text, (10, H - ((i * 20) + 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) if writer is not None: writer.write(frame) frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF if key == ord("q"): break totalFrames += 1 fps.update() fps.stop() print("[INFO] elapsed time: {:.2f}".format(fps.elapsed())) print("[INFO] approx. FPS: {:.2f}".format(fps.fps())) if writer is not None: writer.release() if not args.get("input", False): vs.stop() else: vs.release() cv2.destroyAllWindows() d = [datetime.datetime.now()] dts = [ts.strftime("%A %d %B %Y %I:%M:%S%p") for ts in d] export_data = zip_longest(*[dts, empty, empty1], fillvalue='') with open('Log.csv', 'w', newline='') as file: writer = csv.writer(file) writer.writerow(("End Time", "In", "Out")) writer.writerows(export_data) run()
修复建议
- 统一检测置信度逻辑:代码中命令行参数
--confidence默认值设为1,但检测时却用confidence > 0.2判断,导致参数完全失效。将检测条件改为confidence > args["confidence"],并把默认值调整到0.4左右,避免漏检人员。 - 优化跟踪频率:当前每4帧才重新检测一次,期间仅靠dlib跟踪器,人员快速移动或遮挡时容易丢失目标。降低
skip-frames值到2,增加检测频率;或者在跟踪阶段加入校验,若跟踪框与上一帧偏差超过阈值,触发临时检测。 - 改进质心跟踪匹配规则:如果
CentroidTracker仅用欧氏距离匹配质心,人员密集时会出现ID混淆。可以结合检测框的IOU(交并比)进行匹配,同时根据场景调整maxDistance——画面中人员间距小时,该值不宜过大,否则会把不同人员匹配为同一ID。 - 调整计数触发条件:当前需要积累至少2个质心才判断越线,人员快速通过时可能错过计数。可以增加首次检测时的位置判断,或者放宽计数触发的条件。
- 简化颜色空间转换:代码中多次转换颜色空间(RGB2BGR→BGR2RGB),可能导致画面异常影响检测。简化转换步骤,确保输入到检测网络和跟踪器的画面格式正确。
内容的提问来源于stack exchange,提问作者Zer_W
相关产品推荐
相关产品推荐

