YOLO11积水图像分割检测:从数据集划分到PyQt摄像头界面全流程 简介本资源面向计算机视觉入门与进阶开发者提供一套基于Python与PyTorch的积水图像分割检测完整方案核心采用YOLOv11模型并集成PyQt可视化界面与摄像头实时识别功能可用于城市排水监测、户外安全预警等场景的二次开发与课程实践。压缩包共1108个文件约424.92MB其中442张jpg为积水图像样本429个txt与214个json为标注及配置数据另有4个pt权重文件、3个yaml模型配置、3个py脚本及png、csv等辅助文件覆盖数据集、训练权重与推理代码。使用流程清晰先运行01划分数据集.py完成训练集与测试集切分再执行02train.py训练模型最后通过03pyqt.py启动界面进行摄像头实时检测。目前已有98人学习下载适合希望快速跑通分割训练、理解YOLOv11工程结构并获取可复用数据集的读者参考。1. 积水图像分割检测从数据集到 PyQt 界面的完整落地路径城市内涝预警、地下车库进水、隧道积水监测这些场景对“实时识别积水区域”有硬需求。我拿到这个资源包时第一反应是它把 YOLO11 的图像分割能力直接绑到了积水检测这个具体任务上而且给了数据集、训练脚本和 PyQt 摄像头界面不是那种只丢一个模型权重的“半成品”。整个包基于 Python PyTorch核心是 YOLO11 的实例分割分支能输出积水区域的像素级掩码而不是只画个框。适合谁做安防监控二次开发的、搞智慧城市 demo 的、或者想学 YOLO11 分割任务怎么从零跑通的学生。如果你手头正好有积水场景的图片或视频流这套代码能让你在半天内看到分割效果不用自己从头搭训练管线。2. YOLO11 分割任务拆解为什么选它做积水检测2.1 从检测框到像素掩码分割头到底在算什么YOLO11 的检测分支输出的是每个目标的边界框和类别概率而分割分支额外挂了一个原型掩码生成网络和一组掩码系数。推理时每个检测框会对应一组系数与原型掩码做线性组合再裁剪到框内就得到该目标的像素级掩码。积水检测为什么需要这个因为积水区域形状极不规则边界框会包含大量非积水像素比如路面、标线、车辆底盘。用分割掩码才能准确算出积水面积、轮廓甚至做水位估算。YOLO11 相比前代在分割头里引入了更轻量的原型生成模块在保持掩码质量的同时把参数量压下来这对边缘设备部署很关键。2.2 数据集划分脚本01划分数据集.py 里藏着的三个参数资源包里的01划分数据集.py不是简单随机切分。我拆开看它默认按 8:1:1 分训练、验证、测试但实际代码里留了train_ratio、val_ratio两个变量测试集比例是自动补全的。更关键的是它做了分层抽样——如果数据集中有“无积水”的负样本脚本会保证每个子集里正负样本比例一致。这个细节很多开源项目会忽略导致验证集里全是负样本mAP 虚高。运行前你需要确认数据集目录结构是images/和labels/平行且标签是 YOLO 分割格式的 txt每行类别 x1 y1 x2 y2 ...归一化坐标。脚本会生成train.txt、val.txt、test.txt三个索引文件路径写的是绝对路径换机器跑要改data_root。# 01划分数据集.py 核心逻辑节选 import os, random from sklearn.model_selection import train_test_split data_root rD:\water_dataset # 改成你的数据集根目录 img_dir os.path.join(data_root, images) label_dir os.path.join(data_root, labels) # 收集所有图片文件名不带扩展名 names [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)] # 分层依据标签文件是否为空空表示无积水负样本 labels [1 if os.path.getsize(os.path.join(label_dir, n .txt)) 0 else 0 for n in names] train_names, test_names, train_labels, test_labels train_test_split( names, labels, test_size0.2, stratifylabels, random_state42 ) val_names, test_names train_test_split( test_names, test_size0.5, stratifytest_labels, random_state42 ) # 后续写入 train.txt / val.txt / test.txt每行一个绝对路径逻辑说明stratifylabels保证正负样本在切分后比例一致。random_state42固定随机种子方便复现。参数怎么改如果数据集很小少于 500 张把test_size调到 0.1验证集从训练集里再切避免测试集样本太少导致指标波动大。注意标签文件必须和图片同名同目录层级否则脚本会报FileNotFoundError。2.3 训练脚本 02train.py显存不够时先动这三个地方02train.py用的是 Ultralytics 风格的训练接口但资源包里把配置写成了 argparse 参数。默认batch16、imgsz640、epochs100。如果你只有 6GB 显存直接跑会 OOM。我一般按这个顺序降先把batch降到 8再把imgsz降到 512最后才动workers。workers是数据加载线程数Windows 下设太高反而慢建议 4 或 8。学习率默认lr00.01对积水分割这种小数据集我习惯降到 0.001 并加cos_lrTrue让学习率余弦衰减收敛更稳。还有一个隐藏坑02train.py里model参数默认加载yolo11n-seg.pt如果你要更高精度换成yolo11s-seg.pt或yolo11m-seg.pt但显存占用会翻倍。# 训练命令示例在 02train.py 同级目录下运行 python 02train.py --data data.yaml --weights yolo11n-seg.pt --epochs 100 --batch 8 --imgsz 512 --lr0 0.001 --cos_lr --workers 4参数说明--data指向数据集配置文件里面写train: train.txt、val: val.txt、nc: 1、names: [water]。--weights是预训练权重不写则从头训练但小数据集从头训基本没效果。--cos_lr开启余弦退火。训练日志和权重默认存在runs/segment/train/下results.csv记录每轮 loss 和 mAPevents.out.tfevents...是 TensorBoard 日志用tensorboard --logdir runs可以看曲线。3. PyQt 界面与摄像头识别03pyqt.py 的线程模型和推理封装3.1 为什么不能直接在 Qt 主线程里跑模型推理03pyqt.py用 PyQt5 搭界面左边是摄像头画面右边是分割结果和统计信息。如果你把model.predict()直接写在按钮回调里界面会卡死——因为推理是同步阻塞的主线程一卡Qt 事件循环就停转窗口直接“未响应”。资源包里用了一个QThread子类InferenceThread把摄像头读取和模型推理都放在子线程通过信号frame_ready把带掩码的帧发回主线程刷新 QLabel。这个设计是对的但有个细节子线程里不能直接操作 UI 组件必须用信号槽。我见过有人图省事在子线程里self.label.setPixmap()结果随机崩溃血泪经验。# 03pyqt.py 线程类核心结构 from PyQt5.QtCore import QThread, pyqtSignal import cv2 from ultralytics import YOLO class InferenceThread(QThread): frame_ready pyqtSignal(object) # 发送带掩码的帧 def __init__(self, model_path, cam_id0): super().__init__() self.model YOLO(model_path) self.cap cv2.VideoCapture(cam_id) self.running True def run(self): while self.running: ret, frame self.cap.read() if not ret: continue results self.model.predict(frame, imgsz640, conf0.25, verboseFalse) annotated results[0].plot() # 直接画掩码和框 self.frame_ready.emit(annotated) def stop(self): self.running False self.cap.release() self.wait()逻辑说明conf0.25是置信度阈值积水检测建议调到 0.3 以上减少路面反光误检。results[0].plot()返回的是 BGR numpy 数组可以直接转 QImage。注意verboseFalse关掉每帧打印否则控制台刷屏拖慢速度。cam_id0是默认摄像头如果你用 USB 摄像头且电脑有内置摄像头可能要改成 1 或 2。3.2 摄像头识别延迟高先查这三个环节实时性是这个项目的卖点但实际跑起来有人反馈“画面延迟两秒”。我排查下来通常是三个原因第一imgsz设了 640 但摄像头分辨率是 1080p每帧都要缩放改成imgsz320能快一倍精度掉得不多第二model.predict默认streamFalse每帧都重新初始化推理引擎改成streamTrue用生成器模式但要注意stream模式下results是迭代器得用for r in results取第三Qt 的QLabel刷新用了setPixmap但没调repaint()画面堆积。我一般会在frame_ready槽函数里先self.label.clear()再设新图强制释放旧资源。3.3 分割结果后处理从掩码到积水面积估算results[0].masks里存的是原始掩码数据results[0].masks.data是 tensor形状[n, h, w]每个通道对应一个检测实例。如果你想算积水面积占比可以这样先取masks.data[0].cpu().numpy()二值化后统计非零像素数除以总像素数。但注意这个掩码是模型输入尺寸比如 640x640下的要映射回原始帧尺寸才能算真实面积。资源包里没做这个映射我补了一段import numpy as np def calc_water_ratio(result, orig_shape): if result.masks is None: return 0.0 mask result.masks.data[0].cpu().numpy() # 取第一个实例 mask cv2.resize(mask, (orig_shape[1], orig_shape[0]), interpolationcv2.INTER_NEAREST) return np.count_nonzero(mask) / (orig_shape[0] * orig_shape[1])参数说明orig_shape是原始帧的(height, width)。INTER_NEAREST保持二值性别用线性插值。这个比例可以显示在 PyQt 界面上超过阈值就弹预警。4. 避坑与排查跑通这套代码前必须知道的五件事4.1 现象运行 02train.py 报 “No labels found”原因data.yaml里的train和val路径写的是相对路径但脚本工作目录不对。或者01划分数据集.py生成的 txt 里是绝对路径换机器后路径失效。解决打开train.txt检查第一行路径是否存在统一改成相对于data.yaml的路径比如images/xxx.jpg并在data.yaml里写path: D:/water_dataset。4.2 现象PyQt 界面能开但摄像头画面全黑原因OpenCV 的VideoCapture在 Windows 下默认用 MSMF 后端某些摄像头不兼容。解决在cv2.VideoCapture(cam_id)后面加cv2.CAP_DSHOW即cv2.VideoCapture(cam_id, cv2.CAP_DSHOW)。如果还不行换cv2.CAP_MSMF试试。Linux 下一般不用改。4.3 现象训练 loss 降到 0.1 以下但验证集 mAP 只有 0.2原因过拟合。积水数据集如果背景单一比如全是灰色路面模型会记住背景而不是积水特征。解决在02train.py里加数据增强参数--degrees 10 --translate 0.1 --scale 0.5 --fliplr 0.5并开启--mosaic 1.0。另外把dropout调到 0.1YOLO11 分割头支持。4.4 现象03pyqt.py 运行报 “No module named ‘PyQt5.sip’”原因PyQt5 安装不完整或者 Python 版本和 PyQt5 轮子不匹配。解决先pip uninstall PyQt5 PyQt5-sip再pip install PyQt55.15.9 PyQt5-sip12.12.2。别用pip install pyqt5-tools那个会带一堆没用的依赖。4.5 现象推理结果里积水掩码边缘锯齿严重原因模型输出掩码分辨率低plot()直接放大导致锯齿。解决在predict里加retina_masksTrue让掩码在原图分辨率上生成代价是推理慢 10% 左右。或者后处理时用cv2.morphologyEx做开运算平滑边缘。5. 进阶技巧用 TensorBoard 盯住分割指标别只看 loss训练跑起来后results.csv里有一列metrics/mAP50-95(M)这是分割掩码的平均精度比检测框的 mAP 更能反映积水区域贴合度。我习惯在训练中途用 TensorBoard 看train/seg_loss和val/seg_loss的 divergence如果验证 loss 连续 10 轮不降就手动停掉别等 100 轮跑完。另外events.out.tfevents...文件可以直接拖进 TensorBoard 的--logdir目录不用改代码。还有一个技巧把03pyqt.py里的model.predict换成model.track加上persistTrue就能对视频流里的积水区域做 ID 跟踪适合做积水扩散趋势分析。最后说个我自己的习惯每次改完data.yaml或训练参数先跑python 02train.py --epochs 1做冒烟测试确认数据加载和模型前向不报错再开长训练。从那以后我每次动数据集划分脚本都强制先跑一遍01划分数据集.py并检查三个 txt 的行数比例避免训练到一半发现验证集是空的。希望帮到你。本文还有配套的精品资源点击获取