據(jù)集劃分到PyQt攝像頭界面全流程)
簡介本資源面向計算機(jī)視覺入門與進(jìn)階開發(fā)者提供一套基于Python與PyTorch的積水圖像分割檢測完整方案核心采用YOLOv11模型并集成PyQt可視化界面與攝像頭實時識別功能可用于城市排水監(jiān)測、戶外安全預(yù)警等場景的二次開發(fā)與課程實踐。壓縮包共1108個文件約424.92MB其中442張jpg為積水圖像樣本429個txt與214個json為標(biāo)注及配置數(shù)據(jù)另有4個pt權(quán)重文件、3個yaml模型配置、3個py腳本及png、csv等輔助文件覆蓋數(shù)據(jù)集、訓(xùn)練權(quán)重與推理代碼。使用流程清晰先運行01劃分?jǐn)?shù)據(jù)集.py完成訓(xùn)練集與測試集切分再執(zhí)行02train.py訓(xùn)練模型最后通過03pyqt.py啟動界面進(jìn)行攝像頭實時檢測。目前已有98人學(xué)習(xí)下載適合希望快速跑通分割訓(xùn)練、理解YOLOv11工程結(jié)構(gòu)并獲取可復(fù)用數(shù)據(jù)集的讀者參考。1. 積水圖像分割檢測從數(shù)據(jù)集到 PyQt 界面的完整落地路徑城市內(nèi)澇預(yù)警、地下車庫進(jìn)水、隧道積水監(jiān)測這些場景對“實時識別積水區(qū)域”有硬需求。我拿到這個資源包時第一反應(yīng)是它把 YOLO11 的圖像分割能力直接綁到了積水檢測這個具體任務(wù)上而且給了數(shù)據(jù)集、訓(xùn)練腳本和 PyQt 攝像頭界面不是那種只丟一個模型權(quán)重的“半成品”。整個包基于 Python PyTorch核心是 YOLO11 的實例分割分支能輸出積水區(qū)域的像素級掩碼而不是只畫個框。適合誰做安防監(jiān)控二次開發(fā)的、搞智慧城市 demo 的、或者想學(xué) YOLO11 分割任務(wù)怎么從零跑通的學(xué)生。如果你手頭正好有積水場景的圖片或視頻流這套代碼能讓你在半天內(nèi)看到分割效果不用自己從頭搭訓(xùn)練管線。2. YOLO11 分割任務(wù)拆解為什么選它做積水檢測2.1 從檢測框到像素掩碼分割頭到底在算什么YOLO11 的檢測分支輸出的是每個目標(biāo)的邊界框和類別概率而分割分支額外掛了一個原型掩碼生成網(wǎng)絡(luò)和一組掩碼系數(shù)。推理時每個檢測框會對應(yīng)一組系數(shù)與原型掩碼做線性組合再裁剪到框內(nèi)就得到該目標(biāo)的像素級掩碼。積水檢測為什么需要這個因為積水區(qū)域形狀極不規(guī)則邊界框會包含大量非積水像素比如路面、標(biāo)線、車輛底盤。用分割掩碼才能準(zhǔn)確算出積水面積、輪廓甚至做水位估算。YOLO11 相比前代在分割頭里引入了更輕量的原型生成模塊在保持掩碼質(zhì)量的同時把參數(shù)量壓下來這對邊緣設(shè)備部署很關(guān)鍵。2.2 數(shù)據(jù)集劃分腳本01劃分?jǐn)?shù)據(jù)集.py 里藏著的三個參數(shù)資源包里的01劃分?jǐn)?shù)據(jù)集.py不是簡單隨機(jī)切分。我拆開看它默認(rèn)按 8:1:1 分訓(xùn)練、驗證、測試但實際代碼里留了train_ratio、val_ratio兩個變量測試集比例是自動補全的。更關(guān)鍵的是它做了分層抽樣——如果數(shù)據(jù)集中有“無積水”的負(fù)樣本腳本會保證每個子集里正負(fù)樣本比例一致。這個細(xì)節(jié)很多開源項目會忽略導(dǎo)致驗證集里全是負(fù)樣本mAP 虛高。運行前你需要確認(rèn)數(shù)據(jù)集目錄結(jié)構(gòu)是images/和labels/平行且標(biāo)簽是 YOLO 分割格式的 txt每行類別 x1 y1 x2 y2 ...歸一化坐標(biāo)。腳本會生成train.txt、val.txt、test.txt三個索引文件路徑寫的是絕對路徑換機(jī)器跑要改data_root。# 01劃分?jǐn)?shù)據(jù)集.py 核心邏輯節(jié)選 import os, random from sklearn.model_selection import train_test_split data_root rD:\water_dataset # 改成你的數(shù)據(jù)集根目錄 img_dir os.path.join(data_root, images) label_dir os.path.join(data_root, labels) # 收集所有圖片文件名不帶擴(kuò)展名 names [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)] # 分層依據(jù)標(biāo)簽文件是否為空空表示無積水負(fù)樣本 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 ) # 后續(xù)寫入 train.txt / val.txt / test.txt每行一個絕對路徑邏輯說明stratifylabels保證正負(fù)樣本在切分后比例一致。random_state42固定隨機(jī)種子方便復(fù)現(xiàn)。參數(shù)怎么改如果數(shù)據(jù)集很小少于 500 張把test_size調(diào)到 0.1驗證集從訓(xùn)練集里再切避免測試集樣本太少導(dǎo)致指標(biāo)波動大。注意標(biāo)簽文件必須和圖片同名同目錄層級否則腳本會報FileNotFoundError。2.3 訓(xùn)練腳本 02train.py顯存不夠時先動這三個地方02train.py用的是 Ultralytics 風(fēng)格的訓(xùn)練接口但資源包里把配置寫成了 argparse 參數(shù)。默認(rèn)batch16、imgsz640、epochs100。如果你只有 6GB 顯存直接跑會 OOM。我一般按這個順序降先把batch降到 8再把imgsz降到 512最后才動workers。workers是數(shù)據(jù)加載線程數(shù)Windows 下設(shè)太高反而慢建議 4 或 8。學(xué)習(xí)率默認(rèn)lr00.01對積水分割這種小數(shù)據(jù)集我習(xí)慣降到 0.001 并加cos_lrTrue讓學(xué)習(xí)率余弦衰減收斂更穩(wěn)。還有一個隱藏坑02train.py里model參數(shù)默認(rèn)加載yolo11n-seg.pt如果你要更高精度換成yolo11s-seg.pt或yolo11m-seg.pt但顯存占用會翻倍。# 訓(xùn)練命令示例在 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參數(shù)說明--data指向數(shù)據(jù)集配置文件里面寫train: train.txt、val: val.txt、nc: 1、names: [water]。--weights是預(yù)訓(xùn)練權(quán)重不寫則從頭訓(xùn)練但小數(shù)據(jù)集從頭訓(xùn)基本沒效果。--cos_lr開啟余弦退火。訓(xùn)練日志和權(quán)重默認(rèn)存在runs/segment/train/下results.csv記錄每輪 loss 和 mAPevents.out.tfevents...是 TensorBoard 日志用tensorboard --logdir runs可以看曲線。3. PyQt 界面與攝像頭識別03pyqt.py 的線程模型和推理封裝3.1 為什么不能直接在 Qt 主線程里跑模型推理03pyqt.py用 PyQt5 搭界面左邊是攝像頭畫面右邊是分割結(jié)果和統(tǒng)計信息。如果你把model.predict()直接寫在按鈕回調(diào)里界面會卡死——因為推理是同步阻塞的主線程一卡Qt 事件循環(huán)就停轉(zhuǎn)窗口直接“未響應(yīng)”。資源包里用了一個QThread子類InferenceThread把攝像頭讀取和模型推理都放在子線程通過信號frame_ready把帶掩碼的幀發(fā)回主線程刷新 QLabel。這個設(shè)計是對的但有個細(xì)節(jié)子線程里不能直接操作 UI 組件必須用信號槽。我見過有人圖省事在子線程里self.label.setPixmap()結(jié)果隨機(jī)崩潰血淚經(jīng)驗。# 03pyqt.py 線程類核心結(jié)構(gòu) from PyQt5.QtCore import QThread, pyqtSignal import cv2 from ultralytics import YOLO class InferenceThread(QThread): frame_ready pyqtSignal(object) # 發(fā)送帶掩碼的幀 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是置信度閾值積水檢測建議調(diào)到 0.3 以上減少路面反光誤檢。results[0].plot()返回的是 BGR numpy 數(shù)組可以直接轉(zhuǎn) QImage。注意verboseFalse關(guān)掉每幀打印否則控制臺刷屏拖慢速度。cam_id0是默認(rèn)攝像頭如果你用 USB 攝像頭且電腦有內(nèi)置攝像頭可能要改成 1 或 2。3.2 攝像頭識別延遲高先查這三個環(huán)節(jié)實時性是這個項目的賣點但實際跑起來有人反饋“畫面延遲兩秒”。我排查下來通常是三個原因第一imgsz設(shè)了 640 但攝像頭分辨率是 1080p每幀都要縮放改成imgsz320能快一倍精度掉得不多第二model.predict默認(rèn)streamFalse每幀都重新初始化推理引擎改成streamTrue用生成器模式但要注意stream模式下results是迭代器得用for r in results取第三Qt 的QLabel刷新用了setPixmap但沒調(diào)repaint()畫面堆積。我一般會在frame_ready槽函數(shù)里先self.label.clear()再設(shè)新圖強(qiáng)制釋放舊資源。3.3 分割結(jié)果后處理從掩碼到積水面積估算results[0].masks里存的是原始掩碼數(shù)據(jù)results[0].masks.data是 tensor形狀[n, h, w]每個通道對應(yīng)一個檢測實例。如果你想算積水面積占比可以這樣先取masks.data[0].cpu().numpy()二值化后統(tǒng)計非零像素數(shù)除以總像素數(shù)。但注意這個掩碼是模型輸入尺寸比如 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])參數(shù)說明orig_shape是原始幀的(height, width)。INTER_NEAREST保持二值性別用線性插值。這個比例可以顯示在 PyQt 界面上超過閾值就彈預(yù)警。4. 避坑與排查跑通這套代碼前必須知道的五件事4.1 現(xiàn)象運行 02train.py 報 “No labels found”原因data.yaml里的train和val路徑寫的是相對路徑但腳本工作目錄不對?;蛘?1劃分?jǐn)?shù)據(jù)集.py生成的 txt 里是絕對路徑換機(jī)器后路徑失效。解決打開train.txt檢查第一行路徑是否存在統(tǒng)一改成相對于data.yaml的路徑比如images/xxx.jpg并在data.yaml里寫path: D:/water_dataset。4.2 現(xiàn)象PyQt 界面能開但攝像頭畫面全黑原因OpenCV 的VideoCapture在 Windows 下默認(rèn)用 MSMF 后端某些攝像頭不兼容。解決在cv2.VideoCapture(cam_id)后面加cv2.CAP_DSHOW即cv2.VideoCapture(cam_id, cv2.CAP_DSHOW)。如果還不行換cv2.CAP_MSMF試試。Linux 下一般不用改。4.3 現(xiàn)象訓(xùn)練 loss 降到 0.1 以下但驗證集 mAP 只有 0.2原因過擬合。積水?dāng)?shù)據(jù)集如果背景單一比如全是灰色路面模型會記住背景而不是積水特征。解決在02train.py里加數(shù)據(jù)增強(qiáng)參數(shù)--degrees 10 --translate 0.1 --scale 0.5 --fliplr 0.5并開啟--mosaic 1.0。另外把dropout調(diào)到 0.1YOLO11 分割頭支持。4.4 現(xiàn)象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 現(xiàn)象推理結(jié)果里積水掩碼邊緣鋸齒嚴(yán)重原因模型輸出掩碼分辨率低plot()直接放大導(dǎo)致鋸齒。解決在predict里加retina_masksTrue讓掩碼在原圖分辨率上生成代價是推理慢 10% 左右?;蛘吆筇幚頃r用cv2.morphologyEx做開運算平滑邊緣。5. 進(jìn)階技巧用 TensorBoard 盯住分割指標(biāo)別只看 loss訓(xùn)練跑起來后results.csv里有一列metrics/mAP50-95(M)這是分割掩碼的平均精度比檢測框的 mAP 更能反映積水區(qū)域貼合度。我習(xí)慣在訓(xùn)練中途用 TensorBoard 看train/seg_loss和val/seg_loss的 divergence如果驗證 loss 連續(xù) 10 輪不降就手動停掉別等 100 輪跑完。另外events.out.tfevents...文件可以直接拖進(jìn) TensorBoard 的--logdir目錄不用改代碼。還有一個技巧把03pyqt.py里的model.predict換成model.track加上persistTrue就能對視頻流里的積水區(qū)域做 ID 跟蹤適合做積水?dāng)U散趨勢分析。最后說個我自己的習(xí)慣每次改完data.yaml或訓(xùn)練參數(shù)先跑python 02train.py --epochs 1做冒煙測試確認(rèn)數(shù)據(jù)加載和模型前向不報錯再開長訓(xùn)練。從那以后我每次動數(shù)據(jù)集劃分腳本都強(qiáng)制先跑一遍01劃分?jǐn)?shù)據(jù)集.py并檢查三個 txt 的行數(shù)比例避免訓(xùn)練到一半發(fā)現(xiàn)驗證集是空的。希望幫到你。本文還有配套的精品資源點擊獲取