news 2026/9/26 3:07:51

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于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 单阶段中快中中
YOLO(v5/v8 系列)高快低,生态完整高

我一般会直接推荐 YOLO 系列,原因有三。第一,它在速度和精度上平衡得最好,视频流推理是刚需,两阶段检测器在普通的笔记本上很难跑到实时。第二,YOLO 的开源生态太完整了,从训练到部署都有现成的命令行工具,这对毕设周期来说非常关键。第三,论文好写,因为 YOLO 的改进版本多,你可以基于 baseline 做消融实验或者小改进,这是毕设评审最喜欢的素材。

具体选哪个版本,以 2025 年这个时间点来看,YOLOv8 的集成度高,训练、验证、推理、导出一条命令走完,适合时间紧的同学。如果配置老一些,YOLOv5 也完全够用,网上能查到的资料最全。不建议从零手写网络结构或者用太冷门的模型,毕设的核心是“做出一个可用的系统”,不是重新发明检测器。

2.3 算力评估与深度学习环境配置:先看机器再定方案

深度学习环境配置是劝退率最高的一步,但也是最能提前规避的一步。动手前先看清楚手头机器的显卡和显存,这决定了你能跑训练还是只能做推理。

  • 6GB 以下显存:选 YOLOv8n 或 YOLOv5s,图片尺寸降到 640,batch size 设 8 以内。
  • 8GB 到 12GB 显存:选 YOLOv8s,batch size 设 16,基本够用。
  • 没有独立显卡:不建议在本机训练,用云 GPU 平台跑训练,本机只做推理演示。

训练和推理可以分离。很多人以为必须有一张好显卡才能做这个毕设,其实不然。训练是离线过程,慢一点没关系;答辩现场是推理过程,用 CPU 跑 YOLOv8n 也能达到每秒几帧的检测速度,配合跳帧策略足够演示。

环境配置有一个清单值得抄下来对照检查:Python 3.9 以上、PyTorch 2.x、CUDA 与 cuDNN(无 GPU 可跳过)、ultralytics 包、opencv-python。安装顺序不要乱,先装 PyTorch 再装 ultralytics,否则可能出现 torch 版本不匹配导致模型加载失败。装完后跑一句yolo detect predict source=https://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 data=traffic.yaml model=yolov8n.pt \ epochs=100 imgsz=640 batch=16 device=0

data=traffic.yaml指向你的数据集配置文件,里面写明图片路径和类别名称;model=yolov8n.pt表示用预训练权重作为起点,比从零训练收敛快得多,毕设场景不要从零开始训;epochs=100是训练轮数,交通场景一般 80 到 120 轮足够;imgsz=640是输入图片尺寸,越大精度越高但显存占用也越大;batch=16是每轮批大小;device=0指定用第一张 GPU,没有 GPU 就改成device=cpu,但训练会非常慢。

对应的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 说明模型在偷懒
mAP@0.5上升后趋平徘徊不动检查数据
mAP@0.5:0.95略低于 mAP@0.5差距大说明定位精度不足

可以参考的指标主要有三个。mAP@0.5是 IoU 阈值 0.5 下的平均精度,这个值在交通场景里做到 0.8 以上就算不错。mAP@0.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 model=runs/detect/train/weights/best.pt \ source=test_video.mp4 conf=0.25 save=True

model指向训练得到的权重文件,注意用best.pt不用last.pt;source是测试视频路径,也可以换成图片文件夹;conf=0.25是置信度阈值,低于这个值的结果会被过滤掉;save=True表示把标注后的结果保存下来。跑完后在runs/detect/predict目录下会生成带框的视频,这个视频就是答辩现场的核心演示材料。

如果发现视频里漏检多,先降conf到 0.15 再看看;如果发现误检多(路牌、树影被框出来),就升到 0.4 左右。置信度阈值是最直接的调节旋钮,不用重新训练。另外,save_txt=True可以额外保存每个目标的坐标和置信度到 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 memory,GPU 显存被耗尽。

原因:最常见的情况是 batch size 设置过大,或者是 YOLOv8 的 cache 参数默认把数据缓存到显存导致占用飙升。另外,如果开了多个程序占用显存没释放,也会直接触发。

解决:把batch从 16 降到 8 或 4;imgsz从 640 降到 512;加上cache=False参数强制不对数据做显存缓存;关掉其他占显存的进程。如果这些都做了还是不够,说明显卡实在带不动当前模型规格,换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, conf=0.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(host="0.0.0.0", port=5000)

这段代码把模型加载做在服务启动阶段,避免每次请求都重新加载权重;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 数字。这套流程做完,模型、接口、视频、问答都有了,系统才算真正闭环。希望这个方向和这些具体做法能帮到你,少走点我当年走过的弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 3:07:40

告别 node_modules,Yarn PnP 原理与实战全攻略

前端圈子里对 node_modules 的感情&#xff0c;差不多是又爱又恨。十年了&#xff0c;我们早就习惯它的存在&#xff0c;可它带来的问题也越来越让人无法假装看不见。前几天我帮朋友清理一台开发机&#xff0c;磁盘里躺着十几个前端项目&#xff0c;每个 node_modules 动辄几个…

作者头像 李华
网站建设 2026/9/26 3:06:33

手机写代码实战:Termux、云端IDE与远程开发选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 3:05:50

操作系统学习笔记(二) 进程、线程与协程

操作系统学习笔记(二) 进程、线程与协程 一、三种抽象处在不同层级 进程、线程、协程不是互相替代的三个方案——一个服务可以启动多个进程&#xff0c;每个进程拥有若干线程&#xff0c;其中某个线程再运行事件循环&#xff0c;承载成千上万个协程。它们可以组成一棵执行树&am…

作者头像 李华
网站建设 2026/9/26 3:05:28

Claude Code提示词模板实战:分类写法、接入技巧与避坑指南

用Claude Code做AI辅助编程也有几个月了&#xff0c;工具本身好上手&#xff0c;真正拉开体验差距的&#xff0c;往往不是模型本身的能力&#xff0c;而是你给它的提示词。claude-code-templates这类资源&#xff0c;说白了就是把“你让Claude做什么、按什么规矩做、输出成什么…

作者头像 李华
网站建设 2026/9/26 3:02:59

FDE银行落地:多智能体系统正成为驱动运营跃迁的新引擎。技术、流程与人才的深度协同,将为亚洲银行释放强大的综合效能。

多智能体系统正成为驱动运营跃迁的新引擎。技术、流程与人才的深度协同&#xff0c;将为亚洲银行释放强大的综合效能。过去几年&#xff0c;人工智能的技术浪潮一波接一波。从预测式AI、生成式AI&#xff0c;到如今快速崛起的AI智能体&#xff0c;每一次新技术登场&#xff0c;…

作者头像 李华