ARTICLE DETAIL

资讯详情

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

YOLOv5+DeepSort实现车流量统计:从训练到部署全攻略

YOLOv5+DeepSort实现车流量统计:从训练到部署全攻略 简介基于YOLOv5与DeepSort的车流量统计算法项目实战资源面向算法工程师和计算机视觉开发者适用于密集车流场景下的车辆检测、跟踪与计数可支撑智慧交通、城市监控等方向的算法研究与二次开发。资源压缩包共117个文件总大小约79.17MB主要包含Python源码、YAML配置、模型权重、演示视频、Shell脚本以及Docker部署文件覆盖从模型推理到环境搭建的关键环节。目前已有288人学习浏览适合用于课程设计、毕业设计或项目落地的参考方案。压缩包内还配有使用手册、GIF效果图和多种辅助配置便于快速理解目录结构与代码逻辑借助演示视频和预训练权重可直观复现车流量统计过程并在此基础上扩展多车道计数、车速分析等功能。1. 车流量统计不是数框是把每一帧的“它”认成同一个“它”早高峰路口一辆公交车刚驶过后面的轿车被挡了大半个车身。如果只依赖目标检测这一瞬间轿车框可能消失下一秒又重新出现计数就会从一辆变成两辆。车流量统计算法的核心问题不是“这一帧有几个车框”而是“这一个车框和上一秒那个车框是不是同一辆车”。用YOLOv5负责每帧找出车辆位置用DeepSort把这些框串成带ID的轨迹才能回答“这条路一小时到底过去了多少辆”这种问题。这里按一条完整落地路径来写从yolov5环境配置、yolov5训练自己的数据集讲到车流量统计实现和密集车流下的参数调试目标是让你照着能复现一套自己的车流量统计算法。2. 检测器负责看见跟踪器负责记住YOLOv5DeepSort的角色拆分先建立整体印象整条链路里YOLOv5和DeepSort各干一件事。YOLOv5目标检测负责在当前帧里找出所有车辆框DeepSort负责判断上一帧的某个框和这一帧的某个框是不是同一辆车。两个角色配合起来才是真正的车流量统计而不是简单的“数框”。下面把两个角色分别拆开讲最后再讲它们怎么对接。2.1 先看懂YOLOv5目标检测的输出yolov5后处理不能跳YOLOv5是单阶段检测器输入一张任意分辨率的图内部先缩放到模型输入尺寸经过骨干网络提取特征再由检测头输出三个尺度的预测结果。严格来说这三个尺度的原始输出还不是“框”它是对每个候选位置的一组偏移量、目标度评分和类别评分。要得到最终能用的xyxy框必须经过坐标解码、置信度过滤、类别的非极大值抑制NMS这几个步骤。整套流程合起来就是常说的yolov5后处理。很多从分类任务转过来的人会把模型输出的张量直接理解成“目标位置”从而跳过NMS或者自己写一个简化版本。结果就是跟踪器拿到的框一会儿抖一下一会儿重叠DeepSort的卡尔曼滤波被噪声带着跑计数自然也稳不住。正规做法是直接用yolov5源码仓库自带的推理逻辑或者用torch.hub加载官方封装好的模型。我一般这样写import torch # 加载COCO预训练权重yolov5s是速度和精度相对均衡的版本 model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.classes [2, 3, 5, 7] # 只保留car、motorcycle、bus、truck # frame是BGR格式的numpy数组 results model(frame) dets results.xyxy[0].cpu().numpy() # [x1, y1, x2, y2, conf, class]model.classes指定只输出COCO的这几个车辆类别。注意COCO的IDcar2motorcycle3bus5truck7。如果只统计小汽车和卡车就改成[2, 7]。xyxy里的坐标是原图像素坐标不是归一化值这对DeepSort很重要。conf列是置信度后面要用来过滤。这段代码后还需要设置模型推理的置信度和NMS参数。torch.hub方式默认是640分辨率如果你觉得小目标太多可以显式设置model.conf 0.1 # 检测置信度阈值密集车流调低 model.iou 0.45 # NMS的IoU阈值 model.classes [2, 3, 5, 7]model.conf是yolov5后处理的第一个门槛。密集车流里因为遮挡、模糊很多真实车辆的置信度只有0.20.3默认的0.25会把它们过滤掉。我会把model.conf降到0.1甚至0.08让检测器“多召回”。多召回带来的误检则交给DeepSort的n_init去过滤。model.iou一般不动NMS的IoU阈值太高反而让两个重叠框都保留跟踪器会以为多出一辆车。2.2 DeepSort跟踪的核心运动预测、外观特征与级联匹配DeepSort是在SORT基础上的改进。SORT只靠卡尔曼滤波预测框的位置和大小用IoU做帧间匹配速度快但车辆换道、遮挡后ID容易丢。DeepSort增加了一个外观特征提取分支对每个检测框裁剪出图像送入一个小型ReID网络得到128维或512维特征向量。匹配时不再是只比IoU还会比外观特征的余弦距离这就是“deepsort改进”里最常见、也最核心的一环。密集车流场景里单独的卡尔曼滤波预测很容易被旁边车辆的轨迹干扰而外观特征可以分辨“这是一辆白车不是那辆黑车”。所以DeepSort的适用场景正好匹配车流量统计车辆种类多、外观差异大、局部遮挡频繁。它的匹配流程是级联的优先匹配连续命中且置信度高的轨迹再把剩余检测和轨迹做IoU加外观的联合匹配。如果一辆车被挡了好几秒轨迹处于“已丢失但暂存”状态等到重新出现只要外观距离够近还能接回去。我常用的DeepSort初始化参数如下deepsort DeepSort( model_pathreid/ckpt.t7, # ReID特征模型权重常见做法是用Market1501预训练 max_dist0.3, # 外观特征余弦距离阈值 max_age70, # 轨迹在丢失状态下的最大存活帧数 n_init3, # 新轨迹需要连续命中几帧才确认 nn_budget100 # 外观特征库的容量上限 )max_dist越大越能容忍车辆外观变化比如车身反光、进入阴影但两辆相似的颜色车型也可能被当成同一辆。max_age是密集车流最值得调的参数默认30帧大约对应1秒30fps大车遮挡常常超过这个时间所以我会调到70甚至100。nn_budget是给每个轨迹保存的历史特征数量越大越能适应外貌变化但特征比对的计算量也会上升。这几个参数不是玄学不同摄像头视角、车速、车流密度最优值都不一样建议在验证集上扫一遍。2.3 检测与跟踪怎么协作先过滤类别再统一坐标整个流程可以压缩成三步第一步YOLOv5对当前帧做推理得到若干车辆框第二步把车辆框和置信度传给DeepSort的update第三步DeepSort返回带轨迹ID的框。注意DeepSort的输入不是“整张图”这么简单它需要检测框集合加当前帧图像因为内部要用检测框去ReID网络里提特征。写成代码是这样的# 过滤掉低置信度的检测只保留x1,y1,x2,y2,conf mask dets[:, 4] 0.3 detections dets[mask][:, :5] # 传入检测结果和原始帧返回带ID的跟踪框 outputs deepsort.update(detections, frame) for x1, y1, x2, y2, track_id in outputs: pass这里过滤阈值写0.3实际项目里我在检测端已经设了model.conf0.1到跟踪这一段不会再加高阈值最多用0.3过滤一下尾迹。outputs返回的框是跟踪器根据卡尔曼滤波和外观匹配修正过的比原始检测框抖动小。一个最容易翻车的点传给DeepSort的坐标必须和输入帧的尺寸一致。如果你在调用YOLOv5前对帧做了resize那检测框是基于resize后的尺度算出来的必须再映射回原图尺度再传给DeepSort。否则卡尔曼滤波的观测值和图像空间对不上跟踪框会漂到错误位置。另一个点是DeepSort不要求检测置信度筛选严格因为它有n_init机制一个闪烁的假框要连续出现3帧才会被确认为轨迹所以宁可让检测端多输出一些候选。用纯检测做计数本质上就是每帧统计框数然后做去重这在车流稀疏时勉强能用一到密集场景一个框被遮挡后消失再出现就会被记为两辆车。而ByteTrack这类纯运动跟踪器不利用外观特征车辆互相靠近时也容易换ID。DeepSort的特性决定了它更适合“车流量统计”这种需要较长时间保持身份的落地任务。3. 从零搭环境到训练自己的YOLOv5模型conda、数据与超参数有一类项目是直接用COCO预训练的yolov5s来跑车流量统计也能出结果。但真实路口往往有卡车、三轮车、交通差异大的车辆类型或者你想只统计某一类车这时就需要yolov5训练自己的数据集。这章按“环境-数据-训练-验证”的完整链路走一遍。3.1 conda创建yolov5环境别让依赖版本变成第一个翻车点很多人在“yolov5环境配置”上耽误的时间比写算法还多。最常见的坑是torch和CUDA版本不匹配或者conda和pip混着装依赖导致torch.cuda.is_available()返回False。我一般用conda管python版本用pip管torch和yolov5依赖两者分开。conda create -n yolov5 python3.8 -y conda activate yolov5 # 先装PyTorch根据你的CUDA驱动选择合适的版本 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再进yolov5源码目录装其他依赖 cd yolov5 pip install -r requirements.txtpython版本选3.8是为了兼容ReID相关的一些老依赖。如果你用的是更新的yolov5分支3.10也可以但别直接用3.12有些编译型依赖会翻车。requirements.txt里包含numpy、opencv-python、matplotlib、pyyaml等装完后先跑一行python -c import torch; print(torch.__version__, torch.cuda.is_available())如果输出False优先检查驱动。用nvidia-smi看驱动支持的最高CUDA版本然后选择对应的cu118或cu121t的torch安装命令。如果机器只有CPU就直接装CPU版torch后面训练慢一些但也能跑通流程。3.2 构建自己的车辆数据集标注格式、目录结构与data.yamlYOLOv5训练自己的数据集要求的格式是“每张图对应一个同名txt文件”。txt的每一行表示一个目标类别ID、归一化中心x、归一化中心y、归一化宽、归一化高。注意是归一化的中心点坐标不是左上角坐标也不是像素值。标注工具常见的是LabelImg或AnyLabeling导出为YOLO格式即可。目录结构我一般这样建datasets/traffic/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ └── data.yamlimages和labels文件夹下分别有train和val文件名一一对应。如果某个图片没有目标对应的txt是空文件但文件必须存在否则训练时会报错。data.yaml的内容如下path: ../datasets/traffic train: images/train val: images/val nc: 4 names: [car, truck, bus, motorcycle]path字段我习惯写成相对路径相对于运行train.py的目录。如果写成绝对路径换一台机器就要改。类别顺序一旦确定就不要在训练中途调整否则label的ID对不上。类别数量建议限制在5类以内车流量统计场景里car、truck、bus、motorcycle就够别把“行人”混进来会严重干扰车辆计数。标注时不要把远处极小、只有几个像素的车辆也标成框因为训练时会生成大量低质量先验反而拉低整体精度。我一般只标注最大边超过20像素的车辆。对于被遮挡超过三分之一的车辆如果还能明确判断车型照样标注这对密集场景很重要如果完全看不清类别宁可不标也不要错标。3.3 调yolov5超参数模型选型、图像尺寸与训练命令训练前先选择模型。yolov5n、yolov5s、yolov5m、yolov5l、yolov5x五个尺度的参数量递增。密集车流项目里我一般起步用yolov5s因为它的精度和速度都居中。如果目标是树莓派或者边缘盒子用yolov5n如果机台显存充足且要极致精度用yolov5m。训练命令python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --hyp hyp.scratch-low.yaml --device 0几个关键参数的含义--img是训练时的输入尺寸640是基准。如果你的数据里小目标多比如远距离的摩托车改成960会明显改善召回率但显存占用增加约2倍。--batch受显存限制16G显存跑yolov5s640一般只能到16或32如果batch不够大可以用--accumulate 2开启梯度累积等效扩大batch。--hyp指定超参数文件yolov5自带hyp.scratch-low.yaml里面包含学习率、数据增强强度等。下面是几个和密集车流关系最密切的yolov5超参数我一般会这样调超参数默认值low密集车流建议理由lr00.010.010.005数据少时调低防止过拟合mosaic1.0保持1.0拼接增强能提高被遮挡车辆的感知fliplr0.50.0左右翻转会让“右侧通行”的车变成“左侧通行”破坏方向语义scale0.50.8更强的尺度变换模拟远近变化fliplr这个点容易被忽略。车流量统计往往依赖车辆行驶方向左右翻转后会改变车道位置和方向导致后来做跨线计数时方向判断紊乱。如果数据量充足我建议fliplr0。3.4 用val.py验证、用export.py导出把部署风险提前暴露训练完成后先用val.py看指标不要急着部署python val.py --data data.yaml --weights runs/train/exp/weights/best.pt --img 640输出里重点看 mAP50 和 mAP50-95。mAP50是IoU0.5时的平均精度对车辆检测来说达到0.8以上基本可用mAP50-95更严格低于0.5说明模型对遮挡和重叠的泛化一般。还可以看per-class指标如果某个类别AP特别低通常是数据量不足或标注框太小。部署前导出模型。yolov5的export.py可以把训练好的权重转成torchscript、onnx、tensorrt engine等格式python export.py --weights runs/train/exp/weights/best.pt --include torchscript onnx --device 0导出onnx后在PC上先跑一遍再移植到边缘设备不要等到部署平台发现算力不足才回头优化。这一步就是“yolov5部署”的起点。如果树莓派要用建议导出onnx再用NCNN工具链转成ncnn格式比在树莓派上直接跑PyTorch快一个量级。后面第6章再展开。4. 车流量统计核心实现跨线计数、ID去重与结果落盘前面训练好模型只是第一步。这章把YOLOv5DeepSort真正接到视频上实现车流量统计算法的本体。我会给出一段能在本地跑通的主循环代码再讲计数策略为什么这么设计。4.1 主循环把YOLOv5和DeepSort接进一段可跑的视频处理代码常见做法是用OpenCV读视频逐帧处理。核心流程写在下面假设已经安装好torch、cv2和一个DeepSort的Python实现开源项目里通常叫deep_sort_pytorch。import torch import cv2 import numpy as np from deep_sort_pytorch.deep_sort import DeepSort # 1. 初始化检测器COCO预训练yolov5s只保留车辆类 model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.classes [2, 3, 5, 7] model.conf 0.1 # 检测阈值调低适应遮挡 # 2. 初始化跟踪器ReID权重用常见ckpt.t7 deepsort DeepSort( model_pathdeep_sort_pytorch/deep_sort/deep/checkpoint/ckpt.t7, max_dist0.3, max_age70, n_init3, nn_budget100 ) # 3. 计数线一条横向直线y坐标在画面中下位置 LINE_Y 500 count 0 passed_ids set() # 已经越过计数线的车辆ID cap cv2.VideoCapture(traffic.mp4) while True: ret, frame cap.read() if not ret: break # 4. 目标检测 dets model(frame).xyxy[0].cpu().numpy() mask dets[:, 4] 0.3 detections dets[mask][:, [0, 1, 2, 3, 4]] # x1,y1,x2,y2,conf # 5. 跟踪更新 outputs deepsort.update(detections, frame) # 6. 计数用跟踪框的底边中心点是否跨过LINE_Y for x1, y1, x2, y2, track_id in outputs: bottom_y int(y2) if bottom_y LINE_Y and track_id not in passed_ids: passed_ids.add(track_id) count 1 # 7. 可视化 cv2.putText(frame, ftotal: {count}, (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow(traffic, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码已经把车流量统计的最小闭环跑通。逻辑上要注意几点检测器输出的是多个框每个框有置信度跟踪器输出的是带ID的稳定框计数发生在跟踪之后而不是检测之后。bottom_y用的是跟踪框的下边沿比中心点更接近车辆压线的真实时刻。参数说明model.conf0.1是密集车流下为了召回遮挡车辆而调低的max_age70是为了让被挡住的track能在消失后尽量续上LINE_Y不是随便选的。理想位置是靠近画面下方、不贴住画面边缘并且避开车辆频繁变道的区域。如果计数线离画面底部太近车辆刚进入画面就可能触发跟车辆实际到达“统计断面”不一致如果太靠上又容易在远处还没分清车道时就触发。另外视频帧率不稳定也会影响DeepSort的卡尔曼滤波。如果摄像头是15fps或25fps混用max_age的帧数意义就变了。跑长视频时建议先把时间戳对齐或者统一抽帧策略否则同一辆车在慢帧率下更容易丢ID。4.2 计数策略为什么推荐“跨线ID去重”而不是ROI内计数另一个常见做法是画一个矩形区域ROI检测到车辆进入ROI就计数一次。但ROI内计数有个致命问题同一辆车在区域内会持续存在多帧如果不维护已计ID集合就会重复计数。如果用IOU去重车流密集时框和ID重叠又会误删。我更推荐“跨线ID去重”定义一条或多条虚拟计数线车辆跟踪框的某个关键点比如底边中点从线的一侧运动到另一侧时才计数一次。这样一辆车在整个视频生命周期内只可能被计数一次因为全局去重的passed_ids会挡住重复触发。下面是两种策略的对比策略优点密集车流下的缺点ROI内计数直观、代码简单同一辆车在多帧驻留容易重复计数跨线ID去重计数时机明确天然去重需要处理ID跳变否则一辆车可能算两次这里还有一个容易被忽略的细节计数线的方向性。如果只统计“驶入”的车辆需要判断车辆移动方向。可以通过比较当前帧与上一帧的底边中心点坐标实现如果center_y从小于LINE_Y变成大于LINE_Y才触发计数。上段代码里没有判断方向只是判断bottom_y LINE_Y对于不分方向的总流量是可以的但如果你想单独统计“上行”和“下行”就必须加方向判断。4.3 按车道和方向统计从单一计数线到多车道聚合实际交通场景通常需要按车道统计。一个简单做法是在图像里为每条车道定义一条独立的计数线段并让车道线覆盖整个画面宽度。比如三条车道就定义三条计数线LINE_Y1400,LINE_Y2500,LINE_Y3600然后根据车辆框中心点x坐标落在哪个区间分配到对应车道的集合。方向判断则用“上一帧位置-当前帧位置”track_history {} # track_id - (last_center_y, direction) for x1, y1, x2, y2, track_id in outputs: center_x (x1 x2) / 2 center_y (y1 y2) / 2 if track_id not in track_history: track_history[track_id] (center_y, 0) else: last_y, _ track_history[track_id] direction center_y - last_y # 正数表示向下运动 track_history[track_id] (center_y, direction)注意如果直接按帧差判断方向车速慢的时候中心点可能抖动导致方向错误。更稳的做法是维护最近N帧的位置缓存用平均位移判断方向。密集车流里车辆走走停停单帧位移可能为0这时候要看连续几帧的累计位移。4.4 统计结果落盘把每辆车的事件写入CSV只输出一个总数不够审计和后续分析都需要明细数据。我会在计数触发时把事件写入CSV字段包括时间戳、车辆ID、所属车道、方向、类别。DeepSort输出的track_id是特征级的和车辆类别无关所以如果想记录类别需要把YOLOv5检测的类别和track_id对应起来。常见做法是用DeepSort update返回的框与当前帧检测框中IoU最大的那个框的类别作为该track的类别。import csv from datetime import datetime with open(log.csv, a, newline) as f: writer csv.writer(f) writer.writerow([datetime.now().isoformat(), track_id, lane, direction, cls])写入CSV时注意两点一是只在计数触发瞬间写不要每帧都写否则文件会爆炸二是每条记录配上视频帧号方便回溯。如果视频有20万帧CSV里应该只有几百行事件记录这才叫“车流量统计结果”而不是“检测日志”。5. 密集车流场景的避坑指南漏检、ID跳变与计数重复的现象和处置这一章是密集车流项目里最花时间的部分。模型在公开数据集上AP再高放到真实路口也会冒出一堆现象。以下五条是我在各路况视频里踩过的坑每条按“现象→原因→解决”来写。5.1 大车遮挡导致漏计数车都没看见怎么谈跟踪现象视频里一辆大货车从画面右侧驶过后面紧跟着一辆白色轿车。白色轿车完全被挡住持续约2秒。最后统计总数比人工数少了1辆。原因YOLOv5是单帧目标检测看不到就没有框DeepSort只能依靠卡尔曼滤波预测位置但预测时间越长误差越大超过max_age轨迹就被删除等白色轿车重新出现时只能作为新目标ID变了漏计数。解决三件事配合。第一把检测置信度阈值降到0.1让被挡住半个车身、置信度低的框尽量出来。第二把DeepSort的max_age调大到70或100给轨迹更长的“失联容忍时间”。第三训练时加入mosaic增强和random erasing模拟局部遮挡让检测器对“只露出一个车角”的情况更敏感。5.2 ID跳变导致重复计数一辆车成了两辆车现象同一辆黑色SUV在连续变道过程中track_id从12跳到23计数器先加1过一会又加1最终统计数量超过实际车流。原因DeepSort在密集场景里如果两辆车外观接近ReID特征距离可能小于max_dist匹配矩阵产生歧义。当目标发生遮挡或快速变道时卡尔曼滤波的预测位置偏差变大级联匹配失败就会开一条新轨迹。解决先尝试调参数把max_dist从0.2提高到0.3让外观匹配更宽松把nn_budget从30提高到100让轨迹保留更多历史特征。如果还不行就需要做deepsort改进用一个更强也更轻量的ReID网络替换默认的ckpt.t7或者在匹配阶段加入运动方向一致性的约束。注意调参能改善但不能根治密集车流里ID切换是概率性事件最终要靠“跨线方向判断触发区域”的去重逻辑兜底。5.3 计数线触发时机不准中心点过线不等于车辆压线现象一辆车还没到路口停车线计数器已经1或者一辆车已经过了线但计数没变化。原因如果用跟踪框的中心点来判断跨线因为中心点比车辆前部更靠后车头都过线了中心点还没过。相反如果车辆很长中心点过线时车尾还在线后计数时机偏早。解决改用跟踪框的底边中心点或直接取y2因为底边更接近车辆与地面的接触点和“车辆到达断面”这个物理意义一致。对于不同车型底边的意义比中心点更稳定。如果还需要更精确可以结合车道线在图像里的投影位置用透视变换把图像坐标转到俯视坐标再做跨线判断。5.4 阴影和水渍被当作车辆误检带来的幽灵计数现象晴天傍晚一辆货车在路面上拉出长长的影子影子在画面上和车身分离被检测成另一个“car”。车辆还没到计数线影子的框先到了导致计数提前甚至重复。原因yolov5目标检测在训练时见过带影子的车辆但它不理解“影子的边框也满足车辆形状”。单帧检测不可能完全消除这类误检因为它们确实有很强的车辆表面特征。解决一方面在数据层面把车影明显分离的样本挑出来标注成ignore或直接删除让训练时不要强化影子特征。另一方面在算法层面利用DeepSort的运动一致性影子通常和本体共享同一运动模型速度方向几乎一致可以设置“同向合并”规则如果两个框的中心点距离很近、速度相似、且一个框的底边在另一个框的底边附近就把低置信度那个作为影子剔除。5.5 部署设备跑不动从GPU到树莓派5的性能优化现象在PC上用yolov5s跑30帧视频很流畅但换到树莓派5上处理一帧需要500毫秒以上视频完全卡顿计数严重滞后。原因yolov5s本身算力需求不低DeepSort的ReID网络又是一笔额外开销。树莓派5的CPU/GPU与PC差距很大直接用PyTorch推理走的是CPU效率极低。解决分两步。第一步用轻量模型yolov5n替换yolov5s检测速度能提升一倍以上第二步把模型导出为onnx用NCNN转换后在树莓派上以CPU或NPU后端推理。实际项目里如果树莓派有NPU还可以做INT8量化精度损失约12个点但速度提升非常明显。至于DeepSort的ReID同样可以导出onnx量化。不要天真地以为“树莓派5上部署自己训练的yolov5模型”直接pip install就行要把它当成一个独立的嵌入式部署任务来对待。6. 验证与进阶用计数精度指标说话再谈轻量化部署6.1 验证计数算法精确率、召回率与F1怎么算车流量统计模型的质量不能只看mAP要直接看计数结果。我一般手工标注一小段5分钟的真实视频数出实际通过车辆数GOLD。然后跑算法得到TP、FP、FN。计算三个指标指标公式说明精确率TP / (TPFP)算法报出的车辆里真实车辆占比召回率TP / (TPFN)真实车辆里算法报出的占比F12 * P * R / (P R)综合指标如果F1低于0.9先去查ID跳变如果召回率低先查检测漏检如果精确率低先查误检和重复。每次调参后重跑同一段视频对比F1变化。这是最简单的验证方法也最有说服力。6.2 验证之外还能做什么多车道、逆行与测速在跨线计数基础上可以扩展出几个实用的进阶功能。按车道计数只需要把画面横向划分成多条计数区域每个区域独立维护passed_ids。逆行检测则利用方向判断如果车辆的运动方向和预设的车道方向相反触发警告。测速则需要先通过标定获得图像坐标系到真实世界坐标的单应矩阵再根据车辆跨过两条已知距离计数线的时间差计算速度。这些扩展都建立在稳定的track_id之上所以先把参数调稳再叠加功能。6.3 轻量化部署树莓派5上跑自己训练的YOLOv5模型我常用的部署路径是先导出onnx再用NCNN工具转成ncnn格式写C或Python调用后处理。步骤大致是用python export.py --include onnx导出best.pt用onnx-simplifier做图优化用NCNN的onnx2ncnn转换做一个极简的NMS后处理替代yolov5原生的非极大值抑制把DeepSort的ReID特征网络也转换或者直接用轻量化特征模型。在树莓派5上我更推荐yolov5n 320分辨率作为平衡点。计数不需要60帧稳定10帧以上就能工作但延迟要低。记得开启NCNN的openmp多线程CPU占用反而更均匀。最后说一个我自己的教训最初我把计数线设在画面边缘车辆刚入画就触发结果频繁变道的车头会让同一辆车在边缘来回横跳ID不变但计数却因为底边反复跨越而重复。后来把计数线内缩一段距离并加了一个“触发后100帧内同一ID不再计数”的保护窗口数字才稳定下来。车流量统计项目里检测精度是基础而计数逻辑里的一点点工程细节才是真正决定交付质量的地方。希望这篇笔记里的参数、代码和踩坑记录能帮到你少走这几段弯路。本文还有配套的精品资源点击获取
返回列表