ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于YOLOv8的智慧城市道路积水深度视觉检测系统:从数据集标注到Gradio可视化部署

2026/10/2 9:08:16 拓冰建站 浏览量
基于YOLOv8的智慧城市道路积水深度视觉检测系统:从数据集标注到Gradio可视化部署 简介这份资源面向计算机、人工智能、通信工程、自动化等专业的在校学生与教师提供一套基于YOLOv8的智慧城市道路积水深度视觉检测完整方案可用于毕业设计、课程设计、大作业或项目初期立项演示。压缩包共8个文件约15.91MB包含3个Python脚本、3个模型权重文件与2个说明文本分别承担可视化界面、模型训练、视频检测推理以及预训练权重与使用说明等职责部署流程简单基础尚可者也可在源码上二次修改扩展功能。项目代码均经实际运行验证可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图为答辩提供直观的量化支撑。目前已有121人学习下载适合希望快速获得可运行检测系统、对照完整数据集与可视化页面进行学习或直接用于毕设场景的读者参考使用。1. 道路积水深度视觉检测从一张监控截图到可交付的毕设系统城市内涝的痛点不在于“有没有水”而在于“水有多深、能不能过车”。传统做法靠人工巡查或固定水位标尺覆盖稀疏、响应滞后。这套基于 YOLOv8 的智慧城市道路积水深度视觉检测系统思路是用已有的道路监控摄像头画面先检测积水区域再结合参照物如路缘石、护栏底座、车轮反推水深等级最后在可视化界面上给出分级预警。它适合做毕设或课程设计的同学也适合想快速验证“视觉积水”这条技术路线的工程师。整套方案包含源码、标注好的数据集、可视化界面和部署教程简单部署即可运行不需要从零标注和搭框架。下面按“数据怎么来、模型怎么训、界面怎么接、坑在哪”的顺序拆开讲每一步都给出可复现的命令和参数。2. 数据集构建与 YOLOv8 训练从 Labelme 标注到损失曲线2.1 积水数据集怎么标类别定义与标注规范道路积水检测和通用目标检测最大的区别在于“边界模糊”。水面和湿滑路面在灰度上接近标注时如果只框“明显积水”模型会漏掉薄水膜如果框太宽又会把阴影算进去。我一般把类别定为三类shallow浅积水水深小于 5cm、medium中等积水5~15cm、deep深积水大于 15cm。标注时以水面反光区域的外接矩形为准遇到树影遮挡就按可见水面延伸补全不要留缺口。用 Labelme 标注后每张图会生成一个 JSON。转 YOLO 格式的脚本如下import json import os from pathlib import Path # 类别映射顺序必须和 data.yaml 里的 names 一致 CLASS_MAP {shallow: 0, medium: 1, deep: 2} def labelme_to_yolo(json_dir, out_dir, img_w1920, img_h1080): out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) for jf in Path(json_dir).glob(*.json): data json.loads(jf.read_text(encodingutf-8)) lines [] for shape in data[shapes]: label shape[label] if label not in CLASS_MAP: continue pts shape[points] xs [p[0] for p in pts] ys [p[1] for p in pts] # 转成 YOLO 的归一化中心点宽高 xc (min(xs) max(xs)) / 2 / img_w yc (min(ys) max(ys)) / 2 / img_h w (max(xs) - min(xs)) / img_w h (max(ys) - min(ys)) / img_h lines.append(f{CLASS_MAP[label]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) txt_path out_dir / (jf.stem .txt) txt_path.write_text(\n.join(lines), encodingutf-8) labelme_to_yolo(./labels_json, ./labels_yolo)这段脚本做了三件事读 JSON、按类别映射过滤、把多边形外接矩形转成 YOLO 需要的归一化格式。img_w和img_h必须和实际图片分辨率一致否则框会整体偏移。如果图片来自不同摄像头分辨率不统一建议先统一 resize 到 1920×1080 再标注省去后续换算的麻烦。2.2 用 YOLOv8 训练自己的积水数据集环境配置与关键参数环境配置是新手翻车最多的地方。Ubuntu 20.04 下 CPU 版本也能跑通只是慢。命令如下conda create -n yolo8 python3.9 -y conda activate yolo8 pip install ultralytics opencv-python labelme -i https://pypi.tuna.tsinghua.edu.cn/simple装完后用yolo checks验证。如果报libGL.so.1缺失执行sudo apt install libgl1。有 GPU 的话装对应 CUDA 版本的 torchGTX 1660Ti 跑 YOLOv8n 大概 20 分钟一轮CPU 可能要两三个小时。数据集目录按下面组织datasets/ water/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml内容path: ./datasets/water train: images/train val: images/val nc: 3 names: [shallow, medium, deep]训练命令yolo detect train modelyolov8n.pt datadatasets/water/data.yaml epochs100 imgsz640 batch16 lr00.01 patience20参数含义imgsz640是输入尺寸积水区域通常占画面比例不大640 够用batch16显存不够就降到 8lr00.01是初始学习率YOLOv8 默认就是这个值数据集小于 2000 张时可以降到 0.005 防止过拟合patience20表示 20 轮验证指标不提升就早停。训练完在runs/detect/train/下能看到results.csv用下面脚本画损失曲线import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns df.columns.str.strip() plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(loss_curve.png, dpi150)看曲线时重点看验证损失有没有反弹。如果训练损失一直降、验证损失从第 30 轮开始往上走说明过拟合要么加数据增强要么减模型复杂度。YOLOv8 自带的 mosaic、mixup 增强对积水场景有帮助因为水面反光在不同角度下差异大增强能提升泛化。3. 积水深度分级与可视化界面从检测框到预警输出3.1 深度分级逻辑参照物标定与像素比例换算YOLOv8 只给出积水区域的框深度需要额外推算。常见做法是在画面里找一个已知尺寸的参照物比如路缘石高度通常 15cm、护栏底座 20cm、标准车轮直径 65cm。标定时在画面上量出参照物的像素高度算出“像素/厘米”比例再用积水区域在垂直方向上的像素跨度反推水深。def estimate_depth(box_h_px, ref_h_px, ref_real_cm): # box_h_px: 积水框的像素高度 # ref_h_px: 参照物像素高度 # ref_real_cm: 参照物实际厘米数 px_per_cm ref_h_px / ref_real_cm depth_cm box_h_px / px_per_cm if depth_cm 5: return shallow, depth_cm elif depth_cm 15: return medium, depth_cm else: return deep, depth_cm这个换算假设摄像头光轴水平、积水区域在参照物同一纵深平面上。实际场景里摄像头有俯角越远的区域像素比例越小所以最好按画面分区标定近景区、中景区、远景区各标一组比例。如果只做毕设演示单组比例够用如果要落地建议加透视校正或直接用深度学习回归水深但那是另一个课题了。3.2 可视化界面怎么接Gradio 快速搭建与推理封装可视化界面用 Gradio 最省事几十行代码就能跑起来支持上传图片、实时摄像头和视频流。核心是把 YOLOv8 推理和深度分级串起来import gradio as gr from ultralytics import YOLO import cv2 import numpy as np model YOLO(runs/detect/train/weights/best.pt) def detect_water(img): results model(img, conf0.4, iou0.5) annotated results[0].plot() # 统计各类别数量 names results[0].names counts {} for cls in results[0].boxes.cls.tolist(): name names[int(cls)] counts[name] counts.get(name, 0) 1 summary | .join([f{k}: {v} for k, v in counts.items()]) return annotated, summary demo gr.Interface( fndetect_water, inputsgr.Image(typenumpy), outputs[gr.Image(typenumpy), gr.Textbox(label积水等级统计)], title道路积水深度视觉检测 ) demo.launch(server_name0.0.0.0, server_port7860)conf0.4是置信度阈值积水反光弱时调到 0.3 能多召回一些但误检也会增加iou0.5是 NMS 的 IoU 阈值积水区域重叠多时可以降到 0.4。results[0].plot()直接返回带框的图省去手动画框。界面启动后浏览器访问http://localhost:7860就能用。如果要部署到服务器加shareFalse并配好端口映射。4. 部署与推理加速从本地跑通到边缘设备4.1 模型导出与 ONNX 推理CPU 上的提速方案PyTorch 模型在 CPU 上推理慢导出 ONNX 能快 2~3 倍。命令yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 simplifyTrue导出后用 onnxruntime 推理import onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 img np.expand_dims(img, 0) outputs sess.run(None, {sess.get_inputs()[0].name: img})注意预处理要和训练时一致BGR 转 RGB、归一化到 0~1、HWC 转 CHW。ONNX 输出的框需要自己写 NMS或者直接用 ultralytics 的YOLO(best.onnx)接口它会自动处理。4.2 边缘设备部署RK3588 与 Orin 的适配要点RK3588 和 Orin 是常见的边缘部署平台。RK3588 需要把 ONNX 转成 RKNN 格式用 rknn-toolkit2 转换注意量化时用一批积水图片做校准否则精度掉得厉害。Orin 上可以直接跑 TensorRT用yolo export formatengine导出但 engine 文件绑定设备换机器要重新导出。GTX 1660Ti 这类桌面卡跑 TensorRT 也能提速但毕设场景 CPU 或 ONNX 就够了不必折腾。5. 避坑与排查积水检测里最容易翻车的 5 个点5.1 现象模型把湿滑路面全框成积水原因训练集里湿滑路面样本太少模型没学会区分“反光”和“积水”。解决在标注时专门加一批湿滑但无积水的负样本或者在data.yaml里加一个wet_road类别让模型显式学习这个区分。5.2 现象训练损失正常但验证 mAP 一直很低原因验证集和训练集来自同一段视频的相邻帧数据泄漏导致验证指标虚高或虚低。解决按视频片段划分训练/验证不要按帧随机分。同一段路的连续帧只能出现在一个集合里。5.3 现象Gradio 界面上传图片后报尺寸错误原因YOLOv8 要求输入尺寸是 32 的倍数用户上传的图片尺寸任意。解决在推理前统一 resize 到 640×640或者用model(img, imgsz640)让 ultralytics 内部处理。注意 resize 后框的坐标要映射回原图再画。5.4 现象ONNX 推理结果和 PyTorch 不一致原因预处理没对齐。PyTorch 版 ultralytics 默认做了 letterbox 填充自己写 ONNX 预处理时如果直接 resize 会变形。解决用 ultralytics 的YOLO(best.onnx)接口或者自己实现 letterbox按长边缩放、短边填灰边。5.5 现象深度分级结果跳变严重原因参照物像素高度在不同帧里检测不稳定导致比例波动。解决对参照物检测加滑动平均或者固定参照物位置手动标定一次不要每帧重算。毕设演示时手动标定最稳。6. 进阶技巧用分割模型替代检测框提升深度估算精度检测框只能给外接矩形积水形状不规则时框的高度和实际水深偏差大。把 YOLOv8 换成yolov8n-seg.pt做实例分割拿到积水区域的像素掩码再取掩码在垂直方向上的最大跨度作为水深估算依据精度会明显提升。训练分割模型的数据标注要用 Labelme 的多边形转 YOLO 分割格式时保留多边形点而不是外接矩形。yolo detect train modelyolov8n-seg.pt datadatasets/water_seg/data.yaml epochs100 imgsz640分割格式的标签每行是class x1 y1 x2 y2 ...点按顺时针排列。推理后用results[0].masks拿掩码计算掩码的 boundingRect 高度。代价是推理速度比检测慢 30% 左右边缘设备上要权衡。另一个技巧是加注意力机制。YOLOv8 的 head 部分可以插入协调注意力Coordinate Attention对水面反光这种纹理弱的区域更敏感。改法是找到ultralytics/nn/modules/head.py在 Detect 类里加 CA 模块然后重新训练。改完记得用yolo checks验证模型结构没报错。我自己做这类项目最大的教训是不要一上来就调模型先把数据标清楚、把参照物标定做稳。模型再强标定偏了深度就是错的。另一个习惯是每训完一版就把results.csv和几张典型推理图存下来后面写论文或答辩时直接翻记录比回忆靠谱。希望帮到你。本文还有配套的精品资源点击获取