简介:本资源是一套完整的基于YOLOv8的交通人群监测系统实现方案,面向深度学习初学者、计算机视觉课程设计与本科毕业设计学生,解决交通场景下行人检测、计数与实时监控等核心问题,适用于智能交通管理、公共安全预警等实际应用场景。压缩包共24个文件,含3个核心Python脚本(webcam_detect.py、image_detect.py、utils.py)、1个训练好的best.pt模型、8张标注测试图(png/jpg)、1个Jupyter Notebook实验记录、requirements.txt依赖清单及readme.md项目说明文档,整体大小25.56MB,结构清晰,覆盖数据加载、模型推理、结果可视化全流程。目前已有40人学习下载,提供可直接运行的摄像头实时检测与静态图像批量处理能力,并附带混淆矩阵、F1曲线等评估图表,便于理解模型性能与调优方向。 先说项目结论:这套“基于YOLOv8的交通人群监测”方案,我在实际项目里完整跑通过,从数据标注、模型训练、精度调优到边缘设备部署,全链路走下来大概花了两周。如果你正准备用YOLOv8做类似的人群计数、人流密度预警、交通路口分析这类需求,这篇博客应该能帮你少踩不少坑。
交通人群监测和普通行人检测不太一样,它是把目标检测算法用在真实交通场景里,比如十字路口、公交站、地铁出入口、商场广场这些地方,核心要解决的是“某个区域里到底有多少人、什么时候人流量超过阈值、人群是否出现拥堵或异常聚集”。这套东西在智慧城市项目里需求量很大:交通信号灯配时优化要看路口行人流量,地铁站需要实时预警防止踩踏,商圈需要统计客流做运营决策。
我在这套方案里选YOLOv8不是因为它“最新”,而是因为它在一众开源检测模型里,精度、速度、部署生态的平衡最稳。而且从数据标注到训练再到ONNX导出、RKNN转换,整个工具链都是现成的,不需要自己造轮子。下面我把整个设计和实操过程拆开讲,每个环节都会说清楚“为什么这么做”以及“我踩过的坑”。
1. 项目整体设计与核心需求拆解
1.1 交通人群监测和普通行人检测到底差在哪
你可能会觉得,人群监测不就是行人检测加个计数吗?实际做起来完全是两码事。普通行人检测数据集里,人通常是画面主体,数量少、尺度大、遮挡少。但交通场景的监控画面,摄像头一般架在路口杆子或者建筑高处,俯视角度下的人全是小目标,一个1080P画面里挤几十上百人太正常了,而且人挤人的时候遮挡非常严重。
我把这个项目拆解成三个核心能力:
- 行人检测:把画面里的每个行人用检测框框出来,这是基础能力。
- 人群计数:统计检测框数量,映射到实际场景后给出区域人群数量。
- 密度评估:基于检测结果进一步判断区域属于畅通、拥挤还是拥堵状态,这个需要按实际场景面积和人数设计阈值。
技术上还有一个容易被忽略的点:交通场景里行人和骑行者(骑自行车、电动车的人)经常混在一起,要不要区分?我在项目里选择把“骑行中的人”单独作为一个类别。因为从交通管理的角度,机动车和非机动车混行、行人乱穿马路是不同的安全事件,分开统计对后续应用更有价值。
1.2 为什么是YOLOv8,而不是YOLOv5或RT-DETR
先说结论:YOLOv8在“精度不输、速度够快、部署链路最短”这三点上,是最适合这个项目的。
YOLOv8相比YOLOv5有几个关键结构变化。一个是Backbone里的C2f模块替代了C3模块,它借鉴了ELAN网络的设计思路,把输入特征分流后经过多个Bottleneck串联,再把每层输出拼接起来。这样做的直接好处是梯度流更丰富,网络变深了反而不容易梯度消失,同样计算量下特征提取更充分。
另一个变化是检测头从Anchor-Based换成了Anchor-Free解耦头。分类分支和回归分支分开走独立的卷积分支,每个位置直接预测目标中心点到四条边的距离。没有Anchor的候选框预设了,也就少调一个参数,对密集小目标场景反而更友好。
还有一个设计是TaskAlignedAssigner标签分配策略,它按“分类得分预测和回归IOU的加权对齐度”来选正样本,而不是简单按IOU阈值一刀切。在人群这种目标重叠严重的场景里,这种分配方式能让回归分支学到更准确的边界。
我也对比过RT-DETR,那个模型精度确实高一截,但在边缘设备上跑起来对算力要求高,TensorRT和RKNN的适配也没YOLOv8成熟,现阶段不划算。
1.3 系统架构与数据流设计
整个系统的数据流是这样的:摄像头采集视频流 → 抽帧或直接解码 → YOLOv8模型推理得到检测框 → 后处理过滤+计数 → 按规则判断人群状态 → 联动告警或展示。
我把项目分成了四层:
- 数据层:负责采集、标注、管理图片数据,这部分看起来不起眼,但决定了模型性能上限。
- 模型层:YOLOv8模型训练、评估、导出。
- 推理层:处理视频流、执行检测、做后处理逻辑、计数。
- 应用层:告警规则、可视化界面、数据上报。
这样的分层有个好处:每一层可以独立替换。比如数据层换数据集不影响推理层代码,模型层将来升级成YOLOv11也不需要动应用层逻辑。在做项目的时候,这种解耦能省掉后面大量返工时间。
2. 数据准备与标注:交通场景定制化数据的完整流程
2.1 数据从哪来:公开数据集与自采数据组合
做交通人群监测,数据不建议只依赖单一来源。公开数据集方面,我主要用了三个:
- VisDrone:无人机视角,有大量小目标行人,和监控场景的俯视角度接近,适合作为基础数据扩充。
- CrowdHuman:密集行人数据集,遮挡情况极其丰富,是训练模型应对“人挤人”场面的关键数据。
- CityPersons:城市街景行人数据集,包含各种街道路口场景。
公开数据集有一个麻烦:标注类别和格式不统一。VisDrone的“pedestrian”和“people”需要合并成统一的person类,CrowdHuman的标注是边界框全量标注,但部分框重叠严重,需要做重合度过滤。我处理这些数据花了三天左右,比训练模型本身还久。
如果要做真正落地的交通人群监测,自采数据必不可少。方案是用手机或监控摄像头在几个核心场景采集视频,再抽帧成图片。建议按不同时间段采集:早高峰、晚高峰、平峰期、夜间、雨天,这些场景会让模型泛化能力差很多。我自己的经验是自采数据至少要有2000到3000张高质量图片,再配合公开数据集混着训。
注意:公开数据集的类别体系要和你最终需求对齐。如果公开数据里有“rider”类而你不需要,直接舍弃;如果你需要“rider”而公开数据没有对应类别,就得自己标。我最后定了两个类别:person和rider,既满足交通场景需求,也不会让分类任务过重。
2.2 类别设计与数据清洗
类别设计看起来简单,其实很考究。如果只分一个“person”,行人和骑行中的人就混在一起,统计分析维度少。但如果分太细(比如行人、骑自行车、骑电动车、骑摩托车),类别间特征混淆会非常严重,对标注量和数据量要求都剧增。我实测下来,两个类别是最务实的:
- person:步行状态的人
- rider:骑行状态下的人(车辆类型不细分)
数据清洗要做的三件事:第一是去重,公开数据集和自采数据可能存在相似图片,用感知哈希找到重复图片后删除;第二是剔除极度模糊和过度遮挡的图片,标注本身已经标了遮挡属性,但大多数标注工具导出的格式不含这个属性,只能人工扫一遍;第三步是检查类别平衡,如果rider数量只有person的十分之一,就要多找骑行场景数据,否则模型会对rider类严重欠拟合。
2.3 标注实操:遮挡与密集场景怎么标
标注工具我推荐X-AnyLabeling,开源免费,支持YOLO格式直接导出,而且内置了自动标注模型,可以先自动跑一遍再人工修正,密集场景下能省不少时间。LabelImg虽然经典,但功能还是太简陋了。
在遮挡严重的交通场景里,标注规范比工具更重要。我总结出三条原则,团队标注前必须先对齐:
第一,紧密围绕可见主体画框。如果一个人被杆子挡住一半,框只包住可见部分,不要脑补完整的身体轮廓。为什么?因为模型训练时看到的就是画面里的像素,你标了个包含大量背景的框,会让模型学成“看到一个杆子也框人”。
第二,漏标比错标危害更大。密集场景里,漏标一个人会导致模型认为“人不完整也可以不算人”,错标顶多产生一两个噪声样本。所以人再多也宁可慢一点,尽量不要漏。
第三,多人交错的框采用分割线原则。两个人紧紧靠在一起时,如果一个人挡住另一个人大半身体,就按可见部分分两个框,一定不要把两个人框成一个框。
标注完成后导出YOLO格式,每个标注文件是txt,每行格式是:类别ID x_center y_center width height,坐标都是归一化到0到1之间的值。
2.4 数据集划分与增强策略
数据划分上,我按8:1:1拆成训练集、验证集和测试集。但有一个关键细节:一定要按场景划分,不能按图片随机划分。什么意思?如果同一个摄像头同一个时间段产生的连续帧,一部分进了训练集一部分进了测试集,测试集就形同虚设,模型“背题”了。我把同一场景的图片全部归到同一个集合里,确保测试集是模型从未见过的场景。
增强策略方面,YOLOv8内置了挺强的数据增强,开箱即用。Mosaic把四张图拼成一张训练,对密集小目标帮助很大;MixUp两图叠加混合标签,能提升泛化能力;HSV扰动模拟不同光照条件,对交通场景的日夜变化很重要。
我自己还会加一个自定义策略:随机裁剪增强。因为监控画面里的人群经常集中在某个区域,整图缩放后目标太小,用随机裁剪模拟“镜头拉近”的效果,可以帮模型适应中等尺度的目标。
3. 环境配置与模型训练:从零跑通YOLOv8
3.1 环境配置清单与显卡优化
YOLOv8的环境配置本身不复杂,但版本兼容性是个坑。我的推荐组合是:
- Python 3.9或3.10
- PyTorch 2.0.1或以上,CUDA 11.8
- ultralytics 8.1.x(版本锁定很重要,新版本API变动频繁)
安装其实一行命令:pip install ultralytics。它会自动带上PyTorch相关依赖。但如果你要自己控制PyTorch版本,建议先装好PyTorch再装ultralytics,避免它自动装个不匹配的版本。
如果你用的也是GTX 1660Ti这种6GB显存的卡,有几个优化技巧值得记一下。第一,训练时一定要开AMP(自动混合精度),ultralytics默认会开,半精度训练能明显降低显存占用,速度还快一些。第二,workers线程数可以调到4或者8,配合pin_memory=True,让GPU在等数据的时候不闲着。第三,如果batch_size起不来,用梯度累积技术,效果上相当于变相增大了batch。
实测下来,GTX 1660Ti在640分辨率下训练YOLOv8s,batch_size=16可以稳定跑,显存占用大概在5GB出头。如果调成1280分辨率,batch只能开到8左右。
3.2 预训练权重与超参数选择
训练用预训练权重还是从头训?我强烈建议用COCO预训练权重。YOLOv8官方提供的yolov8s.pt已经在COCO数据集上训过一轮,学到了通用的特征表达。我们项目数据量就几千张,从头训很容易不收敛或者过拟合,用预训练权重微调是正解。
超参数方面给出我调试后比较稳定的组合:
| 参数 | 值 | 说明 |
|---|---|---|
| model | yolov8s.pt | 用s版本性价比最高 |
| epochs | 100 | 这个量级够了 |
| batch | 16 | 6GB显存上限 |
| imgsz | 640 | 小目标多可调至960 |
| optimizer | SGD | AdamW收敛快但泛化弱 |
| lr0 | 0.01 | SGD的基准学习率 |
| cos_lr | True | 配合余弦退火效果更好 |
| patience | 20 | 早停机制防过拟合 |
| amp | True | 混合精度 |
| mosaic | 1.0 | 默认开 |
| mixup | 0.1 | 适当开启 |
| val | True | 边训练边验证 |
这里有个细节:为什么不直接用AdamW?我在实际对比中发现,SGD配合余弦退火,虽然前期收敛慢一点,但最终的mAP通常会比AdamW高0.5到1个点,而且不容易过拟合。AdamW更适合目标函数复杂的场景,或者在调参阶段快速探索的时候用。
3.3 训练实操与日志指标解读
训练命令很简单,在已经配置好的环境里执行:
yolo detect train data=traffic_dataset.yaml model=yolov8s.pt epochs=100 batch=16 imgsz=640 optimizer=SGD lr0=0.01 cos_lr=True amp=True其中traffic_dataset.yaml需要自己定义,内容包括数据集路径、类别数量和类别名称。
训练日志里最关键的几个指标:P(precision)是精确率,R(recall)是召回率,mAP50是IOU阈值0.5下的平均精度,mAP50-95是不同IOU阈值的综合平均精度。对于人群检测这个任务,我第一优先看recall,人群遮挡严重时漏检的安全风险比误检更大。训练结束前,recall能到0.85以上就算合格,mAP50做到0.75以上基本可上线。
训练过程中最需要盯的是val曲线。如果train loss持续下降但val loss先降后升,说明模型开始过拟合,这时候就需要回退到val loss最低的权重,或者用更早的epoch。ultralytics默认会保存best.pt和last.pt两个权重,最好用best.pt做推理。
3.4 损失函数曲线可视化:别只盯着一张图
很多新手问损失函数曲线在哪看。ultralytics训练完会在runs/detect/train目录下生成results.png,里面包含了train/box_loss、train/cls_loss、train/dfl_loss和val对应的指标曲线,基本够用。
但如果想更精细地观察训练过程,建议开TensorBoard。训练前在环境变量里设置:
export ULTALYTICS_TENSORBOARD=true或者在代码里加上回调参数,训练时就能在TensorBoard上实时看loss曲线和各指标曲线。
我自己还会用matplotlib把每次训练的平均loss画出来对比,尤其是做消融实验时,多个训练项目的曲线放在一起,能明显看出哪些改动有效果、哪些改动反而让loss更差了。做法很简单,训练日志里每行都有loss值,提取出来画即可。
3.5 显存不足的五种自救方案
显存不足是这个项目里最常遇到的问题,尤其用消费级显卡训练。我从实际情况出发整理五种方案,按优先级排列:
第一,先降batch_size再降imgsz。batch降到8还不行再考虑imgsz降到480或512。降低imgsz牺牲的是小目标检测能力,影响比降batch严重。
第二,开启梯度累积。代码里通过参数gradient_accumulation控制,batch=4加gradient_accumulation=4,效果相当于batch=16,显存占用却只有原来的四分之一。
第三,开启AMP混合精度。默认是开的,如果你的训练命令里之前关了,一定加回去。
第四,用缓存数据集方式,把数据提前加载到内存,省掉GPU在数据加载上的等待时间,间接提高训练效率。
第五,把模型换小。如果后续还要迭代,先用yolov8n跑通流程,验证数据集和标注没问题,再用s版本正式训练。模型大小不是问题,流程跑通才是关键。
4. 模型评估、性能优化与边缘部署
4.1 评测不止看mAP:混淆矩阵与recall策略
训练完第一件事不是看mAP,而是看混淆矩阵。ultralytics在训练目录里会生成confusion_matrix.png,它展示每个类别被预测成其他类别的比例。我第一版模型在rider上的召回率明显偏低,查了混淆矩阵发现大量rider被预测成了person,原因就是两类在俯视角度下从外观上确实容易混淆。
解决这个问题有两个思路:一个是在数据层面多补充骑行者场景的图片,尤其是电动车和自行车在一起的情况;另一个是增强后处理,比如rider和person的检测框如果重叠度很高且一个是person一个是rider,可以结合目标的宽高比做二次判断。
交通场景对召回率要求高,我的策略是把推理的conf阈值压低到0.25(默认是0.25),NMS的iou阈值从0.7降到0.5。这样虽然会让一些低置信度的误检混进来,但换来的是漏检大幅减少,再配合按区域人数设定告警阈值,误检的影响可以被上层规则消化掉。
4.2 密集人群推理的后处理调优
推理层面的后处理参数对结果影响很大。YOLOv8默认conf_thres=0.25、iou_thres=0.7,在密集人群场景我会做调整。
conf_thres降低到0.2甚至0.15后,检测框数量会增加不少,这时NMS的iou_thres反而要适当调低到0.5,让重叠度高的重复框被抑制得更狠。同时要留意max_det参数,默认是300,密集场景下框数量经常超过1000,需要把max_det调到1000以上,否则人数统计会偏少。
还可以开启agnostic_nms,它让所有类别放在一起做NMS,而不是每个类别单独做。在person和rider这类容易互相重叠的类别场景下,能减少重复框。
如果精度还是不够,可以开启TTA(Test Time Augmentation),通过水平翻转等多重增强推理后融合结果。这个会降低推理速度,边缘设备上一般不推荐,但服务器端做离线分析时很好用。
4.3 注意力机制改进与轻量化:什么时候该做
这个话题要泼点冷水。我在做项目时发现,网上大量“YOLOv8改进”相关的内容,比如给C2f模块融入ECA注意力、EMA注意力等,效果在实际交通场景里可能只提高0.1到0.3个mAP,但训练时间和调试成本却增加不少。
我的建议是:先跑通基线,确认模型在目标场景的精度瓶颈在哪里,再决定要不要做结构性改进。如果模型在白天高密度场景已经85分,晚上低照度场景只有50分,这时候加注意力模块不如去补夜间数据。注意力机制能帮助模型关注重点区域,但解决不了数据本身的分布问题。
如果确实要做改进,ECA注意力融入C2f是个相对轻量的选择,它只增加少量参数,对推理速度影响小。EMA注意力机制对密集小目标有一定帮助,但会明显增加计算量,边缘设备上要谨慎。改进时要做好消融实验:基线模型跑一遍,改进模型跑一遍,其他条件完全一致,最后对比mAP和速度。没有这种对比,改来改去很容易被“感觉好了”误导。
4.4 rk3588等边缘设备的部署流程
项目要落地,部署这步躲不开。我以rk3588为例,这个芯片在边缘设备里性价比很高,6 TOPS的NPU算力,跑YOLOv8s量化后能做到实时。
部署流程大致是:训练好的模型先导出成ONNX,再通过RKNN-Toolkit2转换成rk3588专用的RKNN格式。转换时有几个注意点。第一是版本匹配,RKNN-Toolkit2和rk3588的固件版本必须对应,不然转换后模型可能加载报错。第二是量化数据集,转INT8量化时需要一个校准数据集,一般准备200到500张代表性图片,覆盖不同时段和场景的光照条件。量化后的精度损失如果不大于2%到3%,属于正常范围。
如果部署到Jetson系列设备,直接用TensorRT加速即可。YOLOv8的ONNX导出后,用trtexec工具转成engine,FP16精度损失小,速度提升明显。无论是RKNN还是TensorRT,输入输出格式都变了,后处理代码也要跟着适配。
嵌入式端的C语言后处理,核心是解析模型输出。YOLOv8经过onnx导出后,输出张量通常是[1, 4+num_classes, 8400]这种格式(640输入下),每个目标包含边界框坐标、类别得分。C语言的输出结构体可以这样定义:
typedef struct { float x1, y1, x2, y2; float score; int class_id; } DetectResult;后处理把模型的输出逐列解析,经过conf和NMS筛选后填充到结构体数组里。
4.5 项目交付物清单:一个完整zip包该有什么
这个项目命名为“基于YOLOv8的交通人群监测设计.zip”,那交付物就该对得起这个名字。我梳理了一个完整项目包的文件结构:
- data/:数据集配置文件和标注说明
- models/:训练好的best.pt权重、ONNX文件、RKNN文件
- scripts/:训练脚本、评估脚本、推理脚本
- docs/:项目说明文档、数据标注规范、部署手册
- results/:训练日志、指标曲线图、混淆矩阵
实测下来,一个能复现的项目包,别人拿到后按文档操作,能在三个小时内把模型跑通、复现出主要结果。达到这个标准,说明结构和文档是合格的。
5. 高频问题排查与避坑速查表
5.1 典型问题速查表
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 训练时OOM | batch过大、imgsz过大 | 降batch、降imgsz、开AMP、梯度累积 |
| loss持续为NaN | 学习率过高、数据含异常标注 | 降低lr0、清洗NaN坐标标注、调小样本 |
| mAP很低 | 标注质量差、类别不平衡 | 抽检标注、补数据、统一标注规范 |
| train loss下降但val loss不降 | 数据分布差异大、过拟合 | 增加数据多样性、打开mixup、早停 |
| 小目标完全检测不到 | 输入分辨率太低、下采样丢失信息 | 调大imgsz、开启TTA、考虑加P2检测头 |
| 部署后精度比训练时下降 | 量化精度损失、预处理不一致 | 检查归一化参数、重做量化校准集 |
| 同一目标出现多个框 | NMS阈值不合适 | 调低iou_thres、开启agnostic_nms |
5.2 训练不收敛的排查顺序
遇到loss不下降或者震荡时,我建议按顺序排查,而不是乱调参。
第一步先确认数据标注没问题。随机抽取200张训练图片,用X-AnyLabeling打开看一眼,标注框是否紧贴目标、类别是否正确、是否有大量漏标。很多时候模型训不好不是因为网络问题,而是数据本身有脏东西。
第二步确认数据增强参数是默认值。有人为了追求多样性把Mosaic和MixUp调到很高,结果训练前期loss波动巨大,看起来像不收敛,实际上是增强强度过大数据太“难”了。
第三步检查学习率。SGD的lr0从0.01往下降,二进制搜索调试:如果loss完全不降,试试0.001;如果loss下降又飙升,可能是lr太高。这一步是最耗时间的,但也是最有效的。
第四步看验证集指标。如果valid的mAP一直在上升,只是慢,那就不叫不收敛,而是训练时间不够,把epochs和patience调大。
5.3 小目标漏检的处理思路
交通监控场景里小目标漏检是最大痛点,我的经验是按这个顺序处理:
先调大imgsz。把640改成960或1280,是提升小目标检测最直接有效的方法。代价是训练变慢、显存变多,所以要先确认算力够不够。
再加TTA推理。这个方法不需要重新训练,只是推理时多几次翻转和缩放,小目标检出的稳定性会明显提高,适合在非实时要求的场景用。
最后考虑结构改进。如果前两步都不够,再考虑给检测头加P2层(高层特征图)或者引入注意力机制。但这一步一定要基于前面的消融实验,不要盲试。
5.4 部署精度下降的排查方向
训练好的模型转成RKNN或TensorRT后精度掉了,基本上逃不出这几个原因:
量化校准集没有代表性。校准集应该覆盖待部署场景的真实分布,如果只放了白天数据,部署到夜间的摄像头就会掉点。校准集里白天、夜间、黄昏各放一部分。
预处理不匹配。训练时的归一化是除以255,部署时有些框架的预处理已经做了归一化,你再归一化一次就会输入分布偏移。务必检查两边输入像素范围是否一致。
后处理参数不一致。训练时验证用的conf和iou阈值,部署时如果改变了,效果会有波动。我见过有人训练用conf=0.001做mAP评估,部署时用conf=0.25,然后觉得精度掉了,其实是自己改了配置。
6. 项目复盘与下一步扩展思路
这套交通人群监测系统跑通之后,我最大的感受是:模型训练只是项目的一小部分,数据和部署才是真正花时间的地方。数据决定精度上限,部署决定你能否把精度变成实际价值。
后续扩展的话,我建议优先做两个方向。
第一个是追踪,在检测基础上接入ByteTrack或多目标跟踪算法,这样统计到的就不是瞬时人数,而是这个摄像头一天经过了多少人流量。这对商圈的客流统计、路口的人流潮汐分析更有商业价值。
第二个是密度估计。YOLOv8检测框天然可以转成密度图,对每个检测框中心点做高斯热力渲染,就能得到人群密度热力图。引入密度图比单纯计数更能表达“拥堵”状态,例如检测到100个人但分散在四个角落,和100个人挤在一个电子屏幕前面,安全风险完全不一样。
最后再说一个我非常主观但实用的经验:网上各种眼花缭乱的YOLOv8改进模块,如果时间和算力有限,先别追。把一个标准的YOLOv8在目标场景上做透,数据、标注、后处理、部署都调到最优,效果绝对能超过90%的“魔改”版本。先把地基打牢,再谈改进。
本文还有配套的精品资源,点击获取