ARTICLE DETAIL

资讯详情

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

基于YOLO的交通流量检测系统:从数据集到Flask部署全流程

基于YOLO的交通流量检测系统:从数据集到Flask部署全流程 简介面向计算机专业毕业设计的基于深度学习的交通流量检测系统项目覆盖从数据采集、预处理到模型构建、训练评估及系统集成的完整技术链路。压缩包内文件总数达两千个其中一千四百余个JavaScript脚本承载前端交互与核心逻辑四百余篇Markdown文档提供开发笔记与算法讲解一百七十余个JSON配置存储模型参数与运行设置另有HTML和CSS文件搭建可视化监控界面便于实时查看检测结果整体大小约一百三十MB。项目融合CNN、RNN、LSTM等网络结构可实现车辆检测、流量计数与交通状况实时预测并涉及数据增广、优化器选择、超参数调优及GPU加速等工程环节。已有六百六十六人学习使用适合需要完整毕业设计参考的学生可直接在已有代码基础上扩展模型或替换数据集进行复现实验。1. 拿到这份“交通流量检测系统.zip”先想清楚里面该有什么拿到这个毕业设计交通流量检测系统.zip 时第一件事不是急着解压而是想清楚里面应该有什么。我带过不少做深度学习毕设的学生最容易答辩翻车的不是模型精度不够而是整个系统只有一堆训练代码和权重文件没有演示界面、没有说明文档、没有可复现的数据集评委一打开就冷场。这个方向解决的是一个问题用深度学习算法把视频里的车辆和行人识别出来实时统计车道流量最后落成一个能演示、能被追问的完整系统。适合正在做毕设或课设、需要一个能跑通全链路参考方案的从业者。解压前先给自己定三个验收标准模型能跑、界面能开、答辩能答。2. 把毕设需求拆成技术选型检测任务、算法与算力2.1 交通流量检测是检测任务不是分类任务很多第一次做深度学习项目的同学会把交通流量检测理解成“给一张图判断有没有车”这是分类任务的思路。但实际场景里一张路口视频帧里可能同时有十几辆车和行人你需要知道每一辆车在哪、属于什么类型、从哪个车道经过才能统计流量。这本质上是目标检测任务输出是每个目标的边界框坐标、类别和置信度而不是一个简单的标签。整个系统的工作流可以拆成四步读取视频帧、检测车辆和行人、按车道区域判断目标归属、按时间窗口累加流量。检测模型承担的是第二步里最核心的“找目标”工作后面三步都是围绕检测结果做的工程化处理。也就是说检测模型的精度和速度直接决定了整个系统能不能用而流量统计逻辑反而是相对简单的部分。这个链路是深度学习入门项目里比较标准的实战项目案例难点不在理论而在把模型、数据、接口串起来。做毕设的时候论文的“系统设计”部分也基本是照着这条链路写先总体框架再分模块讲检测、计数、可视化。2.2 检测算法选型为什么默认选 YOLO检测模型的选型决定了后面所有工作的难度这里务必想清楚。常见的候选有三类。方案精度推理速度端到端工程复杂度毕设友好度Faster R-CNN 两阶段高慢不适合视频实时高依赖组件多中SSD 单阶段中快中中YOLOv5/v8 系列高快低生态完整高我一般会直接推荐 YOLO 系列原因有三。第一它在速度和精度上平衡得最好视频流推理是刚需两阶段检测器在普通的笔记本上很难跑到实时。第二YOLO 的开源生态太完整了从训练到部署都有现成的命令行工具这对毕设周期来说非常关键。第三论文好写因为 YOLO 的改进版本多你可以基于 baseline 做消融实验或者小改进这是毕设评审最喜欢的素材。具体选哪个版本以 2025 年这个时间点来看YOLOv8 的集成度高训练、验证、推理、导出一条命令走完适合时间紧的同学。如果配置老一些YOLOv5 也完全够用网上能查到的资料最全。不建议从零手写网络结构或者用太冷门的模型毕设的核心是“做出一个可用的系统”不是重新发明检测器。2.3 算力评估与深度学习环境配置先看机器再定方案深度学习环境配置是劝退率最高的一步但也是最能提前规避的一步。动手前先看清楚手头机器的显卡和显存这决定了你能跑训练还是只能做推理。6GB 以下显存选 YOLOv8n 或 YOLOv5s图片尺寸降到 640batch size 设 8 以内。8GB 到 12GB 显存选 YOLOv8sbatch size 设 16基本够用。没有独立显卡不建议在本机训练用云 GPU 平台跑训练本机只做推理演示。训练和推理可以分离。很多人以为必须有一张好显卡才能做这个毕设其实不然。训练是离线过程慢一点没关系答辩现场是推理过程用 CPU 跑 YOLOv8n 也能达到每秒几帧的检测速度配合跳帧策略足够演示。环境配置有一个清单值得抄下来对照检查Python 3.9 以上、PyTorch 2.x、CUDA 与 cuDNN无 GPU 可跳过、ultralytics 包、opencv-python。安装顺序不要乱先装 PyTorch 再装 ultralytics否则可能出现 torch 版本不匹配导致模型加载失败。装完后跑一句yolo detect predict sourcehttps://ultralytics.com/images/bus.jpg验证环境能出结果说明环境没问题后面就不用再折腾。3. 跑通最小训练闭环从 VOC 标注到 YOLO 格式的转换脚本3.1 数据集从哪来公开数据集与自建标注的取舍训练一个可用的检测模型数据质量比模型结构更重要。公开数据集里交通场景优先考虑这三个UA-DETRAC 是专门的车辆检测追踪数据集BDD100K 有大量真实道路视频帧Cityscapes 覆盖复杂的城市场景。选数据集时注意两点一是类别命名要和你的需求对齐二是照片分辨率要接近你的实际场景。如果说公开数据集拿来做毕设显得太“公用”你也可以自建数据集。常见做法是用 FFmpeg 按一定间隔从视频里抽帧然后逐帧标注。间隔帧数没有固定标准一般来说场景变化快的路口每 5 帧抽一帧场景单调的高速路每 15 到 20 帧抽一帧。抽完帧后用 LabelImg 或 Roboflow 标注标注的类别建议控制在 6 类以内car、bus、truck、motorbike、bicycle、person。类别越多标注工作量越大模型收敛越慢答辩时被问住的概率也越高。关于数据量每类至少 300 到 500 个实例是底线整个数据集 2000 到 3000 张图比较合适。图像太少模型的泛化能力会很差图像太多标注时间会拖垮整个毕设进度。一个折中的做法是先用 80% 公开数据加 20% 自采数据混着训练这样既有真实感又不至于累死。3.2 把 VOC 标注转成 YOLO 格式转换脚本与坐标归一化标注工具导出的常见格式是 VOC XML但 YOLO 训练需要的是每个图片对应一个同名 txt 文件每行表示一个目标格式是“类别id x_center y_center width height”全部归一化到 0 到 1 之间。这个转换写起来不难但坑实在不少我直接给一段可以按需改的脚本。import xml.etree.ElementTree as ET import os classes [car, bus, truck, motorbike, bicycle, person] def xml_to_yolo(xml_path, out_dir, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() file_name os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, file_name .txt), w) as f: for obj in root.findall(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止标注越界导致训练时崩溃 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) w max(0, min(1, w)) h max(0, min(1, h)) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n)这段脚本的逻辑就是解析 XML 里的bndbox四个坐标值算出中心点坐标和宽高再分别除以图片宽高完成归一化。有三个参数需要特别注意img_w和img_h必须和实际图片尺寸一致否则所有框的位置都会偏移classes列表的顺序一旦确定就不能再改因为训练时是按索引读的中间插一个类别会导致所有后续类别全部错位归一化后做了 clip 到 0 到 1 的处理避免标注框超出图片边界导致训练报错。转换完记得随机抽查几个 txt 文件打开看每一行的前两个数是否都在 0 到 1 之间。如果出现负数或者大于 1 的值说明原 XML 里标注框本身就超出了图片范围需要回标注工具里修正不要指望脚本帮你兜底。3.3 标注质量检查与数据集划分转换完格式不等于数据就能用了还差两道检查工序。第一道是可视化检查随便挑几十张图把 txt 里的坐标还原成矩形画在原图上肉眼确认框是否贴边、是否漏标。这一步能用一段简单的 OpenCV 脚本批量完成也可以直接看图。第二道是类别统计数一数每个类别在训练集里出现多少次如果 car 有 5000 个而 bus 只有 100 个模型几乎必然会把 bus 漏掉。针对类别不均衡可以做的处理有两层。数据层面加一些 bus 样本的复制粘贴增强或者干脆多找点公交车图片补标训练层面可以把少样本类别的权重调高一点。不过对毕设来说最省力的是标数据时就有意识多收集少样本类别的图片而不是事后补救。数据集划分上按 7:2:1 切成三份训练集、验证集、测试集。注意测试集一定要和训练集完全隔离不能有同一段视频里抽出的相邻帧同时出现在两个集合里。这个踩坑很常见因为视频相邻帧极其相似会让验证分数虚高答辩时一换真实视频立刻露馅。4. 训练与验证参数怎么定、曲线怎么看、指标怎么算4.1 用一个最小训练命令跑通全流程数据和环境都准备好后先别急着调参用最小的命令把流程跑通。下面是一个标准的 YOLOv8 训练命令。yolo detect train datatraffic.yaml modelyolov8n.pt \ epochs100 imgsz640 batch16 device0datatraffic.yaml指向你的数据集配置文件里面写明图片路径和类别名称modelyolov8n.pt表示用预训练权重作为起点比从零训练收敛快得多毕设场景不要从零开始训epochs100是训练轮数交通场景一般 80 到 120 轮足够imgsz640是输入图片尺寸越大精度越高但显存占用也越大batch16是每轮批大小device0指定用第一张 GPU没有 GPU 就改成devicecpu但训练会非常慢。对应的traffic.yaml内容如下。path: ./traffic_dataset train: images/train val: images/val names: 0: car 1: bus 2: truck 3: motorbike 4: bicycle 5: person这里path是数据集根目录train和val是相对于根目录的图片文件夹路径names用列表形式给出类别名索引顺序必须和第 3 章转换脚本里的classes顺序一致。训练启动后ultralytics 会在runs/detect/train目录下保存权重、日志和验证结果图。训练过程中需要盯住的只有一件事耐心。前 10 轮 loss 可能波动很大不用理会50 轮以后如果还在持续下降就接着训如果验证集的 loss 开始回升而训练集 loss 还在降就是过拟合的信号应该提前停止。4.2 训练曲线怎么看别只看总 loss训练结束后打开runs/detect/train下的results.png一行一行看曲线这里最容易暴露问题。曲线正常趋势异常信号train_loss 总损失整体下降后趋平不降反升或剧烈震荡val_loss 验证损失先降后平中途反弹说明过拟合box_loss 框位置损失下降后平缓不平说明定位不稳cls_loss 分类损失下降后平缓为 0 说明模型在偷懒mAP0.5上升后趋平徘徊不动检查数据mAP0.5:0.95略低于 mAP0.5差距大说明定位精度不足可以参考的指标主要有三个。mAP0.5是 IoU 阈值 0.5 下的平均精度这个值在交通场景里做到 0.8 以上就算不错。mAP0.5:0.95是更严格的指标对定位精度更敏感毕设论文里两个都写显得专业。Precision 和 Recall 是一对矛盾指标P 高 R 低说明模型保守宁可漏检也不误检R 高 P 低说明模型激进经常把背景当目标。流量检测场景漏检比误检更影响计数准确性所以一般倾向把置信度阈值调低一点提高 Recall。除了results.png还可以用 TensorBoard 看更细的日志ultralytics 训练时会自动记录。启动方式是在项目目录下执行tensorboard --logdir runs然后浏览器打开显示的地址。TensorBoard 可以按轮次查看每一类的 P 和 R 曲线排查具体哪个类别拖后腿。4.3 用测试视频跑一遍推理验证效果训练完成后拿出测试集视频跑一次推理这一步既是验证也是答辩素材。yolo detect predict modelruns/detect/train/weights/best.pt \ sourcetest_video.mp4 conf0.25 saveTruemodel指向训练得到的权重文件注意用best.pt不用last.ptsource是测试视频路径也可以换成图片文件夹conf0.25是置信度阈值低于这个值的结果会被过滤掉saveTrue表示把标注后的结果保存下来。跑完后在runs/detect/predict目录下会生成带框的视频这个视频就是答辩现场的核心演示材料。如果发现视频里漏检多先降conf到 0.15 再看看如果发现误检多路牌、树影被框出来就升到 0.4 左右。置信度阈值是最直接的调节旋钮不用重新训练。另外save_txtTrue可以额外保存每个目标的坐标和置信度到 txt 文件做流量统计时需要用到这个结果。这个功能在做后期车辆计数时非常有价值可以提前把检测结果缓存下来方便复盘。5. 毕设最常翻车的五个地方一套踩坑记录5.1 解压后文件乱码或伪加密先解决“打不开”再谈训练现象zip 文件解压后文件夹结构散了文件名出现乱码或者解压时弹出要输入密码但工程本身并没有加密。原因这是 zip 压缩包的编码和标志位问题。Windows 下用旧版压缩工具制作 zip 时中文文件名用的是系统本地编码而非 UTF-8解压工具默认按 UTF-8 解析就乱码了。所谓伪加密是 zip 文件头里加密标志位被置位但文件数据实际并未加密常见于压缩工具兼容性问题。解决换用 7-Zip 或 Bandizip 这类对编码兼容更好的工具解压时在选项里选择“强制使用 UTF-8 文件名”。如果确认是伪加密7-Zip 能识别并正常解出文件如果是真加密且不知道密码系统做的是做不到“移除密码”的先联系文件作者确认密码或者在原始课程设计环境里重新导出工程。做完毕设的压缩包建议用英文文件名重新打包能省掉答辩换电脑时解压乱码的麻烦。5.2 训练一启动就报 CUDA out of memory现象训练命令刚跑几秒终端直接报CUDA out of memoryGPU 显存被耗尽。原因最常见的情况是 batch size 设置过大或者是 YOLOv8 的 cache 参数默认把数据缓存到显存导致占用飙升。另外如果开了多个程序占用显存没释放也会直接触发。解决把batch从 16 降到 8 或 4imgsz从 640 降到 512加上cacheFalse参数强制不对数据做显存缓存关掉其他占显存的进程。如果这些都做了还是不够说明显卡实在带不动当前模型规格换yolov8n是最小权重模型再不行就用云 GPU 平台。5.3 车辆密集时远距离小目标漏检严重现象mAP 数值看着不错但放到真实路口视频里远处的车辆和行人几乎全部漏检而且密集车流中框会乱跳。原因小目标在图片里占的像素太少模型下采样后特征丢失严重。如果训练集里远距离样本占比不多模型会直接放弃学习这类目标。还有一个因素是 NMS 的非极大值抑制密集车辆重叠时 IoU 过高后出现的车辆被抑制掉了。解决采样时多加入远距离和俯拍视角的视频帧数据增强里把 mosaic、旋转、缩放的比例调高推理时把nms_iou从默认的 0.7 调整到 0.4 到 0.5 之间减少重叠框互相抑制。如果对极远距离的目标有强需求可以对输入图片做切片推理把大图切成四块分别检测再合并结果代价是推理时间翻倍。5.4 训练正常但推理结果全是空框或类别错乱现象训练时 loss 下降得很漂亮验证集 mAP 也高但实际推理时输出的框全空或者把行人识别成自行车、把卡车识别成汽车。原因最隐蔽的原因是类别索引错位。如果你训练前修改过classes列表的顺序而模型权重是在旧顺序下训练的那么新推理时调用的模型还是会按旧索引输出导致类别标签对不上。其次训练时图片尺寸是 640推理时输入尺寸如果设置成 1280目标框的坐标会被拉伸错位。解决重新训练前确认data.yaml的names顺序和训练脚本、推理脚本完全一致改任何类别顺序都必须重训。推理时强制固定imgsz与训练设置保持一致。调试时先把conf降到 0.1把所有低置信度的检测结果都输出看看是不是单纯的阈值问题而不是模型本身坏了。5.5 答辩现场视频推流卡顿怎么办现象现场演示视频时画面一卡一卡地跳检测框跟不上画面里车的移动。原因视频读取线程和检测线程速度不匹配OpenCV 读取视频帧的速度远快于检测速度积压的帧越来越多最后画面播放像幻灯片。真实的网络视频流场景下推流和拉流的缓冲机制也会放大卡顿问题。解决三个手段按顺序用。第一是跳帧检测每隔 2 到 3 帧检测一次中间帧沿用上一次检测结果视觉观感影响很小。第二是把预读队列长度限制住检测完一帧再读下一帧宁肯帧率低也不积压。第三是调低输入分辨率把 1080p 的视频缩到 640 宽再推理检测速度能翻倍。答辩前的演示视频建议提前用固定跳帧策略录好一份现场直接用录好的视频播放再把实时推理作为加分项展示不要赌现场网络的稳定性。6. 交付前的最后一段路Flask 接口与验收自检表6.1 用 Flask 把检测模型包成一个能演示的接口训练和推理跑通只完成了一半毕设交付需要有一个“系统”的样子。最省事的做法是写一个 Flask 接口把模型封装成 HTTP 服务前端页面或者手机发一张图片过来后端返回检测结果和数量。这个接口在答辩时可以直接用浏览器演示比当场敲命令行观感好得多。from flask import Flask, request, jsonify import cv2 import numpy as np from ultralytics import YOLO app Flask(__name__) model YOLO(best.pt) app.route(/detect, methods[POST]) def detect(): file request.files[image] img cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR) results model(img, conf0.3) count len(results[0].boxes) boxes [] for box in results[0].boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) cls_id int(box.cls[0]) boxes.append({bbox: [x1, y1, x2, y2], class: model.names[cls_id]}) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(result.jpg, img) return jsonify({count: count, boxes: boxes}) if __name__ __main__: app.run(host0.0.0.0, port5000)这段代码把模型加载做在服务启动阶段避免每次请求都重新加载权重results[0].boxes取第一张图的所有检测框model.names[cls_id]把类别 id 转成可读名称这个映射直接来自训练时的 yaml 配置。接口返回 JSON里面有总数量和每个框的坐标、类别前端拿到数据后可以自己绘制也可以直接用后端画好框的 result.jpg。视频流场景可以在这个接口基础上扩展把输入从单张图片改成视频帧序列每处理一帧返回一次计数结果。对毕设来说先保证单帧接口是通的再谈视频流。6.2 验收自检表答辩前按这个清单过一遍自检项检查方法通过标准模型单帧推理随便找一张测试图跑 predict框位置正确、类别无错乱视频流处理录一段 30 秒路口视频测试检测不崩、计数误差可控Flask 接口用 curl 或浏览器 POST 图片返回 JSON、result.jpg 有标注框数据集预案检查测试集是否与训练集隔离类别索引一致、无相邻帧混入失败问答预案准备 3 个模型失效案例能解释原因并给出改进方向这五条里前三条是功能底线后两条是答辩防线。我自己的习惯是答辩前两周把测试视频换成一组完全没见过的真实路口录像跑一遍看效果如果效果崩了降conf或者重训而不是纠结论文里写的 mAP 数字。这套流程做完模型、接口、视频、问答都有了系统才算真正闭环。希望这个方向和这些具体做法能帮到你少走点我当年走过的弯路。本文还有配套的精品资源点击获取
返回列表