资讯详情

基于YOLOv5与ByteTrack的车辆潮汐监测系统设计

📅 2026/10/12 19:35:14 | 华诺云谱 👁 阅读
基于YOLOv5与ByteTrack的车辆潮汐监测系统设计
简介基于YOLOv5的车辆潮汐监测系统毕业论文完整呈现了该系统的设计思路与实现过程适合计算机视觉、智慧交通方向的学生作为毕业设计参考。论文围绕YOLOv5算法展开详细介绍了卷积神经网络、线程池、MongoDB、PyTorch、cuDNN、Transformer与Flask等关键技术覆盖系统整体架构、前后端分离设计、数据上传与存储结构、模型处理接口及车辆潮汐状态分析算法的具体实现并包含了登录功能与权限分配、车辆实时检测与分类等细节。文档还梳理了国内外研究现状与结论展望展示了从需求分析、算法调优到实际部署的完整流程。资源包共1个docx文件大小1.13MB已有87人学习。对于需要撰写目标检测或智慧交通方向毕业论文的读者这份文档既能提供完整的内容框架也能作为格式和写作思路的参考具有较好的实用价值。1. 用 YOLOv5 做车辆潮汐监测到底要解决什么不是数车而是分方向潮汐车道的管理核心就一句话什么时段该调整双向车道数量。可这句话背后需要的不是“这条路车不少”而是分方向的车流量差。基于yolov5的车辆潮汐监测系统解决的就是把路口或高架上的监控视频变成可量化的交通观测结果检测出画面里的每辆车判断每辆车往哪个方向走再按时间窗口统计双向流量差。这个“分方向的车辆计数”正是潮汐调度决策里最硬的需求。方案适合三类人正在做交通类毕业设计的学生可以把系统拆成“模型—跟踪—统计”三块来论证想用摄像头替代地磁线圈的路口管理者关心成本和长期稳定以及准备在边缘设备上做目标检测的算法工程师关心模型体积和推理效率。下面按“原理—数据—训练—踩坑—验收”的顺序把这套系统讲透。2. 系统方案先从网络结构定下来检测、跟踪、方向计数三件套怎么协同2.1 从 YOLOv5 网络结构图里挑出对监控场景最关键的三个尺度很多人看 yolov5 网络结构图会先盯 CSPDarknet 里的残差块数量我建议直接看三个输出层80×80、40×40、20×20。监控相机拍的是固定车道画面纵深很大远处一辆轿车在图像里可能只有 30×30 像素近处一辆公交车能占到 100×100 以上。80×80 特征层管小目标40×40 管中距离车辆20×20 管近处大车。在潮汐监测场景里漏检通常发生在远端而不是近端所以与其把模型从 yolov5s 换成 yolov5m不如把输入分辨率从 640 提到 960让远端车在特征图上多占几个像素。这个改动对召回率的帮助比换更大的骨干网络更直接代价是推理时间上升但交通监控往往不是多路实时并发这个代价可以接受。还有一点容易被忽略预训练权重是在 COCO 上学的COCO 里机动车相关类只有 car、bus、truck。如果直接拿 80 类权重跑会把摩托车、自行车都检出来而真实路口电瓶车非常多这些非机动车混进机动车流会让潮汐曲线被严重污染。所以我一般会重新定义类别只留 car、bus、truck有时加一个 cone 用来判断潮汐车道切换状态。分类越少每一类的训练样本越充足模型的稳定性也越好。2.2 检测 跟踪 方向计数的工作顺序以及跟踪器的选型理由整个系统的处理顺序可以定成一条链检测器输出每帧的边界框 → 跟踪器把跨帧边界框串成轨迹 → 轨迹与画面里的虚拟线做方向判定 → 按时间窗聚合双向流量差。这里有个常被忽略的选型问题跟踪器用 DeepSORT 还是 ByteTrack。DeepSORT 需要额外加载一个 ReID 特征提取网络换个场景还要重新准备 ReID 训练集对交通监控这种固定机位场景来说成本偏高ByteTrack 只靠相邻帧检测框的 IoU 和高分框关联不需要单独训练在固定机位下足够稳定。我做方向计数时一般用 ByteTrack。下面是接入 ByteTrack 的代码结构和参数说明from trackers.byte_tracker import BYTETracker tracker BYTETracker( track_thresh0.35, # 置信度高于该值的框才能创建或继承轨迹 match_thresh0.8, # 相邻帧边界框 IoU 匹配阈值 frame_rate25 # 视频帧率用于确定关联窗口长度 ) for frame_id, frame in enumerate(video): dets model.detect(frame) # 返回 (x1, y1, x2, y2, conf, cls) tracks tracker.update(dets, None, None) # 每个 track 自带 track_id、class_id 和当前边界框坐标参数说明track_thresh 调高能减少误跟踪但也会把画面远端低置信度的小车丢掉固定机位场景我习惯保留 0.35比默认的 0.5 略低。match_thresh 控制同一个 ID 在前后帧能否接上0.8 适合车辆快速移动、遮挡不多的情况如果夜间检测框抖动比较大我会把 match_thresh 降到 0.7让跟踪更容忍框的漂移。方向判定不要用“框在线的哪一侧”来算。车辆停在线上等红灯时检测框会因为抖动在线的两侧反复跳动一帧一个结果。我习惯记录轨迹上一帧的底边 y 坐标只有当“上一帧在线之上、当前帧在线之下”这个瞬间出现才让该轨迹计数一次。line_y 720 # 虚拟计数线的像素纵坐标 counted_ids set() # 已经计过数的轨迹 ID for trk in sorted(tracks, keylambda t: t.track_id): x1, y1, x2, y2 trk.tlwh_to_tlbr() bottom_y y2 # 用底边代表车辆与地面的接触点 prev_y trk.last_bottom # 上一帧的底边坐标 if prev_y is not None and prev_y line_y bottom_y: if trk.track_id not in counted_ids: direction_count[trk.cls][trk.side] 1 counted_ids.add(trk.track_id) trk.last_bottom bottom_y这段逻辑的关键是“跨越线的瞬间才计数”。车辆排队停在线上时prev_y 和 bottom_y 会一直在线附近小幅抖动但很少同时满足prev_y line_y bottom_y这个单向穿越条件所以不会产生重复计数。左右方向同样处理把虚拟线改成竖线用中心点 x 坐标做穿越判断。2.3 潮汐指数怎么算时间窗口、双向流量差与中位数平滑检测和方向计数解决“今天有多少辆”潮汐监测还要解决“什么时候该调车道”。常见做法是先把每条计数事件打上时间戳按 5 分钟聚合一次得到 A 方向和 B 方向的流量再算潮汐指数 tidal_index (A - B) / (A B)。指数大于 0 说明 A 方向压力大小于 0 说明 B 方向压力大。最后用中位数滤波做 15 分钟平滑把红绿灯分批放行造成的脉冲波动压下去。import pandas as pd events_df[bin] events_df[ts] // (5 * 60) # 5 分钟一个时间桶 grp events_df.groupby([bin, direction]).size().unstack(fill_value0) grp[tidal] (grp[A] - grp[B]) / (grp[A] grp[B] 1e-6) smooth grp[tidal].rolling(3, centerTrue, min_periods1).median()5 分钟聚合、15 分钟平滑是我在快速路匝道项目里的默认值。如果是学校门口这类短时潮汐可以改成 1 分钟聚合、5 分钟平滑。tidal_index 本身很适合写进毕业论文的算法章节它比只画两条流量曲线直观得多而且能直接对应“车道方向切换”这个管理动作。3. 准备自己的车辆数据集从视频抽帧到生成可用的 yaml 配置3.1 视频抽帧间隔怎么定均匀抽 vs 按场景抽训练数据的质量和来源直接决定潮汐监测系统能不能换场景复用。公开数据集可以用但只能作为预训练或补充真正的部署验证一定要从目标摄像头录一段视频来抽帧。我通常的做法是一天里选早高峰、晚高峰、平峰、夜间四段各录 15~20 分钟然后用 ffmpeg 按每秒 1 帧抽取避免连续帧之间画面差异太小造成训练集冗余。ffmpeg -i morning_peak.mp4 -vf fps1 -q:v 2 -f image2 frames/raw/%04d.jpg参数说明fps1表示每秒抽 1 帧-q:v 2是 JPEG 质量数值越小画质越高。如果车流量很大比如一个路口每分钟过 60 辆以上可以把抽帧频率降到fps0.5减少同一辆车在多帧里重复出现的比例。夜间视频建议单独抽一批不要和平峰帧混在一起后面训练时给夜间帧适当提高权重。抽完帧还要做一次人工筛选把画面完全空白的静帧、摄像头抖动模糊帧、以及车辆静止超过 20 秒的排队画面删掉。排队画面会让标注工作做很多无用功也会让模型过度学习“车都堵在路上”的静态特征。3.2 用标注工具标边界框遮挡时标多少、类别定几个抽完帧后用 labelImg 或 X-AnyLabeling 标注输出格式选 YOLO。标注规则要提前定死不然后面补标非常痛苦。我常用的三条规则是第一边界框紧贴车身可见轮廓不要包进地面阴影也不要把后视镜留到框外太多第二公交车、大货车遮挡小轿车超过一半时只标可见的大车不标被挡住的小车第三目标超出画面边缘超过 20% 时不标正在画面边缘开进开出的车会让训练标签很不稳定。类别数量能少就少。潮汐监测只需要区分小型车和大型车时我只会定义car、bus、truck三类。如果某个路口只有小汽车和大客车就直接定义car、bus类别少能让每一类的样本量更充足。把摩托车也单独设一个类看起来合理但摩托车目标小、遮挡率高一旦样本量和汽车差距悬殊模型很容易把远处电瓶车漏掉得不偿失。标注完成后检查一下每个类别的大致数量。truck 这类在市区占比低如果总数少于 50 个实例建议暂时合并到 bus 作为“大型车”否则训练时这一类的权重会被 car 类压住。3.3 数据集目录结构、yaml 配置和第一轮快速验证YOLOv5 要求图片和标签文件名完全一致只是后缀不同。目录结构按下面的方式组织最省事datasets/vehicle_flow/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ └── val/ └── vehicle_flow.yamllabels 里每一个 txt 文件与 images 里同名图片一一对应。如果一个图片文件缺少同名 txtYOLOv5 会把它当作空背景图参与训练这类图多了会让模型误以为“没有车才是常态”所以跑训练前先检查一遍文件数是否匹配。对应的 vehicle_flow.yaml 内容如下path: ./datasets/vehicle_flow train: images/train val: images/val nc: 3 names: [car, bus, truck]path 是数据集根目录可以是绝对路径也可以是相对路径nc 必须和 names 列表长度一致。第一轮先别直接投入完整训练我习惯用小 batch、少 epoch 快速跑一遍目的是让模型把标注错误暴露出来。python train.py \ --data vehicle_flow.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 8 \ --epochs 20 \ --project runs/check跑完后打开 val 集上的混淆矩阵重点看 car 和 bus 之间有没有大量混淆。如果 bus 的标签经常把大型 SUV 也框进去模型很难学到稳定特征这时候回去修标注比调参数有效得多。4. 训练自己的车辆检测模型命令、超参数和评估指标读法4.1 训练命令和关键参数从 yolov5s 起步的性价比路线模型选型上我一般从 yolov5s 起步而不是一上来就 yolov5x。潮汐监测的目标是长时间连续计数每秒要处理的帧多模型推理速度直接影响检测频率。yolov5s 在 640 分辨率下能做到单 GPU 30 FPS 以上对 25 帧的监控视频足够用。如果现场只有低算力设备再考虑 yolov5n 或后续量化。完整训练命令如下python train.py \ --data vehicle_flow.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 120 \ --patience 20 \ --cos-lr \ --project runs/train \ --name tidal_vehicle参数说明--batch 16在 8GB 显存下比较稳妥批量太小会让 BN 层统计噪声变大--patience 20表示连续 20 个 epoch 验证集 mAP 不提升就停止训练--cos-lr是余弦退火学习率对几千张这种规模的数据集会比固定步长衰减更稳。不建议在自定义数据上开--multi-scale因为监控机位固定目标尺度变化范围有限开启只是浪费显存。4.2 影响收敛的 3 个 yolov5 超参数imgsz、batch、mosaicyolov5 超参数文件的入口在data/hyps/hyp.scratch-low.yaml大部分默认值不用动但有三项值得针对交通场景调整。imgsz 是第一个。640 是基础值训练前先看一下标注框的像素分布。如果画面里大量车的高度在 25~45 像素之间把--img提高到 960远端小目标的召回率提升明显代价是显存占用和推理时间一起上去。我通常先在 640 下跑通流程确认曲线收敛后再提分辨率重新训练单独做一次对比实验作为论文里的消融点。batch 是第二个。交通数据集容易出现某个时段车辆密集、某个时段全是空路面的现象如果 batch 太小一个 batch 里可能全是密集车辆另一个 batch 里全是背景loss 会来回震荡。显存允许的话尽量用 16 以上显存不够就降 imgsz不要硬降 batch。mosaic 是第三个也是最容易踩坑的。小数据集上开启 mosaic 增强能大幅提升泛化能力但四张图拼接时会产生很多被切成一半的车辆样本。我习惯前 60 个 epoch 开着 mosaic后 40 个 epoch 在 hyp 文件里把mosaic: 0.0让模型再适应一遍完整形态的车辆。这种两段式训练比全程开 mosaic 的最终 mAP 更稳因为它减少了“车一定完整”的误判。另外YOLOv5 默认会自动重新聚类 anchor。监控视角下车辆往往是扁长形宽高比集中在 1.5~2.5训练时会自动算出一组更贴合数据集的锚框。如果你发现第一轮训练后 mAP 迟迟上不去检查一下训练日志里 anchor 有没有更新不想让它自动更新就用--noautoanchor固定默认锚框。4.3 评估指标怎么读mAP0.5 和 mAP0.5:0.95 别混用训练结束后我通常用 val 集跑一次评估python val.py \ --data vehicle_flow.yaml \ --weights runs/train/tidal_vehicle/weights/best.pt \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45评估输出里有两个关键指标mAP0.5 和 mAP0.5:0.95。前者只看 IoU 阈值 0.5 下的检测质量对框的位置精度要求不高适合评价“车有没有被找到”后者把 IoU 从 0.5 逐步加到 0.95 再平均更看重框的贴合程度。做车辆计数时我更关心 mAP0.5因为潮汐监测用的是“中心点或底边过线”事件框稍微偏几个像素对方向判定影响很小。如果发现 mAP0.5 很高但 mAP0.5:0.95 明显偏低说明模型能找对位置但框不够准优先检查标注时边界框是否普遍包得偏松。还有一个容易被忽略的点best.pt 是按验证集 loss 选出来的不是按某个特定类别的召回率选的。如果你的目标是数小型车但验证集里大型车占比高best.pt 可能会偏向大车。我会在 val.py 输出里单独看 car 类的 recall而不是只看总 mAP。车流量统计的大忌是漏检漏检会被跟踪和计数逻辑放大最终导致潮汐指数整体偏低。5. 车辆潮汐监测常见问题的排查记录4 个让我返工的坑这一路做下来翻车点多数不在模型参数而在数据分布和计数逻辑。下面按“现象—原因—解决”的方式整理我踩过的 4 个坑排序按出现频率从高到低。5.1 雨天或夜间车流量曲线突然“坐滑梯”现象白天计数正常一到夜间或雨天分方向车流量明显低于人工计数潮汐指数被拉偏。原因夜间车辆大灯造成画面局部过曝模型把高光区域当成干扰雨天路面积水反光、雨雾压低对比度远端车辆和背景融为一体检测器召回率大幅下降。这不是模型结构的问题是训练集里缺少低照度样本。解决抽帧时强制加入 20%~30% 夜间和雨天画面让模型见过“带大量噪点的车辆”长什么样。如果夜间样本数量不够可以在推理阶段把置信度阈值从 0.25 降到 0.15利用跟踪器消化部分误检保证召回优先分方向统计看的是流量量级少量误检可以被后面的时间平滑吸收。另外不要在训练时对全部数据开同样的色彩增强夜间帧再做强 HSV 扰动会偏离真实光影关系。5.2 红灯放行时车辆同一画面被反复计数现象某个方向的车流量在红灯期间持续上涨绿灯一亮就恢复正常但总计数远大于实际通过车辆数。原因这是典型的“状态判断”错误不是检测错误。车辆排队停在虚拟线附近检测框的底边在线的上下两侧抖动如果程序只是判断“框在线下方就计数”每一帧都会把同一批车再数一遍没有轨迹 ID 去重。解决必须用事件穿越判断代替位置判断。也就是说计数只发生在prev_bottom line_y bottom_y这个瞬间并且每个 track_id 只允许计数一次。车前轮压线、车停在线上都不满足穿越条件因为下一帧的 bottom_y 不会再从线的一侧跳到另一侧。还要注意等红灯时先把队首车辆在排队前是否已经跨越过虚拟线如果虚拟线刚好画在停止线附近排队车辆会整队压线这时应该把虚拟线往上游移动 10~20 米让排队状态不会长时间压在线上。5.3 公交车遮挡小轿车轨迹中断导致漏计现象一条车道的计数结果在公交车出现后突然偏低而且被遮挡的小轿车方向归属偶尔出错。原因ByteTrack 这类基于 IoU 关联的跟踪器在目标被完全遮挡超过一定帧数后轨迹会被判定为丢失轨迹 ID 被回收。公交车车身大它经过时能把旁边车道的小轿车遮挡 1~2 秒如果帧率只有 12~15这 1~2 秒足够让跟踪器丢掉目标。解决给跟踪器设置一个丢失缓冲帧数让轨迹在被遮挡期间保持“挂起”状态不立刻删除 ID。具体数值在 ByteTrack 里对应max_time_lost我一般从默认的 30 帧调到 50 帧。注意调大这个值会让长时间停在画面里的静止车辆也一直占着 ID所以要和 5.2 的穿越计数配合使用已经计数过的 ID 即使挂起也不能再次计数。还有一个小技巧虚拟计数线不要放在路口停止线附近放在离路口 15 米左右视野开阔的位置车辆排队和遮挡对计数线的干扰都会小很多。5.4 训练时 mAP 很高换一个摄像头就明显掉点现象模型在验证集上 mAP0.5 超过 0.9换到另一个杆位、不同高度的摄像头下车流量计数偏少四分之一。原因训练集大多来自公开数据集或网上的俯拍素材而实际部署的摄像头是路侧视角或高架上的斜俯视角车辆长宽比和遮挡形态差异很大另外不同摄像头安装高度、俯仰角会带来完全不同的目标尺度分布。公共数据集练出来的模型在“标准视角”上很好一旦视角变化分布外检测性能就崩这属于典型的过拟合场景分布。解决从目标点位或相似点位录制现场视频抽帧补充训练集。最有效的做法是找 3~5 个不同安装高度的摄像头每个录 10 分钟视频各抽 500 帧与公开数据集混合后微调 10~15 个 epoch学习率降到原来的十分之一。这样模型能看到不同的透视形变又不会把之前学到的通用特征冲掉。如果实在拿不到现场视频至少要在论文里标明“模型仅适用于特定视角”不要指望一个模型通吃所有监控点位。提示夜间检测不稳时先把问题拆成“数据问题”和“跟踪问题”。数据问题看 val 集 PR 曲线在低置信度区间是否保持高位跟踪问题看轨迹中断的数量。两件事混在一起调参很容易把置信度阈值和匹配阈值互相抵消。6. 用三个验证动作把关整个系统别让潮汐指数只是纸面指标论文里写的潮汐指数、车道切换建议最终要落在真实视频上。我每次做完系统都会用三个验证动作兜底分段精度核查、人工计数比对、潮汐曲线合理性判断。这三个动作做下来系统能不能上线基本心里有数。分段精度核查的做法是把测试视频按白天、夜间、雨天各截一段每段 10 分钟分别统计检测召回率。监控场景下人工数车 10 分钟很累但不做这一步就不知道模型的真实底线。常见通过标准是白天单类召回率不低于 90%夜间不低于 80%雨天不低于 75%。达不到就先补数据不要急着调阈值。人工计数比对是拿同一个 10 分钟片段把系统输出的分方向计数和人工逐帧数出的结果对比误差在 5% 以内才算跟踪逻辑合格。这个误差如果偏大通常不是检测问题而是方向判定逻辑有问题可以把虚拟线和跟踪 ID 的中间结果可视化保存下来一帧一帧往回找。潮汐曲线合理性判断则是对着流量趋势看方向切换点是否和实际高峰吻合常见做法是把系统算出的 tidal_index 和交警发布的潮汐车道切换时间做对比误差在 10 分钟以内是合理范围。跑验证用的命令很简单python val.py \ --data vehicle_flow.yaml \ --weights runs/train/tidal_vehicle/weights/best.pt \ --img 960 \ --conf-thres 0.15 \ --iou-thres 0.45如果要做硬件部署验证常见做法是把 best.pt 导出成 ONNX再转成目标平台格式。导出命令是python export.py --weights best.pt --include onnx --opset 11。像 RK3568 这类边缘板量化到 int8 后模型会小很多但低置信度目标会最先受影响所以量化后要重新看夜间段的召回率。树莓派 4B 也能跑 yolov5s但帧率只有 3~5 FPS适合离线统计不适合实时方向判定。潮汐车道切换时路面会摆锥桶我后来在模型里加了一个 cone 类别让系统能识别“车道正在切换”这一事件。这个小改动让潮汐指数的解释性更强也让我意识到这个系统不是用来取代调度的它是帮调度少盯几块屏幕、把注意力留给异常时段。每次上线新场景我都会先和人工计数比对一段视频再放手这个习惯救了我很多次。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑