
简介基于YOLOv5与DeepSORT实现的行人计数与追踪项目面向计算机视觉开发者、智能安防与客流统计场景可用于实时监测摄像头画面中的行人轨迹、统计出现总人数并针对自定义黄线区域判定穿越人数。压缩包共133个文件以Python源码.py/.pyc、模型权重.pt、配置文件.yaml、示例图片与视频.jpg/.mp4、说明文档.md为主整体大小约94MB结构清晰便于按需取用。目前已有7266人学习使用具备较好的参考价值。借助项目附带的模型文件、演示视频及教程脚本读者可直接运行并验证效果也可深入学习YOLOv5目标检测、DeepSORT多目标跟踪、卡尔曼滤波预测及行人过线判定等关键实现细节适合用于毕设、课设或实际监控系统的快速搭建与二次开发。1. 项目概述这个行人计数仓库到底做了什么把 yolov5-deepsort-pedestrian-counting 这个项目拉下来跑通之前我一直以为行人计数就是个“检测到人就算一个数”的简单任务。真正上手才发现单独用目标检测做计数结果会惨不忍睹——同一帧里一个人被检测框反复命中计数就会成倍虚高人一多、一遮挡数字直接没法看。这个项目聪明的地方在于它把 yolov5 当眼睛把 deepsort 当记忆检测负责“看到人”跟踪负责“记住谁是谁”计数才做到了准确可信。项目本身实现两个核心功能第一个是统计摄像头画面里出现过的总人数也就是这个范围内历史累积出现过多少个不同的人第二个是自定义黄线越线计数提前在画面里画一条黄线行人从一侧跨到另一侧时系统自动判定方向并累加。这两个功能覆盖了绝大多数线下场景门店客流统计、通道进出人数、展台人流热力评估甚至工厂安全区域越界提醒都能直接套用。我个人的建议是无论你是要做毕业设计、公司项目预研还是自学者想搞懂多目标跟踪到底怎么回事这个仓库都是一个非常合适的起点。它不追求花哨的交互界面代码结构也相对直白把检测、跟踪、计数的整条链路串得明明白白。1.1 核心需求拆解总人数统计和越线计数分别怎么实现先说总人数统计。这个需求的本质是“去重”——同一物理世界的人在多帧画面里对应多个检测框必须被归并成同一个身份。yolov5 负责给出每一帧的检测框deepsort 拿到检测框后做特征提取和数据关联给每个行人分配一个稳定的 ID。代码里维护一个全局 ID 集合每当 deepsort 输出一个从未见过的 ID就把它加入集合最后集合的大小就是“出现过总人数”。再说越线计数。这个更讲究一点它要在像素坐标系里定义一条虚拟线然后利用跟踪结果里每个行人中心点的轨迹来判断是否“跨界”。核心判断依据是假设某个人上一帧中心点在线的 A 侧这一帧中心点变到了 B 侧那就说明他穿越了这条线。具体到代码实现就是通过直线方程计算帧间位置变化的符号符号翻转即视为跨越。由于 deepsort 对每个目标维护了持续稳定的轨迹误判率远低于单纯检测框的交叉比对。这两个功能看似差异很大其实底层是同一套基础设施检测 跟踪 轨迹管理。把这三个环节做扎实计数就只是上层的小逻辑。1.2 为什么选 yolov5 deepsort 这个组合这可以说是目前开源社区里最“皮实耐用”的一套组合了。yolov5 作为检测器速度和精度的平衡做得好尤其是针对行人这一类小目标在 COCO 预训练权重下的表现非常稳定而且社区资料极多遇到问题基本搜得到答案。deepsort 则是多目标跟踪领域最常用的基线方案它不依赖 GPU 推理也能运行只是慢一些对初学者相对友好。另一个重要原因是解耦。yolov5 和 deepsort 在工程实现上几乎是独立的你可以只换检测器比如后面换成 yolov8、yolov6也可以只换跟踪器比如换成 StrongSORT、ByteTrack各自调各自的参互不干扰。对于想扩展项目的同学这个灵活性太重要了。2. 系统原理与方案选型不是简单堆两个模型2.1 yolov5 检测端网络结构和工程化细节yolov5 目前的版本迭代很多从 v5.0 到 v7.0 都有结构上总体还是 CSPDarknet 骨干 PANet 颈部 多尺度预测头的框架。对行人计数来说我们最关心两个点选哪个模型规模和推理尺寸。模型规模上yolov5s 属于“性价比最高”的选择。yolov5n 虽然更快但小目标检测精度会有明显下降yolov5m 及以上的精度提升对行人这种“中尺寸目标”来说收益有限但帧率会掉得厉害。我在实测中yolov5s 在 1080Ti 上跑 640 分辨率输入能到 70 FPS 以上在 CPU 上跑 320 分辨率也能做到 15 FPS 左右非常适合做实时计数的原型验证。工程细节上有几个容易踩的坑conf-thres置信度阈值默认 0.25 在实际场景里往往会漏掉远距离行人建议把行人检测场景的阈值降到 0.15~0.2iou-thresNMS IoU 阈值默认 0.45如果人特别密集要适当调高到 0.5 或 0.55否则相邻行人的框容易被 NMS 误合并。另外注意COCO 数据集里 person 类别的索引是 0在使用预训练权重时只需要保留这个类别能省掉大量无用的分类计算。2.2 deepsort 跟踪端从“我看到人”到“我记得这个人”deepsort 的完整名字是 Deep SORTSimple Online and Realtime Tracking with a Deep Association Metric它是在 SORT 基础上的升级。SORT 只靠卡尔曼滤波预测和 IoU 匹配来关联检测框速度快但 ID Switch身份切换很频繁——一个人被挡住一会儿再出来就可能变成“另一个人”。deepsort 的改进在于引入了一个ReID 特征提取网络对每个检测框提取一个高维特征向量在匹配时把“长相相似度”也纳入距离度量从而大幅减少 ID Switch。跟踪流程包含几个关键环节卡尔曼滤波做运动状态预测位置、速度、级联匹配优先匹配那些连续出现的轨迹、IoU 匹配兜底处理短期遮挡、以及轨迹生命周期管理new/confirmed/deleted 状态机。在行人计数场景最重要的参数是max_age——它决定了一条轨迹在丢失目标后能存活多少帧。如果值太小行人短暂被遮挡就会导致轨迹消亡ID 被释放之后这个人重新出现会被赋予新 ID造成重复计数。来自我的实测建议是原始 deepsort 仓库默认max_age30在 25 FPS 视频里大约相当于 1.2 秒的遮挡容忍这个值对行人场景偏小。我自己改成max_age60甚至max_age90重复计数问题显著改善。当然也不能无脑调大因为轨迹存活太久会让“原本是两个人”的轨迹错误合并需要结合实际情况权衡。2.3 计数逻辑设计全局集合与虚拟线算法计数逻辑是这个项目真正的灵魂。全局总人数统计前面已经说过是往集合里塞 ID这个逻辑简单可靠。但越线计数的设计则需要更细致的思考。越线计数本质上是一个几何判断问题。先在画面中定义一条线段比如从点 A(x1, y1) 到点 B(x2, y2)。每帧对每个已确认跟踪的轨迹track取其 bounding box 底边中点或中心点作为“落脚点”。然后判断该点和线段的位置关系——通常用向量叉积来判断点在线的哪一侧。def is_cross(line_start, line_end, prev_point, curr_point): # 计算叉积判断点在线的哪一侧 def side(p1, p2, p): return (p2[0] - p1[0]) * (p[1] - p1[1]) - (p2[1] - p1[1]) * (p[0] - p1[0]) prev_side side(line_start, line_end, prev_point) curr_side side(line_start, line_end, curr_point) # 两侧符号不同说明跨界了 if prev_side * curr_side 0: return True return False实际部署时这个基础版逻辑会遇到一个经典问题人站在线上来回走动会导致重复计数。解决思路是引入“滞回区间”——以黄线为中心画一个带状区域只有当轨迹完整地从一侧进入、穿越、并到达另一侧时才算一次有效越线。或者在状态机里给每个 ID 记录“上一次所在侧”只有在跨越后至少离开线一段距离比如 20 个像素才允许该 ID 再次触发计数。3. 实操过程从环境配置到跑通整个项目3.1 环境配置与依赖安装这个项目的环境配置本身不算复杂但有几个细节值得注意。我用的组合是 Python 3.8 PyTorch 1.10 CUDA 11.3基本是 yolov5 官方推荐的稳定配置。如果你用的是更新的 PyTorch 2.x也兼容但要留意 torch 和 torchvision 的版本必须匹配。克隆仓库后需要分别安装两块依赖。yolov5 部分的requirements.txt在yolov5/子目录下deepsort 部分则在根目录要求scikit-learn、Pillow、opencv-python等。我第一次安装时踩的坑是漏掉了lap线性分配问题求解器deepsort 在跑匹配时直接报ModuleNotFoundError。另外还有两个小问题一是pycocotools在 Windows 上直接 pip 安装会失败需要先装Microsoft C Build Tools二是如果使用 GPU 推理必须确保 CUDA 和 cuDNN 版本对应否则 yolov5 会悄悄退回 CPU 模式帧率瞬间掉到个位数而你不知道为什么。3.2 源码结构说明与核心文件解读建议拿到代码后先别急着跑花半小时把目录结构过一遍。整个项目的主要入口有几个detect.py最核心的推理脚本集成了检测、跟踪、计数逻辑yolov5/完整的 yolov5 检测器源码deep_sort/deepsort 跟踪器实现包含deep_sort_pytorch等子模块utils/计数逻辑、绘图工具等先看detect.py的main流程读取视频 - 逐帧推理 - 检测结果送入 tracker - tracker 更新轨迹 - 根据轨迹执行计数逻辑 - 可视化输出。我强烈建议你从头到尾读一遍detect.py的run()函数它把检测和跟踪的接口衔接写得非常直观理解了它后续你替换任何模块都容易。3.3 自定义黄线越线计数的具体实现关于黄线越线计数大部分版本在代码里已经预设了一条线通常在utils/里的某个配置处你需要改成自己的场景坐标。这一步本质上是“标定”只能在运行前用鼠标选点或者在配置文件里直接设定数值。我推荐的做法是先截取一帧画面用画图工具量出起点和终点的像素坐标再填入代码。坐标选择要注意黄线应该尽量垂直于行人主要行走方向并且选取的位置要让人体轮廓相对清晰。把线画在画面边缘可能会漏计画在人群太密集的中心区域则容易误计。下面是计数模块的关键逻辑示意大部分开源版本的做法都类似for track in tracker.tracks: if not track.is_confirmed(): continue # 获取轨迹当前中心点和上一帧中心点 curr_center track_center(track) prev_center track.previous_center() # 判断是否跨越黄线 if is_cross(line_start, line_end, prev_center, curr_center): side get_side(line_start, line_end, curr_center) if side up: up_count 1 else: down_count 1如果你需要统计进出双向人数建议把up_count和down_count分开记录最后总人数就是两者之和。4. 常见问题与性能优化实录4.1 实际部署中遇到的高频问题排查这个项目在真实场景下跑起来问题一点不比功能开发少。我把自己踩过的、以及社区里提问最多的几个问题整理成一张表方便你直接排查。现象可能原因解决方案同一人重复计数max_age 太小轨迹在短暂遮挡后被释放调大 max_age 到 60~90必要时调大 n_init计数结果严重偏少检测置信度阈值太高远距离行人被漏检将 conf-thres 降到 0.15~0.2使用更大推理尺寸画面卡顿严重CPU 推理或未启用 GPU检查 torch.cuda.is_available()改用 GPU 或减小输入尺寸计数时多时少不稳定画面亮暗变化影响 ReID 特征统一输入视频亮度或引入简单的图像增强预处理人一多就乱ID 频繁切换密集场景下 ReID 特征判别力不足换更强的 ReID 权重或在其基础上叠加 IoU 约束黄线附近来回走动触发多次计数没有滞回逻辑加入带状滞回区间要求轨迹离开线一段距离才允许再次计数4.2 推理性能对比yolov5 与 yolov6 在实际计数场景的差异最近很多人问我yolov5 要不要升级到 yolov6 甚至 yolov8。我在同一段视频上做了对比测试结论可能和你想的不太一样。yolov6 最大的优势是在 NVIDIA GPU 上经过极致优化的检测速度官方公布的数字很好看但在 CPU 上它的推理速度反而不如 yolov5s因为它的网络结构里有更多并行分支对 CPU 的指令集和线程调度不太友好。如果你的部署环境是普通办公电脑无独显yolov5 反而是更稳的选择。yolov8 的检测精度在行人这类目标上确实更高尤其是对小尺寸行人但代价是参数量和计算量更大帧率大约会下降 20%~30%。对于计数任务来说我们并不需要极高的检测精度只要跟踪稳定计数准确度就不会差。所以我的结论是在 CPU 或中低端 GPU 上做行人计数yolov5 依然是首选如果场景密集、遮挡严重且 GPU 资源充足再考虑换 yolov8 作为检测器。4.3 边缘设备部署方向树莓派与 STM32 场景扩展这个项目跑通之后很多人会想把它部署到边缘设备上。树莓派 5 是可以跑得动 yolov5 的但必须要做三个调整把推理尺寸从 640 降到 320减少计算量使用轻量化权重 yolov5n 或做 INT8 PTQ 量化开启 NCNN 或 ONNX Runtime 的 CPU 加速。实测下来树莓派 5 上能跑到 8~12 FPS做实时计数体验已经勉强可用了。至于 STM32 这类单片机说实话跑完整版 yolov5 是不现实的。如果你要做的是“基于 STM32 的边缘端车辆检测与车位管理”这类项目实际方案通常是把模型剪枝量化成极小的二值或 8bit 模型配合外部摄像头和外部算力芯片比如 K210、RV1126来完成检测STM32 只负责控制逻辑和结果上报。所以在架构设计上不要试图把深度模型硬塞进 MCU而是做好“传感器 算力芯片 MCU”的分工。5. 参数调优与工程化落地实践5.1 让计数更稳定的几个重要参数到这里我想重点聊一下基于大量实测得出的参数组合直接抄作业即可。对 1080P 摄像机俯拍或平拍的通道场景我建议使用以下配置推理尺寸img-size640平拍/ 480俯拍conf-thres0.2iou-thres0.5max_age60n_init3max_cosine_distance0.3ReID 特征匹配阈值需要注意max_cosine_distance的值越小匹配越严格越不容易把两个人误判为同一个但也会更容易因外观变化导致 ID 分裂。0.3 是一个比较平衡的起点如果场景光线稳定可以适当降到 0.25 来减少错误合并。5.2 训练自己的行人检测模型从标注到部署如果你不是用 COCO 预训练权重而是想针对自己的摄像头视角训练一个效果更好的模型那就要走完整的训练流程。这个项目兼容 yolov5 的训练接口过程并不复杂先用 LabelImg 或 Labelme 标注行人框标注格式输出为 YOLO 的 txt 格式然后按 8:1:1 划分训练集、验证集、测试集最后配置一个data.yaml文件指向数据集路径和类名列表。训练时要注意如果只有几百张图片直接把预训练权重yolov5s.pt作为初始权重做迁移学习会收敛更快。超参数方面hyp.scratch-low.yaml是稳健的默认选择如果你的场景光照变化大可以调高hsv_h、hsv_s等数据增强参数来提升泛化性。训练完成后把 best.pt 替换掉仓库里的检测权重即可。5.3 工程化落地时可以做的三项改进如果这个项目要用于实际项目交付下面三项改进是我认为性价比最高的第一增加消息队列缓冲。现在的detect.py是单线程逐帧处理一旦检测变慢视频会一卡一卡。改成生产者消费者模式用队列缓冲视频帧可以在一定程度上吸收检测耗时波动。第二增加定时上报与断线重连。在做门店或工地人数统计时计数的结果通常要上报到服务器。建议单独开一个线程每隔 5 秒或 10 秒上报一次当前总人数和越线人数使用 HTTP 或 MQTT 都行。第三把“出现过的总人数”做成持久化存储。如果进程重启内存里的 ID 集合会清零之前的统计数据就丢了。建议每次新增 ID 时同步写入一条 SQLite 记录这样即使程序崩溃也能恢复历史数据。6. 写在最后一些小经验和扩展方向做这个项目最大的收获不是把计数器调准而是彻底理解了“检测”和“跟踪”是两种完全不同的任务。检测是静态的、逐帧的跟踪是动态的、基于时间序列的。只有把两者衔接好才能拿到稳定可靠的结构化数据。很多初学者一上来就想换最新的检测模型却发现计数结果反而变差了原因往往就是跟踪参数没有跟着调整。如果你想在这个基础上继续扩展我建议按这个路线走先替换更优的跟踪器比如 StrongSORT你会发现计数准确率还有巨大提升空间然后引入 ROI 区域计数实现自定义多边形区域内的行人统计再往上是行人属性识别性别、年龄段、着装颜色这类信息在线下场景的商业价值比单纯计数更值钱。但无论怎么扩展yolov5 deepsort 这个链路带来的“检测-跟踪-计数”思维框架是完全可以沿用下去的。最后再分享一个实用小技巧调试计数逻辑时不要直接拿实时视频跑先录一段 5 分钟的测试视频固定输入这样每次改完代码都能用同一段视频对比前后的计数结果调参效率会提高很多。我就是靠着这个办法把计数误差从最初的 20% 降到了接近 1%整个过程全靠反复对比同一段视频的输出。本文还有配套的精品资源点击获取