公司动态
基于PyTorch的YOLOv5+SORT车辆行人识别追踪实战解析
简介计算机视觉中目标检测与目标跟踪是智能视频分析的核心基础。目标检测负责定位画面中的物体而目标跟踪则为每个目标分配稳定ID并预测其运动轨迹。基于PyTorch的YOLOv5作为高性能检测器结合轻量级SORT算法采用检测后跟踪Tracking-by-Detection范式通过卡尔曼滤波预测目标状态匈牙利算法进行数据关联实现对车辆、行人的实时识别与持续追踪。该方案广泛应用于交通流量统计、路口监控、安防巡检等场景。本文围绕YOLOv5SORT的开源项目讲解其原理、数据流、环境配置与参数调优并汇总常见问题排查经验帮助开发者快速上手多目标跟踪落地实践。 把这份基于PyTorch的YOLOv5SORT车辆行人识别追踪源码跑通后我最大的感受是它把目标检测和目标跟踪这两个环节串成了一条清晰、可上手的流水线。YOLOv5负责在每一帧找出车辆和行人在哪里SORT负责给这些目标分配身份ID并持续跟踪最终输出带ID的检测框和轨迹信息。这种系统最典型的应用就是交通视频分析、路口流量统计、园区安防以及入门多目标跟踪的学习项目。如果你已经会跑YOLOv5想再进一步理解“追踪”是怎么实现的这个项目非常适合你。1. 项目拆解YOLOv5和SORT如何配合1.1 目标识别与目标跟踪缺一不可很多人刚接触这个项目时会有一个疑问YOLOv5已经能把车辆和行人框出来了为什么还要再加一个SORT答案是检测器只回答“这一帧画面里有哪些目标”而追踪器要回答“这些目标上一帧在哪、下一帧要去哪、谁是谁”。车辆行人识别追踪系统里如果只用YOLOv5逐帧检测你会发现同一个行人在前后两帧里框的位置是跳变的没办法统计他走了多远也没法区分“左边这辆黑色轿车”和“右边那辆白色轿车”。接入SORT之后跟踪器会给每个目标分配一个唯一ID只要目标没有长时间离开画面ID就不会变后续无论是统计车流量、行人轨迹还是做越界告警都有了一个稳定的数据基础。这里有一个概念需要区分目标检测和目标跟踪是两个不同任务。YOLOv5是one-stage检测器输入图像输出所有目标的边界框、类别和置信度SORT则是多目标跟踪算法输入一组检测框输出维护好的轨迹每条轨迹带有一个ID。两者结合就是最常见的“检测加跟踪”范式也叫做Tracking-by-Detection。这个项目选择这套组合不是因为DeepSORT不好而是因为SORT足够轻量、依赖少、运行快在CPU上也能保持不错的实时性特别适合拿来当第一套多目标跟踪系统上手。1.2 从视频帧到追踪结果的完整数据流整个系统的数据流其实不复杂。你给它一段视频它会拆成一帧一帧的图片按下面的顺序处理YOLOv5对当前帧做推理得到多个检测结果每个结果包含5个信息目标框的x、y、width、height可能是归一化坐标或像素坐标、类别编号、置信度分数。按业务需要做类别过滤比如只保留person、car、truck、bus去掉猫猫狗狗等无关物体。将检测结果整理成SORT能接受的格式一般是一个二维数组每行是[x, y, w, h, score]或者[x1, y1, x2, y2, score]。调用SORT的update方法传入上一帧保留下来的追踪器状态和当前帧检测框SORT内部通过预测和关联输出当前帧仍在跟踪的目标并带有ID。把跟踪结果画到原图上显示类别、ID、置信度然后写入输出视频或推流。我为什么强调这个顺序因为很多刚开始尝试修改代码的人会直接把YOLOv5输出的所有类别都塞给SORT结果跟踪器把自行车和公交车当成同一个目标ID乱跳。正确做法是先过滤类别再决定是否按不同类别分别维护跟踪器。关于这一点我后面会在参数调优里详细展开。1.3 源码包里都有什么一般你下载到的这类源码包解压之后大概会有这么几个部分主程序文件比如main.py、detect_track.py负责启动检测和跟踪流程。yolov5子目录里面是YOLOv5的模型定义、工具函数和配置文件。有些项目不会把整个YOLOv5代码塞进去而是通过import的方式引入这时要注意路径是否写对。sort子目录包含sort.py、kalman_filter.py、linear_assignment.py或hungarian.py这是SORT算法的核心实现。weights目录存放预训练权重文件比如yolov5s.pt。如果压缩包没带权重需要单独下载。requirements.txt列出所有Python依赖库。一些配置文件比如类别名称列表、参数设置文件。拿到压缩包第一步不是急着运行而是先看目录结构搞清楚主程序在哪里、依赖有哪些、权重放在哪。很多报错都是因为直接在不对的目录下运行导致相对路径找不到模型文件。我第一次跑这个项目时就因为在子目录里执行python main.py结果报错找不到yolov5s.pt后来回到项目根目录才解决。2. 核心原理检测器与跟踪器各司其职2.1 YOLOv5检测不只输出框还输出类别和置信度YOLOv5本身是一个成熟的检测框架它在COCO数据集上训练后可以识别80类物体。对于车辆行人追踪系统来说我们通常只关心person、car、truck、bus、motorcycle、bicycle这几类。这里很多人会忽略一个小细节YOLOv5输出的坐标在默认情况下是归一化到0-1之间的但SORT更习惯处理像素坐标所以代码里一般会有一个坐标转换步骤。用YOLOv5做检测时三个参数对后续追踪效果影响很大img-size输入网络的图像尺寸。默认640x640如果视频分辨率不高用320推理更快但小目标可能漏检如果都是远处的小车建议保持640或者提高到1280但速度会下降。conf-thres置信度阈值。阈值越低检测出越多目标但误检也会增多阈值高则只保留高置信度目标。iou-thresNMS的IOU阈值用于合并重复框。这个值通常不用调保持默认0.45即可。检测质量直接决定跟踪上限。如果YOLOv5某一帧漏检了目标SORT只能靠预测维持一小段时间时间稍长目标跟踪轨迹就会断掉。所以当跟踪效果不好时先检查检测结果再调试跟踪参数顺序一定不能反。2.2 SORT跟踪用卡尔曼滤波预测目标去向SORT全称是Simple Online and Realtime Tracking思路非常直接。它对每一个被跟踪目标维护一个卡尔曼滤波状态这个状态不仅包含目标当前的位置和大小还包含位置和大小的变化速度。用这些速度信息可以预测目标在下一帧可能出现的位置从而缩小匹配范围。卡尔曼滤波可以理解成一个“带修正的预测器”。假设你看到一辆车正以某个方向驶过画面根据它前一秒的位置和速度你能猜出它下一秒大概在哪里。但猜测不一定准因为车子可能减速、转弯。卡尔曼滤波的做法是先根据运动模型做预测再拿到当前帧的检测框后把预测值和检测值做一个加权融合得到更精确的位置估计。SORT正是利用这种方法让ID在不同帧之间保持连续。数据关联部分SORT用的是匈牙利算法。它计算每个已有轨迹的预测框和当前帧所有检测框之间的IOU组成一个代价矩阵然后用匈牙利算法找到全局最优的匹配组合。匹配成功的轨迹用检测框更新状态匹配不上的检测框会新建一条轨迹长时间没被匹配上的轨迹会被删除。这套流程虽然简单但在车辆行人这种运动相对平缓的场景里非常实用。2.3 检测结果到跟踪器的坐标转换与关联代码实现中最容易踩坑的就是坐标体系和格式。YOLOv5输出的默认结果是xywh的归一化坐标也就是说x和y表示中心点w和h表示宽高所有值都在0到1之间。而SORT的卡尔曼滤波器在计算时通常使用像素坐标如果不转换预测、IOU计算都会出错跟踪结果自然一塌糊涂。正确的转换方式是拿归一化坐标分别乘以图像的宽度和高度。比如输入图像宽度是1280高度是720归一化中心点x0.5w0.2那么像素坐标就是x640w256。很多源码里会有rescale或xywh2xyxy的工具函数干的就是这件事。另外还要注意SORT接收的检测格式。有的实现接收[x, y, w, h, score]有的接收[x1, y1, x2, y2, score]。如果你拿到的源码包是前者而YOLOv5输出的是xyxy格式的角点坐标就需要先转换。我习惯在封装时统一成[x, y, w, h, score]因为SORT内部的KalmanBoxTracker默认处理的就是这种中心点加宽高格式。3. 实操全记录从环境搭建到跑通视频3.1 PyTorch和YOLOv5环境配置先说环境版本。YOLOv5对PyTorch的版本不是特别挑剔但如果你用的PyTorch版本太新某些旧版本的YOLOv5代码会报错。我建议使用Python 3.8或3.10PyTorch 1.12到2.0之间torchvision版本和torch对应即可。安装PyTorch时先确认你的电脑是NVIDIA显卡还是纯CPU。如果有独显安装GPU版本能明显提速如果只是日常学习CPU版本也能跑只是慢一些。用conda创建环境时我通常这么执行conda create -n track python3.8 conda activate track pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117这里要注意PyTorch官网安装命令会根据CUDA版本变化。先运行nvidia-smi查看本机驱动支持的CUDA版本再选对应的cuXXX版本不能乱装。安装完记得在Python里验证一下import torch print(torch.__version__) print(torch.cuda.is_available())如果torch.cuda.is_available()返回False说明你装了CPU版本或者CUDA驱动没配好后续推理只能用CPU跑。接下来安装YOLOv5依赖。通常源码包的requirements.txt已经列好了opencv-python、numpy、matplotlib、seaborn等库。在项目根目录执行pip install -r requirements.txt如果网络较慢可以加清华镜像源。权重文件yolov5s.pt如果下载失败也可以直接从其他地方下载后手动放到weights目录。我在实践中发现很多人卡在“无法连接到ultralytics服务器”这类问题上解决方式就是手动下载别硬等。3.2 主流程代码走读跑通环境后打开主程序你会发现核心逻辑并不长。我用一个很常见的代码骨架来说明import cv2 import torch import numpy as np from sort import Sort model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.conf 0.30 model.classes [2, 3, 5, 7] # 2:car, 3:motorcycle, 5:bus, 7:truck, person是0 tracker Sort(max_age3, min_hits1, iou_threshold0.3) cap cv2.VideoCapture(test.mp4) while True: ret, frame cap.read() if not ret: break results model(frame) dets results.xyxy[0].numpy() # [x1, y1, x2, y2, conf, class] # 过滤类别 转为 [x, y, w, h, score] 格式 track_input [] for det in dets: x1, y1, x2, y2, conf, cls det w x2 - x1 h y2 - y1 cx, cy x1 w / 2, y1 h / 2 track_input.append([cx, cy, w, h, conf]) track_input np.array(track_input) if track_input else np.empty((0, 5)) tracked_targets tracker.update(track_input) # 绘制跟踪框并显示ID for t in tracked_targets: x1, y1, x2, y2, tid int(t[0]), int(t[1]), int(t[2]), int(t[3]), int(t[4]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, fID:{tid}, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow(frame, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这里最需要注意的是tracker.update每帧都调用一次并且输入的一定是当前帧检测框的二维数组。即使当前帧没有任何目标也要传一个空数组不能传None否则SORT内部做矩阵运算时会报错。另外YOLOv5的model(frame)接收的是RGB图像。如果你用cv2读取的是BGR直接传进去检测结果会偏色导致漏检。稳妥做法是frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results model(frame_rgb)很多基于旧版YOLOv5代码封装的项目会在detect函数内部先做这种转换但写主程序时很容易忽略。3.3 参数调整让追踪更稳的关键设置跑通只是第一步想让车辆行人的追踪效果稳定需要调几个关键参数。第一个是SORT的max_age。这个值表示一个目标连续多少帧没匹配到检测框就认为它已经消失删除轨迹。默认是1也就是漏检一帧就删除车辆刚被遮挡一帧ID就丢了。对于车辆行人场景我建议把max_age设成3到8之间不要超过10否则目标离开画面很久后轨迹又突然被新的检测框匹配上ID会发生漂移。第二个是min_hits。它表示一个目标需要连续被检测到多少帧才被认为是一条正式轨迹。默认1也就是第一次检测到就分配ID。这在密集场景下容易造成大量误触发的短暂ID可以设成2或3过滤掉一闪而过的误检。第三个是iou_threshold。SORT匹配时只有轨迹预测框和检测框的IOU大于这个阈值才可能是同一个目标。默认0.3。如果场景里车辆重叠严重可以调低到0.2让匹配更宽松如果画面空旷目标之间距离很远可以调高到0.4防止不同目标因为预测框交叉而错误匹配。我还要提一个容易忽略的处理类别分开跟踪。比如你想统计通过路口的车辆数又不想让行人干扰车辆ID可以对车辆类目标用一个大写“C”前缀的ID对行人用“P”前缀甚至直接维护两个独立的SORT实例。我实际项目里是这么做的tracker_car Sort(max_age5, min_hits2, iou_threshold0.3) tracker_person Sort(max_age3, min_hits1, iou_threshold0.3)这比用一个跟踪器成本高不了多少但ID稳定性好很多尤其车辆和行人交错时不会出现ID互相抢的情况。4. 常见问题与排查技巧实录4.1 环境依赖的坑先列举几个我身边朋友经常遇到的问题。PyTorch与torchvision版本不对应导致导入torchvision时报错一般pip安装不会自动选择匹配版本建议参考PyTorch官网的版本配对表。例如torch 1.13.1对应torchvision 0.14.1。运行YOLOv5时报错AttributeError: Upsample object has no attribute recompute_scale_factor这多半是PyTorch版本和YOLOv5版本都不太新边界情况下触发了属性兼容问题。最简单的办法是把PyTorch升级到2.0以上或者升级YOLOv5代码。如果是老项目不想动环境也可以手动修改torch的functional.py但不推荐容易引发其他问题。还有一类是CUDA编译问题。Windows上有些开源工具依赖需要C编译器如果你没有Visual Studio Build Toolspip安装时可能报错。解决办法是尽量安装别人编译好的wheel包而不是从源码编译。实在不行就切换到CPU环境跑又不会影响学习。4.2 检测效果不佳怎么办检测不到车辆或行人时先检查YOLOv5的置信度阈值是不是设得太高。如果画面里都是小目标阈值0.5会把不少真目标滤掉降到0.25左右通常能提升召回率。同时确认模型输入尺寸是否太小640x640对远距离小目标不友好按需调整到960或1280。另一种情况是类别过滤写错。有人把模型类别编号写错比如person是0但代码里设成1结果画面里明明有人却一个检测框都没有。建议在调试阶段先把类别过滤注释掉输出所有检测结果确认YOLOv5是否能正常检测到目标再逐步加过滤。如果检测框存在但跟手性不好可能是NMS的iou-thres太高或者太低。iou-thres太高会导致一个目标输出多个重叠框太低则会导致两个靠近的目标被合并成一个框。一般保持0.45即可不需要频繁调整。4.3 跟踪ID频繁跳动这是多目标追踪里最让人头疼的问题。ID来回跳往往是因为目标之间IOU重叠匈牙利匹配分不清谁是谁。可以按优先级依次排查先看检测器是否稳定再调低SORT的iou_threshold然后适当调大max_age。如果目标被长时间遮挡再恢复时ID大概率会变这属于SORT的固有短板想要外观特征抗遮挡可以考虑升级到DeepSORT或ByteTrack。另外如果视频帧率不稳定也容易导致目标位置突变SORT预测不准。处理方式是在视频源读取时做帧率控制或者给卡尔曼滤波的状态噪声适当调大让模型更相信检测框而不是预测值。卡尔曼滤波的噪声参数通常在KalmanBoxTracker初始化时定义适当加大过程噪声可以提高对突然加速或减速的适应能力但这部分SORT源码默认写死需要手动修改。4.4 源码包路径与运行问题很多源码包不是单文件项目而是一个多级目录。如果运行主程序时提示找不到模块先确认你是在项目根目录下运行并且ZIP解压后没有把yolov5文件夹嵌套了一层同名目录。最简单的验证方式是在主程序里加一行import os print(os.getcwd())如果当前目录不是项目根目录用cd切换到根目录再运行。还可以在代码前部加入sys.path.insert(0, os.path.dirname(file))强制把项目根目录加入模块搜索路径。如果提示找不到yolov5s.pt检查weights目录下是否有该文件并确认代码里是否用了相对路径。我习惯把路径统一写成绝对路径或者放到一个config.py里集中管理避免在不同环境切换时报错。4.5 视频输出没有内容或保存失败常见原因是输出路径不存在或编码器格式不支持。用OpenCV保存视频时建议使用如下设置out cv2.VideoWriter(output.avi, cv2.VideoWriter_fourcc(*XVID), fps, (width, height))frame的尺寸必须和VideoWriter初始化时一致否则保存出来的视频是0字节。另外如果用的是MP4格式可能会因为缺少H264扩展而失败换成XVID或MJPG更稳。最后分享一个调参心得。我调试这类系统的习惯是先用一段车辆稀疏、行人较少的视频验证整体流程再把场景换成复杂路口逐帧观察每个ID的稳定性。不要指望一组参数适配所有视频。车流密度、行人遮挡程度、镜头远近都会影响最优参数。源码包只是把基础框架搭好真正有意思的部分是你如何根据自己业务场景去调整检测和跟踪的配合方式。如果后续还想继续深入可以考虑在SORT的基础上加入外观特征做DeepSORT或者使用更年轻的ByteTrack对遮挡场景更友好。这套YOLOv5SORT的源码至少能帮你把检测加跟踪的完整链路吃透。本文还有配套的精品资源点击获取