ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv5+SORT目标跟踪实战:从检测到ID轨迹全流程解析

YOLOv5+SORT目标跟踪实战:从检测到ID轨迹全流程解析 简介本资源是一个面向视频流的多目标检测与跟踪一体化项目适用于计算机视觉方向的本科生课程设计、期末大作业及初学者算法实践。项目基于Python实现融合主流目标检测如YOLO或SSD与目标跟踪如SORT或DeepSORT算法支持端到端视频分析开箱即用且已通过导师验收获97分高分。压缩包共655个文件包含282个核心Python源码含模型训练、推理、可视化模块、248个编译后pyc文件、27个Protocol Buffer定义.proto、21个配置文件.config、18个Markdown说明文档含环境配置、运行指南、结果分析以及图像、模型权重.pb/.pbtxt、检查点和Jupyter Notebook等辅助文件整体体积65.76MB。目前已有316人学习下载资源结构完整、注释清晰、模块解耦合理附带全部标注数据与预置参数省去数据准备与环境调试环节特别适合快速理解视频目标检测全流程并开展二次开发。1. 把视频流里的车、人、狗全框出来还连上ID一个97分课程设计的实战闭环你有没有试过——用YOLOv5跑完一帧视频发现同一辆车在第3帧和第5帧被标成两个不同ID或者目标刚进画面就被漏检等它跑到中间才突然“闪现”这不是模型不行是检测和跟踪没真正咬合。这个项目就是冲着解决这个问题来的它不是简单把YOLO检测结果喂给SORT或DeepSORT而是从数据加载、帧间对齐、特征缓存、ID重识别到轨迹平滑整条链路用纯Python重写不调用任何黑匣子封装库比如deep_sort_realtime那种封装层所有核心逻辑——IOU匹配阈值怎么设、卡尔曼滤波Q/R矩阵怎么初始化、外观特征提取用ResNet18还是MobileNetV2、轨迹存活周期如何动态裁剪——全摊开在.py文件里。它跑的是真实交通监控视频含遮挡、低光照、小目标不是COCO图片集它用的是自己标注的12段带ID标注的视频片段共4786帧不是公开数据集的二手标注它通过了导师逐行代码审查实测视频回放验证最终得分97。适合两类人一是急需交课程设计/期末大作业的同学解压即跑不用改路径、不用装额外依赖、连CUDA版本都锁死在11.3二是想搞懂“检测跟踪”到底怎么协同的视觉初学者——你看得见每个ID怎么诞生、怎么延续、怎么消亡而不是对着tracker.update(detections)发呆。2. 检测与跟踪双模块解耦设计为什么不用Detectron2或ByteTrack2.1 检测模块YOLOv5s轻量版 动态置信度阈值策略项目没用YOLOv8或YOLOv11后者根本不存在是热搜词误传也没用YOLOv26纯属网络梗而是基于官方YOLOv5sv6.1做深度定制。关键改动有三处输入尺寸动态适配不固定为640×640而是根据视频原始分辨率按比例缩放保持长边≤1280避免小目标被过度压缩NMS阈值分场景调节对交通场景车辆密集设为0.45对行人场景ID易混淆设为0.3参数写在config/detector_config.yaml里后处理增加面积过滤剔除面积300像素的检测框防噪点该阈值可调代码在detector/yolo_detector.py第127行# yolo_detector.py 第127行 if (box[2] - box[0]) * (box[3] - box[1]) self.min_area_threshold: continue提示min_area_threshold默认300但如果你跑的是无人机俯拍农田视频目标更小必须手动调低到80–150否则大量鸡鸭会被直接过滤。2.2 跟踪模块SORT变体 外观特征增强项目没直接套用SORT太容易ID跳变也没用DeepSORT依赖预训练ReID模型泛化差而是实现了一个“SORT”运动预测层保留原SORT的卡尔曼滤波状态向量为[x,y,w,h,vx,vy]但过程噪声协方差Q按目标速度动态调整——静止目标Q小高速移动目标Q放大1.8倍外观匹配层用轻量级MobileNetV2提取检测框内ROI特征非端到端训练用ImageNet预训练权重余弦相似度0.6才触发外观关联ID管理策略每个ID绑定一个“活跃度计数器”连续3帧未匹配则进入待回收队列再经2帧确认无重叠才彻底销毁。该设计让ID稳定率提升27%对比纯SORT尤其在车辆并道、行人穿插场景下效果明显。所有逻辑集中在tracker/sort_plus.py没有调用sort或deep_sortpip包。2.3 数据流闭环从VideoCapture到轨迹CSV整个pipeline是同步单线程非多进程确保帧序严格一致video_reader.py读取视频按cv2.CAP_PROP_POS_FRAMES逐帧解码每帧送入yolo_detector.py得到[x1,y1,x2,y2,conf,cls_id]格式检测结果检测结果上一帧跟踪状态送入sort_plus.py输出带track_id的当前帧轨迹实时渲染OpenCVcv2.putTextcv2.rectangle并写入output/track_vis.mp4同时将frame_id,track_id,x1,y1,x2,y2,cls_id,conf写入output/track_result.csv供后续分析。注意track_result.csv是逗号分隔但第1行是headerframe,track_id,x1,y1,x2,y2,class,conf不是空行。很多同学用pandas读时报错就是因为忽略了header。2.4 配置中心化所有可调参数集中管控项目把所有影响行为的参数收拢到config/目录下detector_config.yamlYOLO权重路径、置信度阈值、NMS阈值、最小检测面积tracker_config.yaml卡尔曼滤波Q/R矩阵、外观相似度阈值、ID存活帧数、最大跟踪距离像素video_config.yaml输入视频路径、输出路径、是否保存可视化视频、是否生成CSV。这种设计避免了“改个阈值要翻5个文件”的灾难。例如想调高ID稳定性只需改tracker_config.yaml中# tracker_config.yaml appearance_thresh: 0.65 # 原0.6提高到0.65减少误关联 max_age: 30 # 原25延长ID存活时间3. 环境搭建与运行Windows 10/11 Python 3.8.10 实测可行3.1 依赖安装精确到小版本号项目锁定Python 3.8.10非3.9因为YOLOv5 v6.1官方要求。CUDA版本必须为11.3对应PyTorch 1.10.0cu113显卡驱动≥465.89。依赖列表如下requirements.txt已固化torch1.10.0cu113 torchvision0.11.1cu113 numpy1.21.6 opencv-python4.5.5.64 pyyaml6.0 scipy1.7.3 tqdm4.62.3安装命令必须加--force-reinstall避免旧版本冲突pip install --force-reinstall -r requirements.txt提示如果torch安装失败先卸载所有torch相关包pip uninstall torch torchvision torchaudio再执行上述命令。不要用conda installconda源的torch版本常与本项目不兼容。3.2 数据结构规范视频与标注必须严格对齐项目自带全部数据解压后目录结构为data/ ├── videos/ # 原始MP4视频12段每段30–60秒 ├── labels/ # 对应视频的逐帧TXT标注YOLO格式含track_id └── images/ # 视频关键帧抽帧图用于调试非必需其中labels/下每个TXT文件命名规则为{video_name}_{frame_num:06d}.txt例如traffic_001_000123.txt。每行格式cls_id x_center y_center width height track_id注意track_id是正整数且同一视频内ID连续1,2,3...但不同视频间ID可重复。这是为方便人工校验设计的不影响跟踪逻辑。3.3 运行主脚本三步启动不碰代码项目入口是main.py无需修改任何路径。运行前确认config/video_config.yaml中input_video_path指向data/videos/下某个MP4文件output_dir路径存在且可写如output/GPU可用nvidia-smi可见显卡。执行命令python main.py首次运行会自动下载YOLOv5s权重weights/yolov5s.pt约27MB下载完成后开始处理。典型耗时视频长度分辨率GPU型号耗时45秒1920×1080RTX 30602分18秒60秒1280×720GTX 10605分03秒3.4 输出物说明不只是画框更是可分析的数据运行结束后output/目录生成track_vis.mp4带ID标签的可视化视频红框ID类别如ID:12_cartrack_result.csv结构化轨迹数据共8列可直接导入Excel或pandas分析log.txt逐帧处理日志含检测数量、跟踪ID数、FPS、GPU显存占用debug/子目录若开启debug模式每帧检测框坐标图、特征相似度热力图。提示track_result.csv中x1,y1,x2,y2是绝对坐标非归一化单位为像素可直接用于计算速度、加速度等物理量。4. 避坑指南97分背后踩过的5个血泪坑4.1 现象运行报错ModuleNotFoundError: No module named models.common原因YOLOv5官方仓库结构变更v6.2移除了models/common.py但本项目基于v6.1需确保加载的是原始v6.1的models/目录。常见错误是用户自行git clone yolov5最新版覆盖了项目自带的detector/models/。解决删除项目根目录下的detector/models/从项目压缩包中重新解压detector/models/含common.py、yolo.py等不要用网上下载的YOLOv5源码替换。4.2 现象视频首帧检测正常但从第2帧起所有框消失log.txt显示detections: []原因OpenCV视频读取时cv2.VideoCapture对某些MP4编码如H.265/HEVC支持不佳导致解码失败但不报错返回空帧。解决用ffmpeg转码为H.264ffmpeg -i input.mp4 -c:v libx264 -preset fast -crf 23 -c:a aac output_h264.mp4然后在video_config.yaml中指向output_h264.mp4。4.3 现象ID频繁跳变同一目标ID在1→5→1→3间乱跳尤其在目标短暂遮挡后原因tracker_config.yaml中max_iou_distanceIOU匹配阈值设得过大默认0.7导致遮挡后新检测框与旧轨迹IOU不足触发新ID分配。解决将max_iou_distance从0.7降至0.45并同步调高appearance_thresh至0.68强化外观匹配权重。修改后需重启程序。4.4 现象CPU占用100%GPU显存只用200MBFPS低于5原因main.py中cv2.VideoCapture默认使用CPU解码未启用GPU硬解如NVIDIA NVDEC。解决在video_reader.py第32行附近将cap cv2.VideoCapture(video_path)改为# video_reader.py 第32行 cap cv2.VideoCapture(video_path, cv2.CAP_FFMPEG) # 强制FFmpeg后端 cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_GPU) # 启用GPU加速仅Windows注意此修改仅在Windows NVIDIA显卡 安装了FFmpeg的环境下生效。Linux需额外配置VA-API。4.5 现象track_result.csv中同一帧出现多个相同track_id原因YOLO检测出重叠框NMS未完全抑制导致同一ID被多次分配给不同框。解决在yolo_detector.py的NMS后增加二次去重# yolo_detector.py 第185行NMS后插入 # 去除同一ID在单帧内重复分配 seen_ids set() filtered_dets [] for det in dets_after_nms: if int(det[6]) not in seen_ids: # det[6]是track_id此处为临时ID filtered_dets.append(det) seen_ids.add(int(det[6])) dets_after_nms np.array(filtered_dets)5. 轨迹后处理技巧从原始CSV到可交付分析报告5.1 用Pandas快速统计ID生命周期track_result.csv本质是长表格每行一条轨迹片段。我们关心每个ID持续了多少帧最长存活ID是谁平均ID寿命用以下脚本一键生成# analyze_track.py import pandas as pd df pd.read_csv(output/track_result.csv) # 按track_id分组统计帧数跨度 id_lifespan df.groupby(track_id)[frame].agg([min, max]).reset_index() id_lifespan[duration] id_lifespan[max] - id_lifespan[min] 1 print(ID最长存活帧数:, id_lifespan[duration].max()) print(平均ID寿命帧:, id_lifespan[duration].mean().round(1)) print(ID总数:, len(id_lifespan))输出示例ID最长存活帧数: 1842 平均ID寿命帧: 217.3 ID总数: 42这个数字比单纯数len(df[track_id].unique())更准因为排除了因遮挡短暂中断又恢复的ID它们在CSV中是同一ID但min/max跨度已体现连续性。5.2 计算目标速度像素/帧并过滤异常值速度是轨迹分析核心指标。假设视频帧率为30fps我们用相邻帧坐标差估算# 续上 analyze_track.py df df.sort_values([track_id, frame]) df[dx] df.groupby(track_id)[x1].diff() # x方向位移 df[dy] df.groupby(track_id)[y1].diff() # y方向位移 df[speed_px_per_frame] np.sqrt(df[dx]**2 df[dy]**2) # 过滤抖动位移50px视为异常可能是检测漂移 df df[df[speed_px_per_frame] 50] print(平均移动速度像素/帧:, df[speed_px_per_frame].mean().round(2))血泪经验不做异常值过滤speed_px_per_frame均值会虚高3倍以上。因为YOLO检测框偶尔偏移100像素但实际目标没动。5.3 可视化轨迹热力图用OpenCV绘制不依赖Matplotlib直接用OpenCV在空白画布上累加轨迹点import cv2 import numpy as np # 读取视频获取宽高 cap cv2.VideoCapture(data/videos/traffic_001.mp4) w int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) cap.release() # 创建热力图画布灰度图 heatmap np.zeros((h, w), dtypenp.float32) # 读取CSV对每个点加权 for _, row in df.iterrows(): x int((row[x1] row[x2]) / 2) # 中心x y int((row[y1] row[y2]) / 2) # 中心y if 0 x w and 0 y h: heatmap[y, x] 0.5 # 权重0.5避免过曝 # 归一化并转为伪彩色 heatmap cv2.normalize(heatmap, None, 0, 255, cv2.NORM_MINMAX) heatmap cv2.applyColorMap(heatmap.astype(np.uint8), cv2.COLORMAP_JET) cv2.imwrite(output/trajectory_heatmap.jpg, heatmap)生成的trajectory_heatmap.jpg直观显示高频通行区域如路口左转车道比单纯看视频更易发现规律。5.4 导出指定ID的完整轨迹视频带路径动画有时需要向导师演示某个特定目标如ID7的白色轿车的全程轨迹。用以下脚本提取并叠加动画线# export_single_id.py import cv2 import pandas as pd df_id7 df[df[track_id] 7].sort_values(frame) cap cv2.VideoCapture(data/videos/traffic_001.mp4) out cv2.VideoWriter(output/id7_trajectory.mp4, cv2.VideoWriter_fourcc(*mp4v), 30, (int(cap.get(3)), int(cap.get(4)))) points [] for _, row in df_id7.iterrows(): ret, frame cap.read() if not ret: break # 画检测框 cv2.rectangle(frame, (int(row[x1]), int(row[y1])), (int(row[x2]), int(row[y2])), (0,255,0), 2) cv2.putText(frame, fID:{int(row[track_id])}, (int(row[x1]), int(row[y1])-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2) # 画轨迹线 center (int((row[x1]row[x2])/2), int((row[y1]row[y2])/2)) points.append(center) if len(points) 1: for i in range(1, len(points)): cv2.line(frame, points[i-1], points[i], (255,0,0), 2) out.write(frame) cap.release() out.release()生成的id7_trajectory.mp4中绿色框是实时检测蓝色线是历史轨迹一目了然。从那以后我每次交付课程设计都强制走一遍这四步①用analyze_track.py看ID寿命分布②用export_single_id.py导出3个典型ID轨迹视频③用ffmpeg转码确保兼容性④最后用nvidia-smi截图附在README里证明GPU真在跑。不是为了炫技是避免答辩时被问“你这个ID稳定吗”“速度怎么算的”“能复现吗”——这些细节才是97分和85分的分水岭。希望帮到你。本文还有配套的精品资源点击获取
返回列表