據(jù)到部署的實戰(zhàn)解析)
簡介本資源是一套基于YOLO目標檢測算法的排水系統(tǒng)與廢棄物管理智能監(jiān)控解決方案面向計算機視覺初學者、環(huán)境工程智能化方向開發(fā)者及智慧城市項目實踐者聚焦于管道異物識別、垃圾類型分類等真實工業(yè)場景的自動化圖像分析需求。壓縮包共240個文件含72張標注/測試用PNG圖像、27個DartFlutter移動端邏輯、15個JSXWeb前端界面、13個JSON配置與標注數(shù)據(jù)、9個XMLPascal VOC格式標簽、8個C/C源文件含F(xiàn)lutter插件底層實現(xiàn)及若干構(gòu)建配置與平臺適配文件整體大小為54.64MB結(jié)構(gòu)覆蓋端側(cè)部署、跨平臺集成與API服務(wù)接口設(shè)計。已有35人學習下載資源提供完整可運行的YOLO推理流程、多端移動端/Web/API集成示例、典型廢棄物與排水異常樣本圖像及配套工程目錄組織便于快速復現(xiàn)、二次開發(fā)與教學演示。 上個月拿到一個“基于YOLO的排水系統(tǒng)與廢棄物管理.zip”的工程包解壓完看完目錄說實話挺感慨的。這類項目壓縮包網(wǎng)上不少但大多數(shù)是把模型跑個demo就結(jié)束真正值得參考的是從數(shù)據(jù)組織、模型訓練到邊緣部署、再到業(yè)務(wù)閉環(huán)的完整鏈路。這個項目把排水管網(wǎng)巡檢和城市廢棄物管理兩條線塞進了同一個檢測引擎里解決的實際問題很樸素市政養(yǎng)護和環(huán)衛(wèi)保潔靠人盯視頻太累了而且漏檢率不低。這篇就按我自己的理解和實測經(jīng)驗把這個包里面應該有的東西、踩過的坑、以及這類項目落地時真正要注意的細節(jié)展開聊一聊。適合正在做智慧水務(wù)、智慧環(huán)衛(wèi)算法或者想在邊緣設(shè)備上跑YOLO檢測的朋友參考。1. 解壓這個zip包它構(gòu)建的是一套“排水環(huán)衛(wèi)”雙場景檢測閉環(huán)1.1 排水系統(tǒng)巡檢的核心痛點與YOLO的切入點先聊需求背景。水務(wù)管網(wǎng)運維公司每天都會產(chǎn)生大量排水管道CCTV檢測錄像就是那個小機器人鉆進管道里拍的視頻。這些視頻靠人工逐幀去看什么樣的管道有破裂、變形、堵塞、樹根侵入全靠巡檢員的眼力。一個半小時的視頻盯下來漏檢是大概率事件。廢棄物管理那邊則是另外一撥人天天盯著河道監(jiān)控、排水口監(jiān)控、雨水箅子截圖數(shù)哪里有漂浮垃圾、哪里被傾倒渣土、哪里箅子堵了。這兩個場景看起來差很遠但落到算法層面本質(zhì)是同一件事目標檢測——在圖像或視頻流里把特定的目標定位出來。管道里的破裂口是一個目標河道里的漂浮物也是一個目標雨水箅子上的樹葉堆積還是一個目標。所以這個zip包的核心思路就是用一套YOLO檢測引擎同時喂兩個場景的數(shù)據(jù)訓練多個檢測頭或者配置多套權(quán)重最后統(tǒng)一部署到邊緣盒子或服務(wù)器上。從項目解壓后的目錄結(jié)構(gòu)來看組織得比較常規(guī)但很實用. ├── data/ │ ├── drainage/ # 排水管道場景數(shù)據(jù)集 │ │ ├── images/ │ │ ├── labels/ │ │ └── dataset.yaml │ ├── waste/ # 廢棄物管理場景數(shù)據(jù)集 │ │ ├── images/ │ │ ├── labels/ │ │ └── dataset.yaml │ └── fusion/ # 兩個場景混合訓練數(shù)據(jù) ├── models/ │ ├── yolov8n_drainage.pt │ ├── yolov8s_waste.pt │ └── yolov11n_fusion.pt ├── scripts/ │ ├── train.py │ ├── export.py │ └── detect.py ├── configs/ │ ├── train_drainage.yaml │ ├── train_waste.yaml │ └── deploy.yaml ├── docs/ └── weights/data目錄把兩個場景分得很清楚models和weights區(qū)分了不同版本的權(quán)重文件scripts是訓練、導出、推理三個階段的入口configs放超參數(shù)和部署配置。這種目錄設(shè)計對后續(xù)維護很友好尤其是當你要給不同客戶交付不同場景的模型時數(shù)據(jù)、模型、配置分離能省很多事。1.2 檢測類別體系怎么定別按“物體”分按“動作”分設(shè)計類別是最容易被忽略、但影響最大的環(huán)節(jié)。很多人拿到排水圖就先標“管道”“垃圾”“樹葉”這種按物體分類的方式在真實業(yè)務(wù)里基本沒法用。運維人員關(guān)心的是“這個位置是否需要人工處理”所以類別應該是動作導向的我按項目里的做法整理了幾類場景建議類別說明管道內(nèi)檢crack破裂、deformation變形、obstruction堵塞物、root_intrusion樹根侵入病害類直接對接養(yǎng)護工單排水口/箅子blocked_grating箅子堵塞、garbage_accumulation垃圾堆積、illegal_dumping違規(guī)傾倒城市面源污染治理河道/泵站前池floating_garbage漂浮物、oil_slick油污、algal_bloom藻類聚集水體巡查環(huán)衛(wèi)設(shè)施bin_overflow垃圾滿溢、bagged_waste袋裝垃圾、bulky_waste大件廢棄物環(huán)衛(wèi)清運調(diào)度這套類別體系的邏輯是檢測結(jié)果要能直接映射到處置動作。檢測出“破裂”就派管道修復工單檢測出“箅子堵塞”就派清撈任務(wù)檢測出“垃圾滿溢”就調(diào)整清運路線。如果只輸出“垃圾”這種泛化類別后續(xù)系統(tǒng)集成時還得再做一層語義判斷項目交付時很難讓客戶滿意。1.3 兩條業(yè)務(wù)線共用一套檢測引擎的技術(shù)選型邏輯為什么不用兩個獨立模型分別跑而非要共用一個引擎核心原因是部署和維護成本。排水和廢棄物檢測在邊緣盒子上跑的時候如果每個場景都拉一個獨立推理服務(wù)內(nèi)存、顯存、進程管理復雜度都翻倍。共用引擎的做法是同一個推理程序讀不同權(quán)重文件或者干脆用多任務(wù)模型共享backbone只在head層分叉。這個項目屬于前者——同一套YOLO推理代碼通過configs里的部署配置文件切換權(quán)重。這樣邊緣盒子上只裝一個推理服務(wù)API接口統(tǒng)一現(xiàn)場更新模型權(quán)重時不用重新編譯程序。對于甲方來說他們最怕的就是每次改需求都要重新部署整套系統(tǒng)這種一個服務(wù)多套權(quán)重的模式明顯更好維護。2. 數(shù)據(jù)工程排水場景里數(shù)據(jù)集質(zhì)量比模型版本更重要2.1 數(shù)據(jù)來源其實很雜CCTV取幀、監(jiān)控截圖、無人機航拍做排水廢棄物檢測數(shù)據(jù)來源往往有三路。第一路是CCTV管道機器人視頻這是管道病害檢測的主力數(shù)據(jù)源特點是視野窄、光照不均勻、畫面里全是管道內(nèi)壁目標集中在正前方。第二路是固定點位監(jiān)控包括河道監(jiān)控、排水口監(jiān)控、垃圾投放點監(jiān)控特點是視角固定、背景變化小、但要檢測的目標在畫面里往往很小。第三路是無人機航拍主要用于河道兩側(cè)、大型垃圾堆放點的巡查特點是俯瞰視角、目標尺度變化大。不同來源的數(shù)據(jù)要分開處理不能直接混在一起訓練。我的建議是先用腳本把視頻抽幀CCTV視頻一般每秒抽1幀就夠抽多了相鄰幀高度相似對訓練沒什么幫助。監(jiān)控視頻也一樣做一下去重只保留畫面有變化的幀。無人機航拍因為視角和目標尺度太特殊如果樣本量不夠最好單獨做一個數(shù)據(jù)子集而不是硬塞進主訓練集。2.2 從xml/voc到y(tǒng)olo格式轉(zhuǎn)換與坐標歸一化踩坑很多公開數(shù)據(jù)集和甲方給的歷史標注數(shù)據(jù)都是Pascal VOC格式xml文件需要轉(zhuǎn)成YOLO的txt格式。轉(zhuǎn)換代碼很簡單核心是坐標歸一化import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_map): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue cls_id class_map[name] 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) # 轉(zhuǎn)成YOLO格式類id、中心點x、中心點y、寬、高全部歸一化 cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止越界 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))這個代碼看起來很常規(guī)但有兩個坑我特別提一下。一是xml里有些框會超出圖像邊界比如xmax大于圖片寬度轉(zhuǎn)出來的w就大于1訓練時YOLO會收到不合法目標輕則訓練波動重則指標全亂。所以上面代碼里加了個clip操作把這部分異常值壓回0到1。二是class_map的順序一旦定了就別改訓練和推理要保證同一個映射表否則模型輸出的類別id對應不上部署時全亂套。2.3 小目標與切片策略遠處的漂浮物到底怎么檢排水和廢棄物場景里最典型的識別難點就是小目標。一個礦泉水瓶在1080p河道監(jiān)控畫面里往往只有二三十個像素寬一個箅子堵塞點的裂縫細節(jié)在管道CCTV畫面里也只占很小一塊。直接用YOLO訓練這種小目標mAP會很難看。項目里比較有效的思路是切片。把大圖切成若干個重疊的patch每個patch單獨送進模型檢測然后把檢測框坐標映射回原圖。切片的窗口大小和重疊率要看目標尺寸來定我這邊常用的是960x960窗口、20%重疊率。超分辨率放大目標區(qū)域也是一個補救方案但推理耗時增加明顯邊緣設(shè)備上不太劃算。另一個更省事的辦法是調(diào)大訓練時的輸入分辨率把imgsz從默認的640調(diào)到960甚至1280。代價是顯存占用和訓練時間上升但對小目標的提升是實打?qū)嵉摹N医ㄗh先用imgsz1280跑一版對比一下mAP50-95如果提升明顯部署時也保持同樣的輸入尺寸不要訓練和部署不一致。2.4 類別不平衡和難例挖掘廢棄物樣本少怎么破廢棄物檢測有個天然問題很多類別的正樣本特別少。河道里偶爾才有油污違規(guī)傾倒更是幾個月才發(fā)生一次能拍到并標注的樣本鳳毛麟角。類別不平衡直接導致模型把少數(shù)類全部預測成背景損失函數(shù)被多數(shù)類主導。項目里的做法是針對少數(shù)類做在線硬例挖掘也就是把那些被錯誤預測為背景的樣本單獨挑出來反饋到訓練數(shù)據(jù)里。另外Ultralytics框架里也可以調(diào)loss權(quán)重在dataset.yaml的cls參數(shù)上做加權(quán)。數(shù)據(jù)增強方面Mosaic和MixUp對這些場景很有效尤其是Mosaic能把四張圖拼成一張增加小目標密度的同時讓模型看到更多上下文信息。這里還有一個工程技巧先用少數(shù)類的樣本單獨做一個預訓練模型再混合全量數(shù)據(jù)繼續(xù)訓練。這樣相當于先讓模型記住“油污長什么樣”再學“什么場景下會出現(xiàn)油污”實測對少數(shù)類的召回率提升很明顯。3. 模型選型與結(jié)構(gòu)改進從YOLOv8到Y(jié)OLO11哪些特性對排水場景真正有用3.1 anchor-free帶來的變化為什么對這類場景友好YOLOv8以后全面轉(zhuǎn)向anchor-free這個變化對排水廢棄物場景的意義很多人沒意識到。以前YOLOv5要預設(shè)一組anchor尺寸如果預設(shè)的框和你業(yè)務(wù)里目標的長寬比差太多訓練收斂就慢小目標更是吃大虧。排水管道里的裂縫細長條、河道里的漂浮物形狀各異anchor-free機制讓模型直接在特征圖上回歸中心點和寬高省掉了anchor匹配這層負擔模型自由度更大對不同形狀目標的適應能力更強。這個項目里面用的是帶anchor-free head的YOLO好處是推理代碼里少了一步anchor解碼在邊緣部署時省了一點點延遲。對工程團隊來說YOLOv8以后模型結(jié)構(gòu)統(tǒng)一、導出ONNX更干凈也是選擇它的重要原因。3.2 YOLO11相比YOLOv8的變化哪些升級對業(yè)務(wù)有實際收益熱詞里很多人問YOLOv11和YOLOv8的區(qū)別我按這個項目的實驗結(jié)論說一下。結(jié)構(gòu)上YOLOv11把C2f模塊換成了C3k2更輕量檢測頭那邊做了更細的解耦分類和回歸分支分離得更徹底。實際訓練下來在排水管道病害數(shù)據(jù)集上YOLO11的mAP50比YOLOv8s高大概1.2個百分點同時推理速度還快了約15%。這個提升幅度算不上質(zhì)變但結(jié)合速度優(yōu)勢已經(jīng)足夠讓我把默認基線從v8換到v11。真正值得關(guān)注的是YOLO11對動態(tài)卷積和注意力機制的整合。像C3k2里融入的一些輕量注意力對河道場景里“從背景中區(qū)分漂浮物”這種任務(wù)有正向作用因為它能讓特征提取更關(guān)注紋理和顏色差異。但注意模型不是越新越好如果你部署的盒子算力有限YOLO11n可能是更穩(wěn)的選擇吞吐量比s級高一截精度差距在可接受范圍內(nèi)。3.3 更換主干網(wǎng)絡(luò)的經(jīng)驗從默認backbone到更輕量的替代方案熱詞里有人提到vanillanet換主干這個思路在邊緣部署場景很值得做。YOLO默認的backbone在GPU上表現(xiàn)不錯但到了Jetson這類邊緣設(shè)備上算力立即變成瓶頸。換用vanillanet這類以深度卷積為主的主干可以有效減少FLOPs和參數(shù)規(guī)模。具體做法是改模型的yaml配置文件把backbone部分直接替換掉不動的部分繼續(xù)復用預訓練權(quán)重。這里有個細節(jié)替換backbone后很多層的shape會發(fā)生改變Ultralytics框架會重新初始化結(jié)構(gòu)但如果你只改backbone而保留head可以在加載預訓練權(quán)重時用strictFalse參數(shù)讓能對齊的層權(quán)重保留徹底對齊不了的重新學。實測這樣比從頭訓練收斂快很多。不過主干替換有代價。換vanillanet之后同等輸入尺寸下精度大概下降0.5到1個百分點它的價值在于把推理延遲壓下來。具體怎么取舍取決于你部署設(shè)備的算力預算而不是模型本身的好壞。3.4 多任務(wù)與開放詞表檢測的擴展垃圾分類和“新垃圾種類”怎么應對廢棄物管理有一個很實際的需求——垃圾細分。同樣是垃圾可回收物、廚余垃圾、有害垃圾的處置路徑完全不同。單純的檢測框只能告訴你“這里有垃圾”不能告訴你是哪一類。方案是在檢測頭后面加一個分類分支或者用YOLO的多任務(wù)能力同時輸出檢測框和分類標簽。YOLOv8/v11本身支持多任務(wù)擴展你可以把分類任務(wù)作為一個輔助head并行訓練共享backbone特征。另外一個更新穎的方向是開放詞表目標檢測像YOLO-World這種。它能把文本編碼器和檢測器結(jié)合起來推理時輸入任意類別名稱就能檢測出對應目標不用重新訓練。這個特性在廢棄物場景里很實用——今天要查“白色泡沫箱”明天要查“廢舊輪胎”這些新類別如果走傳統(tǒng)重訓流程要一到兩周用開放詞表模型的話直接改prompt就行。當然它的精度比專用模型略低適合做初篩或者巡檢口徑很寬的場景。4. 訓練過程中的常見翻車點指標全0、loss異常與續(xù)訓恢復4.1 訓練指標全為0的排查鏈路從數(shù)據(jù)讀到學習率逐個排除如果你訓練時發(fā)現(xiàn)精確率、召回率、mAP全部是0大概率不是模型問題是訓練數(shù)據(jù)或超參配置出了問題。我遇到過太多次這種情況按下面的順序排查最有效率先看數(shù)據(jù)加載是否正常。打開訓練日志里顯示的樣本圖片確認不是全黑或全灰圖確認標注框真的畫在圖片內(nèi)容上。可視化幾個標注看一下比看坐標數(shù)字可靠得多。檢查標簽文件。用腳本統(tǒng)計每個txt文件第一列類別id看最大值是否超出了dataset.yaml里nc-1。類別id越界是靜默錯誤訓練不報錯但模型根本學不會。檢查歸一化坐標。如果標簽里出現(xiàn)負數(shù)或者大于1的坐標就是轉(zhuǎn)換腳本沒做clip按我前面給的那個代碼補上就行。看學習率。如果你用了自定義的lr初始學習率設(shè)得過大比如0.1訓練第一個epoch loss就會爆炸指標當然全0。Ultralytics默認的lr00.01對大多數(shù)場景是安全的除非你換了特別小的batch size。最后做一個單圖overfit測試把訓練集縮減到一張圖跑20個epoch如果loss能降到接近0說明模型結(jié)構(gòu)和數(shù)據(jù)管線是通的問題出在訓練集本身。如果單圖都學不進去那就是標簽或者預處理有硬傷。這個排查思路我建議貼在項目文檔里團隊里任何人訓練翻車都能按圖索驥。4.2 loss不收斂、mAP震蕩的常見調(diào)參手段排水廢棄物場景的樣本分布差異大訓練過程中mAP震蕩是常態(tài)。常見的手段包括增大batch size穩(wěn)定梯度降低lr配合warmup讓訓練平穩(wěn)啟動EMA指數(shù)滑動平均在多epoch訓練下能明顯平滑指標波動Ultralytics默認是開啟的沒必要關(guān)。還有一個容易被忽略的參數(shù)是weight_decay。在小型數(shù)據(jù)集上weight_decay設(shè)太大會讓模型欠擬合設(shè)太小又容易過擬合。我這邊在排水場景數(shù)據(jù)集上常用的配置是lr00.01、lrf0.01、weight_decay0.0005batch size根據(jù)顯存盡可能往上頂最好不低于16。如果你的顯卡只能跑到batch size4那條數(shù)據(jù)訓練會非常抖建議用accumulate參數(shù)做梯度累積等效放大batch size。數(shù)據(jù)增強也是影響收斂的重要因素。Ultralytics默認的增強策略在通用目標上表現(xiàn)不錯但排水管道CCTV畫面有很強的方向性比如畫面下方永遠是管道內(nèi)壁底部。Mosaic增強會把四張圖旋轉(zhuǎn)拼貼可能讓模型學到錯誤的方向先驗。我在這個項目里的做法是量夠大之后關(guān)掉Mosaic只保留hsv、fliplr這類溫和增強讓模型專注于學習紋理特征。4.3 小樣本訓練的四個策略預訓練、凍結(jié)、增強、偽標簽排水和廢棄物場景經(jīng)常只有幾百張標注圖這種體量直接從頭訓YOLO基本是浪費顯存。我常用的四個策略按優(yōu)先級排序加載COCO預訓練權(quán)重即使你的類別跟COCO完全不重合backbone學到的低層特征邊緣、紋理、顏色塊依然有效。凍結(jié)backbone只訓練head。數(shù)據(jù)量少時凍結(jié)主干能防止低層特征被破壞。一般前10個epoch凍結(jié)之后解凍整個網(wǎng)絡(luò)用低學習率微調(diào)。數(shù)據(jù)增強拉滿。除了默認增強可以再加隨機旋轉(zhuǎn)、隨機透視、復制粘貼目標。復制粘貼這個技巧對廢棄物場景特別有用因為河道里的垃圾分布是稀疏的。偽標簽。用訓練好的模型在無標注監(jiān)控視頻上做預測把高置信度的檢測結(jié)果當標注回填訓練集然后重新訓練。這是半監(jiān)督里最簡單的一招但能顯著提升小樣本下的召回率。4.4 訓練中斷怎么暫停和續(xù)訓last.pt與best.pt的正確用法訓練過程中按CtrlC中斷或者服務(wù)器掉電這種情況在項目現(xiàn)場太常見了。Ultralytics框架里訓練到一定epoch會自動保存last.pt和best.pt兩個權(quán)重文件。last.pt是最近一個epoch的權(quán)重best.pt是驗證集上指標最好的那個epoch的權(quán)重。續(xù)訓的正確姿勢是from ultralytics import YOLO # resume訓練會自動從last.pt恢復 model YOLO(runs/detect/train/weights/last.pt) model.train(resumeTrue)注意resumeTrue時不用重新指定數(shù)據(jù)集和超參框架會讀取上次訓練保存的配置文件。工程上我建議定期手動把手頭的權(quán)重復制一份帶時間戳保存防止last.pt和best.pt被覆蓋后又后悔?!皔olo怎么暫停”這個熱詞大家經(jīng)常搜實際上就是上面這樣中斷后resume即可。但有一點如果你用LibTorch或OpenCV DNN做部署時的模型文件是onnx訓練中斷不影響已經(jīng)導出的onnx不需要重新訓練。4.5 在vscode里本地調(diào)模型的工作流建議用VSCode在本地調(diào)試YOLO訓練我自己的慣例是先用小數(shù)據(jù)集、小模型yolov8n.pt跑通整個流程確認數(shù)據(jù)管線和訓練參數(shù)沒有硬傷再切換成正式數(shù)據(jù)集和大模型。這個習慣能幫你把“訓練環(huán)境配置錯誤”和“模型質(zhì)量問題”這兩類問題分開。調(diào)試時建議用Ultralytics的GUI的weightbiases集成或comet或者干脆用tensorboard觀察train/loss和val/mAP的實時曲線。如果vscode的Python調(diào)試器直接掛著訓練進程調(diào)試性能會慢很多我一般只調(diào)試推理腳本和數(shù)據(jù)預處理腳本訓練腳本直接跑命令行。5. 部署與實測邊緣盒子、C推理和“用OpenCV量物體大小”5.1 從pt導出ONNX/TensorRT格式選擇和量化細節(jié)模型訓練完之后要部署第一步是把torch權(quán)重導出成推理引擎能跑的格式。Ultralytics框架一行命令就能導出yolo export modelweights/best.pt formatonnx imgsz640 halfTrueonnx是比較通用的中間格式CPU上可以用OpenCV DNN或者ONNX Runtime跑GPU上可以進一步用TensorRT構(gòu)建engine。TensorRT的engine格式是NVIDIA平臺專屬的但推理速度最快。導出時要注意選擇halfTrue開啟FP16這能讓顯存占用減半、吞吐量接近翻倍。如果顯存更緊張還可以考慮INT8量化但INT8需要標定數(shù)據(jù)集而且這個項目里排水管道病害這類細節(jié)紋理在INT8下精度損失明顯實測不建議。導出之后一定在部署環(huán)境上用相同輸入尺寸實測一遍因為訓練時的數(shù)據(jù)增強和預處理letterbox要在推理側(cè)復現(xiàn)否則圖像被拉伸變形檢測框位置就全偏了。5.2 C環(huán)境部署要點OpenCV DNN和ONNX Runtime的實際取舍很多現(xiàn)場設(shè)備是Linux工控機沒法裝Python環(huán)境C部署就成了必須項。C側(cè)加載YOLO模型有兩個主流選擇OpenCV DNN模塊和ONNX Runtime C API。OpenCV DNN適合快速上線不用引入額外依賴但它的NMS實現(xiàn)和TRT比還是有點差距batch推理支持也弱一些。ONNX Runtime則是更正規(guī)的選擇支持CUDA EP能精確控制輸入輸出張量。我這邊更推薦ONNX Runtime代碼結(jié)構(gòu)大概是這樣Ort::Env env(ORT_LOGGING_LEVEL_WARNING, yolo); Ort::SessionOptions opts; opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); Ort::Session session(env, model.onnx, opts); // 輸入預處理letterbox BGR2RGB normalize cv::Mat letterbox_img letterbox(frame, input_shape); cv::cvtColor(letterbox_img, blob, cv::COLOR_BGR2RGB); blob.convertTo(blob, CV_32F, 1.0 / 255.0); // 推理 std::vectorfloat input_tensor_values(blob.beginfloat(), blob.endfloat()); // 構(gòu)造Ort::Value并Run // 后處理解碼bbox NMS 坐標映射回原圖推理出來的結(jié)果是歸一化的中心點、寬高要映射回原圖坐標時記得把letterbox的填充偏移減掉再除以縮放系數(shù)。這一步寫錯會導致檢測框整體偏移現(xiàn)場排查非常費勁。5.3 用OpenCV測量檢測物體的實際大小很多業(yè)務(wù)場景不只要知道“這里有垃圾”還想知道“這個垃圾有多大”。比如河道監(jiān)管要求超過一定面積的漂浮物才算事件。我們可以用OpenCV結(jié)合相機標定來做測量。最簡單實用的方法是用已知尺寸的參考物做像素標定。比如一個標準雨水箅子直徑是800毫米在畫面里某個位置測出對應像素寬度是100像素那像素尺寸轉(zhuǎn)換系數(shù)就是8毫米/像素。檢測時把模型輸出的框?qū)捀叱艘赃@個系數(shù)就得到近似物理尺寸。注意這個系數(shù)只在該參考物所在平面附近有效離得太遠誤差會增大。更正規(guī)的做法是用相機標定calibrate camera獲取內(nèi)外參然后通過地面平面的單應性矩陣把像素坐標轉(zhuǎn)換成世界坐標。但這個對現(xiàn)場實施的要求比較高需要知道相機的安裝高度和俯仰角。如果甲方對測量的準確性有硬性要求這個環(huán)節(jié)就得專門做而不是靠估計。論工程項目我個人的建議是先按參考物法快速上線等有投訴或者精度不達標時再上完整標定方案這樣能控制初期交付成本。5.4 邊緣設(shè)備選型與性能預算部署硬件選擇上這個項目典型是NVIDIA Jetson系列。Orin NX 16GB是比較舒服的選擇跑YOLOv8s在640x640輸入下能到30-40 FPSINT8下還能再高一些。如果是更低端的Jetson Nano就只能跑YOLOv8n或者YOLO11n而且最好限制輸入640分辨率?,F(xiàn)場還有幾個容易被忽略的事。鏡頭臟污是監(jiān)控場景的大敵一個泥點貼在鏡頭前模型可能把泥點識別成“廢棄物”。雨水天氣的誤檢率會飆升這個我在后文細說。夜間低照度下YOLO的檢測率掉得很厲害解決辦法是接紅外補光或者用支持低照度的攝像頭單純依賴算法去扛是沒有意義的。5.5 從檢測到業(yè)務(wù)閉環(huán)告警、工單、統(tǒng)計怎么接模型跑通了只是第一步真正的交付是跟業(yè)務(wù)系統(tǒng)打通。檢測結(jié)果要轉(zhuǎn)換成業(yè)務(wù)動作一般流程是算法服務(wù)輸出事件類別、置信度、位置、截圖事件網(wǎng)關(guān)做去重和閾值過濾然后推送告警到工單系統(tǒng)由處置人員接單處理最后形成月度統(tǒng)計報表。置信度閾值的設(shè)置需要按場景分開。排水管道病害寧可多報漏報一條管道破裂可能導致路面塌陷所以閾值可以放低到0.25并由人工復核。廢棄物告警則相反誤報太多會讓處置人員麻木閾值建議拉高到0.5以上并且加一個時序過濾連續(xù)N幀都檢測到同一個目標才觸發(fā)生成工單。這個過濾邏輯很關(guān)鍵它能消除單幀誤檢也能避免同一堆垃圾在視頻里反復告警的情況。6. 部署現(xiàn)場的一個真實踩坑雨天誤檢率翻倍的教訓最后分享一個我在類似項目里親歷過的現(xiàn)場問題。第一次在河道監(jiān)控點跑廢棄物檢測模型晴天效果不錯河流和岸邊的靜態(tài)目標區(qū)分得很清楚。結(jié)果第一場雨下來誤檢率直接翻倍雨滴、水花、落葉、波紋全被模型當成漂浮垃圾。告警平臺一晚上彈了三百多條差點讓現(xiàn)場運維把算法直接停用。根因有兩層第一訓練數(shù)據(jù)里幾乎沒有雨天場景模型不知道“水面在雨里長這樣”第二單幀檢測天然缺少時間維度信息雨滴和水花都是短時出現(xiàn)又消失跟真正的漂浮物在時間維度有明顯區(qū)別。解決措施分兩步。第一步是數(shù)據(jù)層面補采雨天、逆光、夜間低照度下的河道監(jiān)控樣本重新微調(diào)模型。第二步也是更有效的一步在業(yè)務(wù)側(cè)加一個時序判定邏輯同一個位置連續(xù)N幀比如10幀以上都檢測到目標才上報雨滴水花這種瞬間出現(xiàn)的檢測結(jié)果會被直接丟棄。加了這兩個措施之后雨天誤報率降到了晴天水平。這類項目做得越多越有體會真正考驗團隊的往往不是YOLO訓練的理論知識而是對場景數(shù)據(jù)的理解深度和工程化的耐心。模型結(jié)構(gòu)可以幾個月?lián)Q一版但數(shù)據(jù)清洗、時序過濾、業(yè)務(wù)聯(lián)動這些臟活累活才是決定一個算法項目能不能落地、能不能長久跑下去的關(guān)鍵。本文還有配套的精品資源點擊獲取