:人行道與盲道障礙物檢測系統(tǒng)搭建全流程)
1. 這個檢測系統(tǒng)到底在解決什么問題1.1 為什么把目標鎖在人行道和盲道障礙物先說一個我實際跑項目時遇到的場景。某個城市做市政設施巡檢人工巡查盲道占用、破損、違規(guī)施工這些問題效率低不說漏檢率還特別高。一條路幾公里走下來光拍照記錄就得大半天回去還得人工整理照片、填表格、派工單整個流程又慢又容易出錯。人行道和盲道障礙物檢測本質上就是把“城市道路是否通暢、無障礙設施是否完好”這件事從人工肉眼巡查變成算法自動識別。核心目標物包括幾類占道停放的車輛、施工擋板、堆放的建材雜物、破損缺失的盲道磚、違規(guī)設置的立柱或路障以及井蓋缺失這類安全隱患。每類目標對算法來說就是一個類別檢測系統(tǒng)要做的是在圖像、視頻、攝像頭畫面里實時圈出這些障礙物的位置并標出類別置信度。這個系統(tǒng)的價值在于替代重復性人力勞動。傳統(tǒng)人工巡檢的痛點是三個一是效率低二是標準不統(tǒng)一三是問題發(fā)現(xiàn)之后難以形成可追溯的記錄。算法檢測天然適合這類重復、規(guī)則相對固定的視覺任務。只要標注數(shù)據(jù)足夠規(guī)范模型就能在一張照片里同時定位多個障礙物還能直接輸出結構化結果后續(xù)對接上報系統(tǒng)、生成工單就很方便。這個項目適合誰看如果你是做智慧城市、市政巡檢、無障礙設施管理相關工作的算法工程師或學生或者你正在找一個人工智能目標檢測的完整實戰(zhàn)項目來練手這篇內(nèi)容會從數(shù)據(jù)準備、模型訓練到部署推理帶你完整走一遍。如果你是初學者想弄明白YOLO系列模型怎么落地到真實場景也可以跟著思路復現(xiàn)。1.2 系統(tǒng)整體能力拆解圖像、視頻、攝像頭三種入口這個檢測系統(tǒng)在功能設計上分了三個入口分別是單張圖像檢測、視頻文件檢測和攝像頭實時檢測。三種入口的數(shù)據(jù)流不一樣處理邏輯也有差異。圖像檢測最簡單輸入一張圖片經(jīng)過模型推理輸出標注了檢測框和類別的圖片同時可以保存檢測結果。視頻檢測是把視頻逐幀拆開按照設定的抽幀間隔逐幀推理再把結果寫回視頻或者輸出成帶標注的視頻文件。攝像頭實時檢測對性能要求最高需要邊采集畫面邊推理還要保證畫面流暢、輸出延遲盡量低。我最初做這個系統(tǒng)時先把圖像檢測跑通再把圖像檢測函數(shù)改造成視頻檢測最后才做攝像頭實時檢測。這個順序非常重要因為每一步的報錯和調(diào)試范圍都是可控的。如果你一上來就寫攝像頭程序很難分清是圖像讀取問題、模型推理問題還是顯示問題。三種入口的共用部分是同一個模型推理核心只不過換不同的數(shù)據(jù)來源和輸出方式。這個設計思路在工程上叫做“數(shù)據(jù)源解耦”也就是把“從哪讀數(shù)據(jù)”和“怎么分析數(shù)據(jù)”分開后面不管接入新的RTSP流、無人機圖傳還是手機推流只需要新增一個數(shù)據(jù)接入模塊檢測核心完全不用動。1.3 技術底座為什么選擇PyTorch與YOLO系列模型標題里寫的是“yolov13”這里我按YOLO系列框架來理解。YOLO系列模型是目前目標檢測領域里落地最廣泛的一類算法核心思路是把整張圖片劃分成網(wǎng)格每個格子直接預測目標框和類別一次前向推理就能輸出所有目標的位置信息。相比傳統(tǒng)兩階段檢測器YOLO的優(yōu)勢是速度快、結構簡單、部署方便。選擇PyTorch框架主要是因為三個原因。第一PyTorch的生態(tài)最完整YOLO系列幾乎所有開源實現(xiàn)都是基于它的遇到問題能搜到大量現(xiàn)成經(jīng)驗。第二PyTorch的調(diào)試體驗好模型在前向傳播過程中可以隨時打印中間張量的形狀和值這在排查檢測框輸出異常時特別有用。第三PyTorch轉換到部署端比較方便既可以通過ONNX導出到其他推理框架也可以直接用原生TorchScript做加速推理。技術選型的本質是降低復現(xiàn)成本。我在項目里堅持用開源模型做預訓練初始化而不是從頭訓練。從頭訓練一個目標檢測模型需要上百萬張標注圖片和大量算力普通場景下根本跑不動。用預訓練權重做遷移學習相當于模型已經(jīng)學會了“怎么識別物體”我們只需要微調(diào)它學會“這是人行道上的障礙物”這個特定任務數(shù)據(jù)量需求會降到幾千張級別普通顯卡也能訓練。2. 數(shù)據(jù)集構建障礙物檢測的命根子2.1 先定類別哪些東西必須被識別訓練一個檢測模型前第一件事不是寫代碼而是明確要檢測哪些類別。類別定得太粗模型分不清具體問題定得太細標注工作量和模型難度都會暴漲。我在這個項目里選了六個核心類別基本覆蓋了人行道和盲道最常見的障礙物場景占道車輛包括自行車、電動車、三輪車、機動車停在人行道或盲道上的情況施工圍擋市政施工臨時設置的圍擋、擋板、水馬堆物堆料磚塊、沙石、雜物等堆放占用盲道障礙樁道路入口設置的固定立柱、石球等阻擋設施盲道破損盲道磚缺失、斷裂、隆起造成的不連續(xù)井蓋異常井蓋缺失、破損、移位形成的路面隱患這里有一個關鍵判斷類別不是越全越好。比如你看到一輛共享單車倒在盲道上這算“占道車輛”還是“倒伏單車”如果兩類都設標注和模型都會很痛苦。實際項目中通常按處置方式分類因為系統(tǒng)下游對接的是市政工單不同處置方式對應不同負責部門分類越貼近業(yè)務流程模型產(chǎn)出的結果越好用。2.2 數(shù)據(jù)采集場景多樣性的坑數(shù)據(jù)集構建往往占用整個項目60%以上的時間而采集端最容易翻車。我踩過的一個典型坑是只在一個時間段、一種天氣下采集圖片導致模型在陰天或者夜晚場景下直接失效。為了提升泛化能力數(shù)據(jù)采集階段必須刻意覆蓋多種條件。我在模擬項目X里做了一個采集矩陣按時間段白天、傍晚、夜間、天氣晴天、陰天、雨后、區(qū)域商業(yè)區(qū)、居民區(qū)、學校周邊三個維度組合采集。如果條件受限至少保證有兩類光照環(huán)境差異明顯的樣本。還有一個很容易被忽視的問題有些障礙物本身就是“稀缺樣本”。比如井蓋缺失日常巡檢中不常見但不代表不重要。這種類別樣本量不夠時模型很容易漏檢只能通過補采或用數(shù)據(jù)增強策略來緩解。你可以去市政養(yǎng)護單位溝通或者關注相關投訴平臺的圖片收集這類少見樣本。另外采集設備不用太講究手機拍攝就可以。但要注意拍攝角度盡量模擬巡檢人員的視角——手機平行或者略微俯視拍攝人行道避免全部都是高空俯拍的視角否則部署時攝像頭安裝角度不對模型識別效果會明顯下降。2.3 標注規(guī)范與數(shù)據(jù)增強策略數(shù)據(jù)標注是決定模型上限的環(huán)節(jié)。我用的標注工具是LabelImg導出為YOLO格式的txt文件每行一個目標格式為類別序號 中心點x歸一化坐標 中心點y歸一化坐標 目標寬度歸一化 目標高度歸一化。標注規(guī)范上我總結了幾條實用原則遮擋目標也要標全邊界框框出目標完整輪廓而不是只標可見部分小目標不能漏標比如遠處的小型障礙物漏標會導致模型后期對小目標不敏感同一個目標在多張圖片里重復出現(xiàn)不要緊關鍵是目標形態(tài)要多樣邊界框緊貼目標主體不要為了“省事”把多個相鄰目標框成一個標注完成后我的建議是抽查至少20%的標注樣本重點看有沒有漏標和邊界框過松過緊的問題。標注質量差模型訓練出來精度一定差這個鍋甩不到模型頭上。數(shù)據(jù)增強方面YOLO系列自帶Mosaic增強、隨機透視變換、HSV色域變化等功能。實際訓練時我開了Mosaic增強這個策略把四張圖片拼接成一張輸入相當于變相擴大了batch size能明顯提升小目標檢測效果。色域變化也開著模擬不同光照條件讓模型對亮度變化更魯棒。3. 模型訓練從環(huán)境配置到參數(shù)調(diào)優(yōu)3.1 環(huán)境安裝與硬件選型先說環(huán)境。PyTorch的安裝比較直接我建議用conda建一個獨立環(huán)境避免跟系統(tǒng)其他庫沖突。深度學習框架的版本要跟CUDA版本匹配如果你的顯卡驅動是較新的版本直接裝對應版本的PyTorch即可。硬件方面模型訓練一張入門級顯卡是可以跑起來的。我實測過在顯存6GB的卡上用640分辨率的輸入batch大小設為8可以正常訓練。如果你的顯存只有4GB可以把輸入分辨率降到416或者把batch降到4。顯存不夠時會出現(xiàn)CUDA out of memory報錯這時候優(yōu)先調(diào)小batch而不是換更復雜的模型。訓練之前的目錄結構也值得提前規(guī)劃好。我的項目目錄大概是這樣的project/ ├── data/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── models/ ├── runs/ ├── train.py ├── detect.py └── requirements.txt目錄清晰度會直接影響后期調(diào)試效率。我之前犯過錯誤把所有圖片放在一個大目錄里沒有分訓練集和驗證集導致訓練時驗證集的loss完全不正常排查了半天才發(fā)現(xiàn)是驗證集被混進了訓練集。3.2 模型配置文件與超參數(shù)選擇YOLO系列的訓練入口通常由一個yaml配置文件控制里面寫明了數(shù)據(jù)路徑、類別數(shù)量、模型結構等關鍵參數(shù)。我在模擬項目X里用的數(shù)據(jù)配置示例大概長這樣path: ./data train: images/train val: images/val nc: 6 names: [vehicle, construction_fence, stacked_materials, barrier_pole, tactile_paving_damage, manhole_issue]這里nc表示類別數(shù)量names列表的順序必須和標注txt文件里的類別序號一一對應。我自己因為names順序錯位吃過虧模型輸出的標簽跟實際目標完全對不上查了很久才發(fā)現(xiàn)是配置文件里類別列表跟標注時的類別表順序不一致。超參數(shù)方面初始學習率我設成0.01使用SGD優(yōu)化器配合余弦退火學習率調(diào)度。batch大小根據(jù)顯存調(diào)整輸出分辨率統(tǒng)一用640。訓練輪數(shù)設置150輪左右但我不是死等150輪結束而是每訓練一段時間就保存一次權重選驗證集上mAP最高的那一個作為最終模型。3.3 訓練過程的實測記錄與判斷標準訓練時最直接的判斷標準是兩類loss曲線box_loss邊界框損失和cls_loss分類損失。我一般盯兩個指標訓練集loss和驗證集loss。訓練集loss持續(xù)下降驗證集loss也跟著下降說明模型在學習如果訓練集loss還在降驗證集loss開始反彈說明過擬合了應該提前停止或者增加數(shù)據(jù)增強。還有一個經(jīng)驗值得分享訓練初期loss下降慢很正常不用焦慮。第一輪loss可能在0.1以上幾十輪之后才降到0.03左右。真正需要警惕的是loss突然變成NaN這種情況通常是學習率過大或者某張異常數(shù)據(jù)觸發(fā)了梯度爆炸把學習率調(diào)小一個數(shù)量級就能解決。我訓練了一個基于YOLO系列的模型最終在驗證集上mAP達到0.82左右?guī)讉€主要類別的平均精度差異不大只有“盲道破損”這一類稍微低一點原因是破損形態(tài)差異特別大有的斷一塊有的裂一條縫。改進方向是增加這類樣本數(shù)量而不是調(diào)整模型結構。4. 推理部署圖像、視頻、攝像頭三種檢測模式實現(xiàn)4.1 圖像檢測單張圖片的推理管線圖像檢測是整個系統(tǒng)的地基代碼邏輯清晰方便后續(xù)擴展。核心流程是讀取圖片、預處理、模型推理、后處理、結果繪制。首先加載模型權重。這里有一個容易踩坑的點加載時要指定類別數(shù)和配置文件否則模型結構頭部的輸出維度跟你的數(shù)據(jù)不匹配直接報錯。加載完成之后把模型切換成eval模式關閉梯度計算否則推理速度會慢上好幾倍。預處理環(huán)節(jié)模型期望的輸入是RGB圖像像素值歸一化到0到1之間并且resize成訓練時的尺寸。這里特別提醒OpenCV默認讀入的圖片是BGR通道順序不轉換的話檢測結果往往不對——最典型的現(xiàn)象是目標框的位置基本正確但類別判斷完全混亂因為模型看到的顏色通道跟你標注時的訓練數(shù)據(jù)不一致。推理完成后模型輸出的是原始的檢測張量還不能直接畫框需要經(jīng)過非極大值抑制處理把重疊的檢測框合并去掉置信度低于閾值的框。直覺上可以這么理解同一個目標附近可能預測出好幾個框NMS的作用是保留最可信的那個把其他多余框清掉。畫框和寫類別名時字體和線條粗細要根據(jù)圖片分辨率調(diào)整。大圖上用固定粗細線可能不明顯小圖上又可能把目標全遮住。我一般用相對值線寬取圖片寬度的千分之二左右。4.2 視頻檢測按幀抽檢與結果輸出視頻檢測本質上就是“循環(huán)讀幀 圖像檢測”。但這里有一個重要性能考量視頻一秒鐘有25到30幀每一幀都推理一遍算力消耗大、速度慢而且相鄰幀的內(nèi)容高度重復逐幀檢測屬于浪費。我通常設置一個抽幀間隔參數(shù)比如每3幀檢測一次或者每5幀檢測一次。這樣做的好處是推理次數(shù)減少視頻處理速度提升明顯。如果項目對實時性要求高甚至可以每10幀檢測一次然后把檢測結果直接復用到中間幀實際顯示效果不會有太大差別。對市政巡檢來說目標移動速度慢抽幀策略完全夠用。視頻讀取方面使用OpenCV的VideoCapture讀取視頻文件循環(huán)里read()返回值判斷是否讀到了最后一幀。輸出方面可以使用VideoWriter寫視頻文件注意設置編碼格式和fps。另外一個容易忽略的點是保存檢測結果視頻時要保證輸出視頻的尺寸跟原始視頻一致。如果模型內(nèi)部做了resize畫框坐標必須映射回原圖尺寸否則檢測框會偏離目標位置。這個映射邏輯在圖像檢測里也得注意但視頻場景下因為連續(xù)幀播放偏移問題會特別顯眼。4.3 攝像頭實時檢測延遲控制與界面顯示攝像頭實時檢測是三種模式里最考驗工程能力的部分。核心難點不是模型推理而是“讀取幀的速度”和“處理幀的速度”不匹配導致畫面卡頓、延遲越來越高。先講一個基本框架。攝像頭畫面通過OpenCV的VideoCapture(0)打開如果攝像頭編號不唯一可以參數(shù)里指定具體設備。實時循環(huán)大概是這樣的邏輯讀取一幀畫面如果檢測線程空閑就交給檢測線程處理如果檢測還沒完成就先顯示上一幀的檢測結果不阻塞等待。import cv2 import torch import time # 假設 model 是訓練好的模型 model.eval() cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # 跳幀計數(shù) frame_skip 2 frame_count 0 last_results None while True: ret, frame cap.read() if not ret: break # 如果到達跳幀間隔執(zhí)行檢測 if frame_count % frame_skip 0: results detect_frame(model, frame) # 返回繪制后的圖像 last_results results # 優(yōu)先顯示最新檢測結果 display last_results if last_results is not None else frame cv2.imshow(Detection, display) if cv2.waitKey(1) 0xFF ord(q): break frame_count 1 cap.release() cv2.destroyAllWindows()延遲控制的另一個關鍵點是把圖像讀取和模型推理放到不同的線程或者至少不要在讀取幀的同一線程里跑模型推理。因為在推理期間攝像頭緩沖區(qū)會持續(xù)積壓新幀讀到的幀越來越陳舊畫面延遲越來越大。把兩個操作解耦后檢測線程專注推理展示線程專注顯示延遲體驗會好很多。攝像頭畫質也會影響檢測效果。我建議把攝像頭分辨率設成1280x720不需要4K因為過高的分辨率對模型精度提升有限反而增加預處理耗時。光線較暗的環(huán)境里可以適當開啟攝像頭的低照度模式或者加補光因為模型在低光照下誤檢率會明顯上升。5. 常見問題與排查技巧實錄5.1 訓練不收斂或loss波動訓練過程中最讓人頭疼的問題就是loss不收斂。我遇到過幾種情況一種是loss一直維持在0.1上下不下降另一種是loss劇烈震蕩還有一種是loss直接變成NaN。loss不下降先檢查學習率是不是太小。YOLO系列默認初始學習率是0.01如果基礎環(huán)境變了比如數(shù)據(jù)集規(guī)模特別小學習率可以降到0.001左右重新跑。學習率太大則表現(xiàn)為loss震蕩特別在訓練后期需要配合余弦退火把學習率降下來。loss變NaN最常見的原因是梯度爆炸。我排查的第一件事是看數(shù)據(jù)集中有沒有異常標注比如某個目標框坐標超過圖片邊界或者類別序號超出類別總數(shù)這類臟數(shù)據(jù)會直接破壞訓練。第二個排查點是學習率把學習率調(diào)低一個數(shù)量級再試。還有一個比較少但真實存在的坑顯卡溫度的波動導致硬件不穩(wěn)定也會偶發(fā)出現(xiàn)NaN這種情況下?lián)Q個時間段跑同樣的訓練如果不再出現(xiàn)說明不是代碼問題。5.2 攝像頭推流延遲、卡頓攝像頭檢測最常見的問題是畫面越來越卡、延遲越來越大。原因前面提過圖像讀取線程和推理線程沒有解耦導致顯示的是過期幀。遇到延遲問題時我的排查順序是先看視頻讀取速度再看推理速度。先單獨測試攝像頭讀幀的速度如果本身就慢那可能是攝像頭驅動或USB帶寬問題換一個攝像頭試試。如果讀幀正常推理每幀耗時超過200毫秒那就需要優(yōu)化推理速度。推理提速有幾個方向一是直接把輸入分辨率從640降到416速度提升明顯精度稍微下降二是用半精度推理只要顯卡支持就能在保持精度基本不變的情況下大幅提速三是做TensorRT等專用加速這個在嵌入式設備上效果最明顯但部署復雜度會高一些。5.3 小目標漏檢和誤檢人行道障礙物檢測里小目標的問題特別突出——比如遠處的電動車、很小的盲道磚破損。YOLO系列模型對越大越清晰的目標效果越好小目標天然吃虧。解決小目標漏檢我的經(jīng)驗是兩條路。第一條是數(shù)據(jù)層面保證訓練集中小目標樣本占比合理并且對所有小目標框都嚴格標注不能因為目標小就順手忽略。第二條是推理層面使用多尺度推理對同一張圖片用原始分辨率、放大的分辨率各推理一次合并結果能提升小目標召回率但推理耗時加倍這種策略適合離線處理不適合實時場景。誤檢的高發(fā)場景也有規(guī)律夜間路燈下的樹影、斑馬線旁的石墩子都可能被誤識別為障礙物。經(jīng)驗上看誤檢往往集中在特定場景下統(tǒng)計錯誤樣本中出現(xiàn)頻率最高的圖片形態(tài)再有針對性補充負樣本和圖譜往往能快速收斂問題。不要一上來就加數(shù)據(jù)量很多情況下誤檢是訓練數(shù)據(jù)里背景環(huán)境太單一導致的。5.4 模型加速與壓縮經(jīng)驗之前在一個演示環(huán)境里我只用CPU跑推理。模型前向傳播一次就要幾百毫秒根本沒法做實時檢測。后面我用了兩個技巧一是把模型導出成TorchScript格式去掉動態(tài)圖開銷二是使用半精度計算在支持的硬件上推理速度幾乎翻倍。還有一個實戰(zhàn)技巧是減少推理中的無用計算。比如對視頻檢測場景背景基本不變可以只在畫面變化明顯的區(qū)域做檢測但這個方法實現(xiàn)復雜容易引入新問題我在實際項目里用得不多。更穩(wěn)妥的方案是固定輸入尺寸、減少NMS的候選框數(shù)量上限比如把每張圖片最多保留300個檢測框改成100個推理速度會有可感知的提升對典型場景影響不大。6. 這套系統(tǒng)的延伸方向與個人體會6.1 從檢測到上報對接工單系統(tǒng)模型檢測出障礙物只是第一步真正產(chǎn)生業(yè)務價值的是檢測結果能自動觸發(fā)處置流程。我在模擬的項目里把檢測結果導出成帶時間戳、位置坐標、現(xiàn)場照片的結構化記錄再通過接口拉到市政巡查平臺上自動生成待辦任務。這個方向對系統(tǒng)的要求就不只是檢測精度了還有定位能力。單靠攝像頭畫面無法精確知道障礙物在哪條路的哪個具體位置所以部署時很多項目會接入經(jīng)緯度信息或者在巡檢車上加GPS模塊檢測到目標的同時記錄當時的定位。對接工單系統(tǒng)后發(fā)現(xiàn)問題的確認效率提升了現(xiàn)場復核時間也減少了。如果只做檢測不做閉環(huán)系統(tǒng)的價值會大打折扣。6.2 一些個人實操體會系統(tǒng)性來說在這類目標檢測項目里80%的時間都在和數(shù)據(jù)打交道。模型結構、訓練參數(shù)這些社區(qū)里的開源方案已經(jīng)很成熟了真正決定項目成敗的是你有沒有一套干凈規(guī)范的數(shù)據(jù)集。標注質量差、場景覆蓋不全再好的模型也救不回來。另外一點體會是算法模型要在真實場景里邊用邊改。在實驗室驗證集上mAP高不代表現(xiàn)場效果就好。攝像頭安裝高度、光線角度、畫面抖動都會影響檢測效果。我建議項目上線后保留一段時間的現(xiàn)場數(shù)據(jù)持續(xù)補充訓練集模型效果會越用越好而不是一錘子買賣。最后想分享的一個細節(jié)技巧是給模型寫推理腳本時盡量把預處理和后處理封裝成獨立函數(shù)參數(shù)用配置文件管理這樣后期換數(shù)據(jù)、換場景、調(diào)閾值時不需要改動核心代碼只改配置就能完成能省掉很多重復調(diào)試的時間。