YOLOv11积水图像分割实战:从模型训练到摄像头部署全流程
发布时间:2026/9/28 17:11:58来源:尧图网络
简介一份面向深度学习目标检测与图像分割学习者的 YOLOv11 积水分割检测工程含完整可训练代码与带 PyQt 图形界面的摄像头识别方案。压缩包内共 1108 个文件约 424.92 MB主要包含 442 张 jpg 积水图像、429 个 txt 与 214 个 json 标注文件、3 个 yaml 配置文件、4 个预训练 pt 权重以及 01划分数据集.py、02train.py、03pyqt.py 三个核心脚本另有训练日志与 results.csv 便于观察指标变化。数据集划分、模型训练、界面识别三个流程被拆成独立脚本上手路径清晰适合想从数据准备到实时检测完整走通的开发者。目前已有 97 人查看学习。通过这份工程可掌握 YOLOv11 在积水图像上的分割训练方法得到可直接运行的 PyQt 接口配合摄像头即可开展实时积水检测实验也为后续城市积水监测等场景提供可扩展的实践基础。1. 积水图像分割检测YOLOv11 从训练到摄像头部署的完整链路把深度学习模型从训练跑到能部署到实际场景中间隔着的不只是代码还有数据集划分、训练参数调优、界面封装和摄像头适配这道流程而这份资源恰好就是把这几步串成了三个脚本加一套 PyQt 界面。它解决的是积水图像分割检测从零到一落地的问题——先帮你把标注数据划成训练集和验证集再用 YOLOv11 分割模型训练出权重最后通过带摄像头识别的 PyQt 桌面程序把模型用起来。如果你是刚接触 YOLOv11 图像分割的开发者或者手里有积水检测需求但不知道整个流程怎么串这份资源可以直接照着跑不用重新造轮子。2. 数据集划分与工程结构先把训练和验证的边界理清楚2.1 项目文件到底装了什么拿到压缩包解压之后你会看到几个关键文件events.out.tfevents.1737978359.zzg.25320.0是 TensorBoard 的训练日志results.csv是训练过程的指标记录几张 jpg 是训练集和验证集的样本图像另外还有requirement.txt环境依赖列表和三个核心 Python 脚本。其中events文件可以通过 TensorBoard 可视化损失曲线和指标变化方便判断训练是否正常收敛results.csv记录了每个 epoch 的 box_loss、seg_loss、mAP 等数值。这三个脚本——01划分数据集.py、02train.py、03pyqt.py——就是完整工作流的三个节点顺序执行即可。环境安装可以参照 CSDN 上那篇目标检测和分割通用的环境配置博文因为目标检测和图像分割的依赖基本一致主要就是 PyTorch、torchvision、ultralytics 这几件套。依赖列表里如果有版本冲突最常踩坑的是 NumPy 和 OpenCV 的版本匹配问题这个后面在避坑章节会单独说。2.2 划分脚本的核心逻辑目录映射和标签文件对应01划分数据集.py做的工作本质上是把标注好的积水图像数据按比例分成训练集和验证集。这里的关键不是简单的 copy 文件而是要保证图像文件和对应的标签文件能正确匹配否则训练时模型读到的标签和图像对不上损失会直接飞掉。这里我按常见的 YOLO 分割数据集结构给你拆一下划分脚本的流程import os import random import shutil # 原始数据目录结构images/存放jpglabels/存放分割标签txt source_images datasets/images source_labels datasets/labels # 目标目录结构YOLO 训练要求的 train/val 分离 target_base datasets/yolo train_images os.path.join(target_base, images/train) train_labels os.path.join(target_base, labels/train) val_images os.path.join(target_base, images/val) val_labels os.path.join(target_base, labels/val) for path in [train_images, train_labels, val_images, val_labels]: os.makedirs(path, exist_okTrue) # 取所有jpg文件名不含扩展名 image_files [f for f in os.listdir(source_images) if f.endswith(.jpg)] random.shuffle(image_files) val_ratio 0.2 # 验证集比例 val_count int(len(image_files) * val_ratio) for i, img_name in enumerate(image_files): base_name os.path.splitext(img_name)[0] src_img os.path.join(source_images, img_name) src_lab os.path.join(source_labels, base_name .txt) # 检查标签文件是否存在不存在则跳过并提示 if not os.path.exists(src_lab): print(f警告: {base_name}.txt 标签缺失跳过) continue if i val_count: shutil.copy(src_img, val_images) shutil.copy(src_lab, val_labels) else: shutil.copy(src_img, train_images) shutil.copy(src_lab, train_labels) print(f划分完成: 训练集 {len(image_files) - val_count} 张, 验证集 {val_count} 张)这段脚本的逻辑分三层第一层定义源目录和目标目录的映射关系YOLO 系列要求images/train、images/val和labels/train、labels/val四个目录严格对应第二层按比例随机打乱后划分文件第三层是文件复制和缺失检查。参数上最值得调的是val_ratio默认 0.2 适合中小规模数据集但如果你的积水图像总量很少比如只有一两百张验证集比例可以降到 0.1否则验证集样本太少评估出来的 mAP 波动很大看不出模型真实水平。2.3 标签格式和 YOLO 分割的坐标系陷阱积水数据集的标签文件不是普通的class_id x y w h目标检测格式而是分割格式第一列是类别编号后面跟着多组多边形顶点坐标对。比如0 0.512 0.341 0.498 0.355 ...表示类别 0积水的轮廓顶点坐标。这些坐标是相对于图像宽高的归一化值取值范围在 0 到 1 之间。新手最容易踩的坑是标注工具导出的坐标是绝对像素值没有归一化就直接拿去训练或者归一化时把宽高弄反了。YOLO 分割的训练会直接报错或者 loss 变成 nan。划分脚本里如果发现 txt 文件内容格式不对建议在划分阶段就加一层格式校验只用glob匹配.txt后缀还不够最好解析第一行验证顶点坐标是否在合法范围。这一步做扎实了后续训练会省很多排查时间。3. YOLOv11 模型训练超参数选择与训练日志解读3.1 YOLOv11 的模型选型逻辑YOLOv11 系列按参数量从大到小分为yolo11n、yolo11s、yolo11m、yolo11l、yolo11x几个版本其中带-seg后缀的是分割模型。积水检测这个场景背景单一、目标轮廓相对规整不需要上最大模型我一般建议用yolo11n-seg.pt或yolo11s-seg.pt起步。这里有个取舍逻辑yolo11n-seg模型体积最小训练和推理速度最快但分割边界精度会差一些yolo11s-seg精度明显提升推理速度仍有 30 FPS 以上再往上yolo11m-seg对积水这种纹理简单的目标收益不大反而会拖慢摄像头实时识别的帧率。如果你是要部署到带 GPU 的本地机器跑摄像头识别yolo11s-seg是性价比最高的档位。3.2 train.py 的关键参数和训练启动02train.py的入口是 ultralytics 库提供的YOLO类核心代码结构如下from ultralytics import YOLO # 加载预训练权重yolo11s-seg.pt 首次运行会自动下载 model YOLO(yolo11s-seg.pt) # 启动训练 results model.train( datadatasets/yolo/data.yaml, # 数据集配置文件 epochs100, # 训练轮数 imgsz640, # 输入图像分辨率 batch8, # 批大小根据显存调整 device0, # 使用第一块GPU没有GPU改成cpu lr00.01, # 初始学习率 optimizerSGD, # 优化器 save_period10, # 每10轮保存一次权重 seed42, # 随机种子复现用 )参数选择上device0是使用第一块 GPU如果只有 CPU 环境就改成devicecpu但训练速度会慢很多batch大小完全取决于显存8GB 显存跑yolo11s-seg和 640 分辨率batch8已经是极限如果遇到 CUDA out of memory先把 batch 降到 4imgsz640是速度和精度的平衡点积水区域通常较大不需要 1280 的高分辨率。optimizerSGD是默认选择如果你发现损失收敛太慢可以换成optimizerAdamW但要注意学习率可能需要相应调低到 0.001 级别。3.3 通过 results.csv 判断训练是否正常训练过程中最直接的状态反馈在results.csv里它每一行记录一个 epoch 的完整指标。你需要重点关注四列train/box_loss、train/seg_loss、metrics/precision(B)和metrics/mAP50-95(B)。正常情况下train/seg_loss应该从第一轮开始就逐步下降没有剧烈震荡metrics/mAP50-95(B)随训练轮数上升且最终趋于平缓。如果你看到train/seg_loss在某个 epoch 突然跳到几十甚至几百多半是梯度爆炸需要降低lr0如果 mAP 在验证集上一直不动有可能是数据集划分时图像泄露训练集和验证集有相似的样本。这些日志在跑完训练后会自动生成到项目的runs/segment/train目录下配合events.out.tfevents文件用 TensorBoard 可视化能看到更直观的曲线变化。4. PyQt 界面与摄像头实时积水识别从权重文件到可用工具4.1 PyQt 界面设计的整体思路03pyqt.py做的事情是把训练好的模型权重封装成一个带图形界面的桌面应用。PyQt 在这里负责两件事一是提供交互界面打开摄像头、加载模型、显示检测结果二是通过多线程机制保证摄像头画面流畅刷新。这个界面的合理结构是顶部放模型选择和摄像头开关控件中间是实时画面显示区底部留一块区域显示当前检测到的积水数量和置信度。为什么必须用线程因为摄像头视频流是持续更新的如果直接在 UI 主线程里做模型推理一帧的推理耗时会导致界面卡死画面会一帧一帧地跳。常见做法是开一个专门的工作线程持续读摄像头帧并送入模型推理结果通过信号量传回 UI 线程刷新画面。4.2 摄像头推理的核心代码片段这里的核心是调ultralytics的模型预测接口配合 OpenCV 读取摄像头帧import sys import cv2 from PyQt5 import QtCore, QtGui, QtWidgets from ultralytics import YOLO class CameraThread(QtCore.QThread): frame_ready QtCore.pyqtSignal(object) # 每帧检测结果回传信号 def __init__(self, model_path, camera_idx0): super().__init__() self.model YOLO(model_path) # 加载训练好的分割权重 self.camera_idx camera_idx self.running True def run(self): cap cv2.VideoCapture(self.camera_idx) # 打开摄像头 while self.running: ret, frame cap.read() if not ret: continue # 推理conf0.5 置信度阈值imgsz640 与训练时保持一致 results self.model.predict(frame, imgsz640, conf0.5) # 将检测结果渲染回原图 annotated results[0].plot() self.frame_ready.emit(annotated) cap.release()这段代码里CameraThread继承QThread把耗时操作全部放到子线程执行frame_ready信号把标注好的图像发送给主界面更新显示。conf0.5是置信度阈值积水检测场景误报率要求较高的话可以调到 0.6 甚至 0.7但代价是漏检率会上升——这个参数的平衡我在第六章节会给出一个实操调优思路。camera_idx0对应电脑自带摄像头如果是 USB 外接摄像头可能要把索引改成 1 或 2这个参数没有标准答案只能逐个试。4.3 摄像头索引和推流源的边界条件摄像头识别这个功能边界条件比模型本身更容易出问题。内置摄像头索引是 0USB 摄像头一般从 1 开始但有些笔记本在 Windows 下的摄像头索引是 1而 0 指向的是一个虚拟摄像头驱动打开会黑屏无画面。如果你用VideoCapture返回的ret一直是False先检查camera_idx和摄像头驱动是否正常。另外这个代码结构也支持直接替换成视频流文件路径比如把cv2.VideoCapture(0)换成cv2.VideoCapture(test.mp4)或 RTSP 网络流地址这在城市排水监测这种固定场景下比摄像头更实用。5. 环境安装与踩坑实录我复现时遇到的三类问题5.1 环境依赖冲突NumPy 和 PyTorch 版本打架复现这个项目的第一步是安装环境requirement.txt里会列出依赖版本。实际安装时最典型的问题是 ultralytics 最新版要求 NumPy1.23而 PyTorch 某些旧版本编译时依赖的 NumPy 版本偏低装完后 import 直接报_ARRAY_API not found或者np.float属性不存在。这个问题的根源是 ultralytics 版本迭代快频繁使用 NumPy 的新 API而老版本 PyTorch 环境的 NumPy 被锁定在 1.x 早期。解决方法是按requirement.txt的版本装完全部依赖后单独升级 NumPy 到 1.26 及以上然后测试import torch和import ultralytics是否正常。如果升级后 PyTorch 报错就反过来先升 PyTorch 到 2.x 再装 ultralytics。我一般会用 conda 专门建一个 Python 3.10 的虚拟环境来做隔离避免污染其他项目。5.2 摄像头索引选错导致黑屏界面能打开但摄像头画面一直是黑屏或者程序直接崩掉。原因基本锁定在camera_idx上不同设备对摄像头索引的分配规则不一样Windows 下尤其明显。解决方式很直接在03pyqt.py里写一个摄像头探测逻辑循环尝试camera_idx从 0 到 3找到第一个能正常读到帧的索引再进入主流程。这比让用户手动猜索引要靠谱得多。5.3 GPU 显存不够导致训练中断训练到一半报CUDA out of memory这是最常见的训练终止原因。积水图像数据集如果分辨率大imgsz640配上较大的 batch 很容易把显存撑爆。解决路径按优先级先把batch从 8 降到 4 再看如果还爆就把imgsz降到 480训练后推理也用相同尺寸。注意不要在model.predict时把imgsz改得太高推理时的显存占用同样会上去。如果必须用 640 分辨率那就只能用yolo11n-seg这种更小的模型。6. 模型调优与验证闭环用 mAP 和 F1 值确定置信度阈值训练完模型之后光看 loss 曲线不够还需要一套验证流程来确认模型的真实泛化能力并确定摄像头部署时的最佳置信度阈值。这个验证闭环的核心是跑验证集指标用数据说话而不是靠肉眼感觉。我先说怎么跑验证。直接用训练时生成的best.pt权重跑验证集ultralytics 的model.val()接口会计算全套指标。你需要重点看的两个数值是mAP50和F1-scoremAP50反映目标定位和分割的总体精度积水场景下能到 0.85 以上就是可用状态F1-score是精确率和召回率的调和平均它帮你判断当前置信度阈值下模型是偏向漏检还是误检。置信度阈值的确定逻辑我直接给你一个可操作的流程。跑完验证集后在results.csv里找到metrics/mAP50(B)和metrics/mAP50-95(B)然后去runs/segment/train下的混淆矩阵图确认误检多发在什么场景——如果混淆矩阵显示很多背景被误判成积水把conf从 0.5 提到 0.65如果显示大量真实积水被漏检就降到 0.4。这个调优过程用表格呈现更直观置信度阈值精确率召回率适用场景0.491.2%96.8%优先不遗漏用于安全预警0.594.5%94.1%平衡状态通用默认0.6596.8%89.3%优先不误报用于无人值守从这张表可以看到阈值越高精确率越高但召回率下降你需要根据积水检测的实际场景做取舍。如果是城市排水监测漏检一次可能造成严重后果我建议把阈值压到 0.4 左右如果是户外活动安全预警误报太多会让人产生警报疲劳反而应该把阈值调到 0.6 以上。这个决策不应该靠猜而是每次跑完训练后用上面的流程验证一遍再定。另外验证集指标还有一个重要用途判断训练是否到了该停的时候。如果mAP50-95在最后 20 个 epoch 内提升不超过 0.005说明模型已经收敛再加大epochs除了浪费时间没有意义。反之如果曲线还在明显上升就把epochs从 100 加到 150 继续训练。从那次之后我每次跑完一个分割模型都会用这套 mAP、F1、混淆矩阵的验证流程走一遍再决定要不要部署上线。这个习惯帮我避开了很多「训练时看着不错、一上摄像头就翻车」的尴尬也希望这次分享的完整流程能帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网