ARTICLE DETAIL

资讯详情

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

YOLOv5人群计数:从训练到边缘部署的完整方案

YOLOv5人群计数:从训练到边缘部署的完整方案 简介一套基于YOLOv5的人群计数Python项目专为计算机视觉开发者与算法学习者设计能够对图像或视频画面中的人员进行准确识别与数量统计。项目依托YOLOv5目标检测模型在高精度与高速度之间取得良好平衡支持摄像头实时画面接入和本地视频文件处理可广泛应用于安防监控、商场客流统计、交通枢纽人流密度分析等真实业务场景。压缩包共207个文件包含Python源码、YAML配置、模型权重pt、Shell脚本、Dockerfile以及示例图片等整体约30.58MB目录结构清晰。源码文件负责核心检测逻辑YAML配置定义模型参数PT权重可直接加载推理Shell脚本与Dockerfile则辅助自动化部署和跨平台运行。已有1363人学习下载。读者可获得完整的可运行工程包括预训练模型、推理与训练脚本、环境配置说明等无需从零训练即可快速搭建人群计数系统也可以在此基础上调整模型参数或扩展功能适应不同应用需求显著缩短开发周期。 人群计数这个需求在景区、商场、地铁站、校园这类公共场所几乎天天遇到。以前大家习惯用红外对射或WiFi探针去估算客流精度实在感人现在视觉方案基本是主流而其中落地做得最多的做法就是把人群计数当成目标检测问题来解——用YOLOv5检测每一个人头或者人体框最后统计检测框数量。这篇文章我会从方案选型、数据标注、训练调参、推理后处理到边缘端部署完整走一遍用YOLOv5实现人群计数的落地方案适合刚接触目标检测、或者已经跑通YOLO基础流程但想把它接到实际业务场景的朋友。1. 方案选型为什么是YOLOv5做人群计数1.1 人群计数的两条主流技术路线人群计数在计算机视觉里其实有两条完全不同的技术路线。一条是密度估计回归代表工作是CSRNet、MCNN这类网络输入一张图输出一张密度图对密度图求和得到总人数。这条路线的特点是极度密集场景下精度不错因为它是按“区域拥挤程度”来估计不需要框出每个人。但它的问题也很明显没有个体位置信息想做人流轨迹、区域停留分析就非常麻烦而且训练数据的标注成本很高通常需要点标注或者逐像素密度图标注一个密集场景的工作量比画框还恐怖。另一条就是目标检测计数也就是YOLO系列的做法检测出每个人头/人体的边界框直接数框个数。它的上限在极度拥挤时不如密度回归但胜在落地属性强——能拿到坐标、能接追踪器、能输出热力图模型和工具链都是现成的工程收益明显更高。我实际做过的项目里商场客流、校园食堂拥挤度、工地安全区域人数统计基本都走的是目标检测这条线。一个很现实的原因是这类场景虽然人流不小但很少会夸张到“一平方米站五六个人”那种极度过饱和的情况用检测计数完全够用还能顺手多做不少事。1.2 YOLOv5方案的优势与适用边界YOLOv5能成为今年来这类项目的主力不是因为它精度在所有模型里最高而是因为它的生态成熟度和部署适配性太强了。训练方面官方仓库开箱即用预训练权重覆盖面广从Windows到Linux再到树莓派都有大量踩坑案例可以查部署方面ONNX、TensorRT、OpenVINO、NCNN、RKNN、eIQ一套套工具链都接得明明白白直接决定了它能跑进边缘设备。相比之下同期的YOLOX、YOLOv8这里指Ultralytics系列性能上各有千秋但很多边缘NPU厂商的SDK适配文档仍然以YOLOv5为主要参考模型这就是选择它的最大理由。再加上YOLOv5有n/s/m/l/x多个分支覆盖从手机端到服务器的算力范围做人群计数这种对帧率有要求的场景算力预算很好控制。当然要清楚它的边界如果真要做那种几千人聚集的超密集广场YOLOv5的密集遮挡漏检率会明显上升这时候与其硬调框不如考虑混合方案比如检测计数为主、密度图修正为辅。但日常的90%项目还是YOLOv5这条路更稳、更省心。2. 数据准备与训练自己的数据集2.1 用哪个数据集开源还是自采训练之前先把数据问题理清。人群计数的开源数据集有不少Mall Dataset场景小但干净适合做验证ShanghaiTech Part A/B是学术界最常用的人群计数数据集Part A密集程度相当高UCF-QNRF更极端单张图几千人标注数量大、目标尺度跨度大。如果你的项目只是为了评估算法可行性拿这些跑一遍没问题。但要是做实际落地我的经验是开源数据只能做预训练和可行性验证最终还是要自己采一批现场数据来微调。原因很简单监控摄像头的安装角度、高度、光照、图像分辨率都和公开数据集差异巨大直接用人家的模型硬上泛化效果多数情况下不理想。自采数据时有一个比较务实的建议先固定摄像头的安装位置和角度再按时间段批量截取画面尽量覆盖早中晚、晴天雨天、节假日这种光照和密度差异大的时段。数据集不需要一口气堆几万张几千张高质量画面加上在线增强就够起步了批量标注完跑一版看效果不够再补比一次性投入大量标注成本要划算得多。2.2 标注规范标人头比标人体更稳到了标注环节这是人群计数项目最值得抠细节的地方。我的核心建议是优先标注“人头”而不是整个人体。监控摄像头大多是高角度俯拍人体之间相互遮挡非常严重一个完整的人体框可能被前面的人挡住一半标出来各种不规则模型要学出稳定的特征很难。但人头在俯拍视角下基本是完整可见的即使是密集场景头部的轮廓和纹理相对清晰标注和检测的稳定性都要好得多。还有一个细节如果你接的是通道闸机、出入口这类场景人体框可能因为人挨着人而连成一片但头部框依然能分开对后续计数更友好。标注工具用LabelImg或LabelMe都可以导出YOLO格式时每条标注是class_id x_center y_center width height坐标要归一化到0~1。下面是我常用的标注规则你可以直接抄头部完全可见、遮挡超过65%的目标都要标模糊的也尽量标实在无法辨认的放弃目标在画面中的像素宽度小于8px时标注的意义不大模型很难学到有效特征同一目标只标一个框不重复框选类别就一个head不要做多类别背景干扰单独靠难例挖掘来压。这里有个容易被忽视的坑标签文件里会出现大量小目标框也就是标注框的宽高在归一化后小于0.02。如果这种小框占比过高模型训练时对这些小目标的梯度贡献被大目标掩盖最后推理时远处的人群基本全漏检。遇到这种情况要么把训练分辨率从640拉高到960或1280要么在损失函数里适当加大小目标分支的权重这是最有效的两个手段。2.3 数据组织与配置文件修改YOLOv5训练自己数据集的目录结构有固定要求按这个整理就好dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── dataset.yamldataset.yaml内容很简单但有几个细节要注意路径最好写绝对路径避免相对路径在不同环境下引发玄学问题nc必须是1names写[head]注意列表顺序要和标注的类别id保持一致。train: /home/user/dataset/images/train val: /home/user/dataset/images/val nc: 1 names: [head]训练集和验证集划分建议按9:1或8:2但一定要保证同一个场景的画面不要出现在两个集合里否则你验证集看到的都是“熟脸”指标虚高真实场景一跑就现原形。另外整个数据集路径里不要出现中文和空格YOLOv5对路径处理不够健壮这种低级问题排查起来最浪费时间。3. 环境搭建与训练超参数调优3.1 显卡驱动、CUDA与PyTorch版本怎么配环境搭建是很多人卡壳最久的一步。先说我自己的顺序先装NVIDIA显卡驱动用nvidia-smi确认驱动和最高支持的CUDA版本再装CUDA Toolkit和cuDNN最后创建PyTorch环境。关键点是PyTorch官方安装命令里绑定的CUDA运行时版本其实可以和支持的CUDA版本不一致只要PyTorch运行时依赖的CUDA版本不大于驱动支持的版本就行错误消息和网上教程的常见坑大多是这里产生的。nvidia-smi # ----------------------------------------------------------------------------- # | NVIDIA-SMI 525.105.17 Driver Version: 525.105.17 CUDA Version: 12.0 | # -----------------------------------------------------------------------------比如驱动支持CUDA 12.0那PyTorch装cu118或cu121版本都能跑PyTorch会自动打包它需要的CUDA runtime不需要额外装一份系统级CUDA。下面是几组我自己试过比较稳的组合显卡型号驱动版本建议PyTorch CUDA版本备注RTX 3060470cu118显存12G训练yolov5s很舒服GTX 1080Ti470cu113/cu118老卡但显存11Gyolov5s也够RTX 4090525cu121新卡必须新驱动旧驱动识别不了纯CPU/npu环境不需要CPU版即可推理用训练靠服务器装完以后用这个命令验证CUDA是否可用python -c import torch; print(torch.__version__, torch.cuda.is_available())如果torch.cuda.is_available()输出False99%是CUDA版本不匹配或显卡驱动太旧不要继续往下走先排查环境。3.2 train.py训练命令与关键超参数环境就绪后训练命令本身不复杂python train.py --img 640 --batch 16 --epochs 100 --data dataset.yaml --weights yolov5s.pt --name crowd_head几个参数值得展开说。--img是输入分辨率追求精度可以上1280但显存占用会显著上涨--batch受显存限制用RTX 3060 12G跑yolov5s、640分辨率batch 16是合适的如果batch太小比如4训练过程不稳定建议用梯度累积来模拟大批量。--weights建议用官方预训练权重初始化虽然你要做的只有“head”这一个类别但预训练权重已经把通用特征学好了比从头训练快得多、稳得多。YOLOv5的超参数配置文件在data/hyps/hyp.scratch-low.yaml注意里面几个关键参数lr0初始学习率默认0.01。用预训练权重时不用动从头训练时可以调到0.005mosaic默认1.0开启后四张图拼接能显著提升小目标泛化但人群场景里偶尔会把目标裁掉一半建议保留但观察loss曲线mixup默认0.0混类增强人群密集场景不建议一开始就开先不开等基础收敛后可以开0.2微调hsv_h、hsv_s、hsv_v颜色增强光照变化大的场景可以加大这里的值。3.3 训练监控与模型效果评估训练时主要盯着两个东西看一个是终端输出的Pprecision、Rrecall、mAP0.5另一个是runs/train/crowd_head/目录下的曲线图。人群计数这个场景里我个人的排序是recall优先于precision。道理不难理解计数偏少漏检比计数偏多误检在实际业务中更难接受漏了一个人就少一个人多检一个可能是某个背影造成的可以靠后处理滤掉一些。如果你的recall明显偏低优先加大训练数据覆盖、调低置信度阈值、或者提高输入分辨率。训练到100个epoch还不够的情况也很常见尤其是小样本数据集。此时用前一轮的权重继续训练--weights runs/train/crowd_head/weights/best.pt --resume然后把epoch补到150或200观察val曲线是否还在下降。真正收敛的标志是mAP趋于平缓且不再有明显抖动而不是盲目追求高mAP。还有一个简单技巧人群计数场景下mAP0.5达到0.85以上通常就可用了不必执着于0.95这种高IoU指标因为密集人群的框本身重叠严重高IoU要求会大幅压低召回。4. 推理计数与后处理调参4.1 推理计数代码怎么写模型训练完成后最简单直接的计数方式就是加载模型对每一帧做推理统计检测框的个数。下面是我常用的一个推理计数脚本注意我加了过滤条件只保留高置信度和尺寸在合理范围内的目标import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/crowd_head/weights/best.pt) img cv2.imread(test.jpg) results model(img, size640) # results.xyxy[0]是每帧所有检测框的tensor每行[x1,y1,x2,y2,conf,cls] boxes results.xyxy[0].cpu().numpy() conf_thres 0.35 min_w 8 # 小于8个像素的检测框大概率是远距离误检 min_h 8 valid_boxes [] for box in boxes: x1, y1, x2, y2, conf, cls box if conf conf_thres and (x2 - x1) min_w and (y2 - y1) min_h: valid_boxes.append(box) print(f人群计数结果: {len(valid_boxes)} 人)这里有两个细节值得注意。一是torch.hub.load虽然方便但在联网环境受限的边缘设备上不适用那种场景应该在代码里直接加载本地权重或者导出ONNX后用ONNX Runtime推理后面部署部分会细说。二是过滤条件中的min_w/min_h过滤很有必要监控画面里远处的人头可能在10x10像素以下这些目标即使被模型检出来置信度也很低保留它们会造成计数抖动。4.2 置信度与NMS阈值对计数的影响后处理是人群计数项目最容易被低估的部分。YOLOv5默认的置信度阈值是0.25NMS的IoU阈值是0.45这两个参数在通用目标检测里问题不大放到密集人群场景就要重新审视。密度较高时人头的检测框距离很近、甚至相互部分重叠若IoU阈值设得太大比如默认0.45在某些密集情况下会把重叠的相邻人头框强制合并NMS会把两个相邻但不重合的人头当同一个目标删掉计数结果就会偏小。我用一个实际测试过的数据举例同一张200人的密集场景图IoU阈值从0.45降到0.30计数从176变成194而误检率没有明显上升。反过来阈值太低时又会冒出大量重复框需要配合较高置信度来平衡。一般人群场景推荐这样调置信度阈值0.30~0.40之间。0.25偏低容易把背景纹理误检成人头0.5偏高遮挡和模糊目标漏检严重NMS的IoU阈值0.30~0.45之间。密度越大阈值越偏小但要靠A/B测试决定不要拍脑袋max_det默认300密集场景可以调到600~1000否则检测框数超过上限后多余的会被截断。另外视频计数里有一个常见的体验坑逐帧统计人数时单帧的误检和漏检会造成数字频繁跳动。实际项目中我习惯加一个滑动平均滤波比如取最近5帧的计数结果做平均输出到前端时数字就会平滑很多。虽然单帧响应慢了一点但用户体验完全不一样。4.3 从单帧计数扩展到实时流量统计做完了静态图片计数很多场景其实还要求动态统计比如商场出入口统计进出人数、通道双向客流、某个区域的人流量趋势图。这一步的核心是在检测的基础上加跟踪器常见组合是YOLOv5 DeepSort / ByteTrack。跟踪器给每个目标分配一个track_id这样就能跨帧跟踪同一个人再配合区域判断逻辑就可以做进出计数。这里我只提醒一个坑跟踪器的输入质量直接取决于检测器的稳定性如果你在检测阶段把置信度阈值调得很低跟踪器会产生大量碎片轨迹同一个人的id频繁跳变从而导致进出计数重复统计。所以动态统计场景下置信度阈值反而不能太低我一般用0.45以上同时把漏检问题交给检测模型本身去优化而不是靠降低阈值来补。这个思路一开始可能反直觉但实测下来对最终统计精度更友好。5. 边缘设备部署从i.MX8MP到树莓派55.1 模型导出从pt到ONNX再到量化模型训练好的模型要落地到边缘设备几乎不会直接用PyTorch的权重文件跑因为太重、环境依赖多。通用做法是先转成ONNX再根据目标设备选择进一步的转换。python export.py --weights runs/train/crowd_head/weights/best.pt --include onnx --opset 12导出时有两个参数值得关注--dynamic可以让输入尺寸动态可调但会牺牲一些性能--simplify用onnx-simplifier做图优化能在不损失精度的情况下把模型压小一点、推理快一点。导出完成后用onnxruntime在本机验证一遍中间结果确认和PyTorch输出一致再进入设备端。5.2 端侧部署的关键约束NXP i.MX 8M Plus和树莓派5是两类不同的边缘设备部署策略要分开看。i.MX 8M Plus带NPU官方标称算力在2.3 TOPS左右适合跑轻量模型常规做法是用NXP的eIQ Toolkit把ONNX模型转换成语义量化的模型再部署到NPU上跑。转换时一般要做INT8量化输入分辨率降到416甚至320这样推理帧率能到10~15FPS左右。这里要特别注意NPU跑出来的模型其输出的解码和NMS后处理通常还是在CPU上执行如果整个推理流程里这两部分处理得不够高效你会发现NPU再快整体帧率还是被CPU后处理拖住这也就是网上“imx8mp yolov5后处理”相关讨论比较多的原因。解决思路是把后处理写成向量化或SIMD友好的代码或者用NXP官方提供的后处理库而不是在Python里逐框循环做NMS。树莓派5则完全是CPU方案没有NPU可用。常见组合是树莓派5 ONNX Runtime或LiteRT模型选yolov5n或yolov5s。我实测下来yolov5s在640输入下大约只有4~6FPS把输入降到416或换成yolov5n能到10~15FPS已经能满足实时性要求。如果还需要更快还有一个思路是把后处理从Python挪到C用ONNX Runtime的C API做推理再把NMS用OpenCV自带的cv2.dnn.NMSBoxes实现整体性能会再上一个台阶。不过C工程化门槛偏高前期用Python验证业务逻辑稳定后再移植是性价比最高的路径。5.3 实测表现与部署避坑我没有跑特别严谨的benchmark只基于自己做过的几个项目给一个参考区间设备模型输入尺寸推理耗时单人帧率参考i.MX 8M PlusYOLOv5s INT8量化41660~100ms10~15FPS树莓派5YOLOv5s ONNX Runtime640150~250ms4~6FPS树莓派5YOLOv5n ONNX Runtime41660~100ms10~15FPS桌面RTX 3060YOLOv5s PyTorch64010~15ms60FPS部署时还有几个容易踩的坑。第一是视频流拉取问题用OpenCV默认的cv2.VideoCapture直接读RTSP流在设备端经常因为网络抖动导致解码线程阻塞表现为画面卡死、计数中断。解决方法是改用GStreamer管道、或者单独用一个线程拉帧并把解码后的帧放到队列里推理线程从队列取帧这样即使偶发丢帧也不影响整体。第二是内存占用树莓派5虽然内存有8G但跑ONNX Runtime加OpenCV再加上系统本身2G多内存就进去了如果同时跑多个模型或多路视频流要警惕OOM必要时用线程池限制并发。第三是模型的浮点精度量化模型在光线较暗的场景下精度衰减明显可以准备一版float16模型和一版int8模型实测对比选实际效果更好的而不是只看文件大小。我自己做部署时养成的习惯是先在设备端收集一段真实场景的测试视频离线跑一遍模型把每帧的计数结果和检测框可视化保存下来再逐帧检查漏检和误检案例。这个排查过程虽然耗时但对提升最终落地效果帮助非常大尤其能发现很多和标注、后处理相关的隐蔽问题。本文还有配套的精品资源点击获取
返回列表