檢測:YOLOv8小目標(biāo)訓(xùn)練與OBB旋轉(zhuǎn)框?qū)崙?zhàn)指南)
簡介這是一份面向智能交通、自動駕駛與智慧城市應(yīng)用的無人機視角交通目標(biāo)檢測YOLO格式數(shù)據(jù)集。數(shù)據(jù)集包含956張訓(xùn)練航拍圖與169張驗證航拍圖覆蓋公交、轎車、廂式貨車、摩托車、船舶、商業(yè)車輛、工程車輛、特種車輛及區(qū)域特色車輛共9類陸海交通工具標(biāo)注采用YOLO格式并經(jīng)航空影像專家雙重校驗。壓縮包共2000個文件以1125個txt標(biāo)注文件、873個jpg航拍圖片為主體另含1個yaml配置與1個docx說明文檔整體大小83.14MB目錄結(jié)構(gòu)清晰便于直接投入模型訓(xùn)練。該數(shù)據(jù)集突出高空視角特性涵蓋城市道路、港口、建筑工地等多樣環(huán)境及日間、黃昏、晴/多云等光照條件包含車輛轉(zhuǎn)向、泊車、編隊行駛等動態(tài)樣本可有效補充傳統(tǒng)地面視角數(shù)據(jù)提升目標(biāo)檢測模型的多維度泛化能力。已有125人學(xué)習(xí)適合用于車流監(jiān)控、違章識別、應(yīng)急救援等場景的開發(fā)與算法驗證。1. 無人機視角交通目標(biāo)檢測數(shù)據(jù)集高空小目標(biāo)不白嫖先搞清這批圖怎么用做無人機視角的交通目標(biāo)檢測最煩的不是模型是數(shù)據(jù)。公開數(shù)據(jù)集里 KITTI、BDD100K 全是車載平視視角你拿它訓(xùn)出來的模型一放到高空俯視圖上漏檢率直接翻倍——因為目標(biāo)尺度、遮擋模式、光照角度完全不是一回事。這個名為“無人機視角交通目標(biāo)檢測數(shù)據(jù)集.zip”的資源在 YOLO 生態(tài)里算是比較難得的垂直場景包圖源是無人機航拍視角覆蓋車輛、行人、騎行者和交通標(biāo)志等類別標(biāo)注格式能直接喂給 YOLO 系模型。適合誰你要做車流密度分析、違章抓拍、智慧園區(qū)巡邏或者想把手頭的 VOC 模型遷移到高空場景這批數(shù)據(jù)就是替你省采集和標(biāo)注時間的。它解決的核心問題只有一個把“從天上往下看交通”這件事的數(shù)據(jù)分布拉到你模型訓(xùn)練能用的水平。2. 數(shù)據(jù)集解剖目錄結(jié)構(gòu)、標(biāo)注格式與類別分布拿到壓縮包先別急著解壓扔給訓(xùn)練腳本先花五分鐘把目錄和標(biāo)注格式摸清后面能省半天排錯時間。無人機視角數(shù)據(jù)集的坑往往不在模型而在標(biāo)注文件和你預(yù)期不一致。2.1 目錄結(jié)構(gòu)與標(biāo)注文件先看 json 里的坐標(biāo)體系壓縮包解壓后常見做法是這么組織的unzip 無人機視角交通目標(biāo)檢測數(shù)據(jù)集.zip -d drone_traffic/ tree drone_traffic -L 2我一般會先跑上面這行命令看兩層結(jié)構(gòu)。正常的無人機交通數(shù)據(jù)集目錄應(yīng)該是drone_traffic/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── annotations/ │ ├── train.json │ ├── val.json │ └── test.json └── classes.txt如果 annotations 下是 json 而不是 xml那大概率是 COCO 格式或自定義 JSON 結(jié)構(gòu)。這里有個高頻分叉點很多從無人機視頻抽幀做的數(shù)據(jù)集標(biāo)注框是旋轉(zhuǎn)框OBBOriented Bounding Box因為俯視圖下車頭朝向各異水平框會框進大面積背景。先讀一個標(biāo)注看看import json with open(drone_traffic/annotations/train.json, r, encodingutf-8) as f: data json.load(f) # COCO 風(fēng)格的話keys 通常是 info/images/annotations/categories print(data.keys()) print(data[annotations][0])常見的兩種格式區(qū)別如下格式類型坐標(biāo)字段適合的檢測方式COCO 水平框bbox: [x, y, w, h]水平框檢測YOLOv8 默認(rèn)OBB 旋轉(zhuǎn)框segmentation四點或rbox: [cx, cy, w, h, angle]旋轉(zhuǎn)框檢測YOLOv8-obb / MMRotate如果看到segmentation字段是四個點坐標(biāo)那這批標(biāo)注很可能支持旋轉(zhuǎn)框訓(xùn)練。你直接拿它當(dāng)水平框訓(xùn)不是不行但密集車輛場景下精度上限會被框的“多余背景”按住后面第 4 章細(xì)說。2.2 類別分布與適用場景從車輛類型到小目標(biāo)密度把類別統(tǒng)計跑一遍比看任何 README 都直觀from collections import Counter cat_ids [ann[category_id] for ann in data[annotations]] counter Counter(cat_ids) print(counter) # 再看目標(biāo)尺寸分布小目標(biāo)占比 small 0 for ann in data[annotations]: w, h ann[bbox][2], ann[bbox][3] if w 32 and h 32: small 1 print(f小目標(biāo)32px占比: {small / len(data[annotations]) * 100:.1f}%)這段代碼的邏輯第一個 Counter 統(tǒng)計每個類別出現(xiàn)次數(shù)讓你知道類別是否均衡第二個統(tǒng)計小目標(biāo)占比這是無人機交通場景的命門——航拍高度 50 米以上一輛普通轎車的像素寬度經(jīng)常只有 20 到 40 像素屬于典型的小目標(biāo)檢測場景。這個統(tǒng)計結(jié)果直接決定你后面訓(xùn)練怎么配參小目標(biāo)占比高img_size就不能設(shè)太低mosaic增強的比例也要謹(jǐn)慎調(diào)。另一個值得注意的點是類別定義交通標(biāo)志和信號燈在部分?jǐn)?shù)據(jù)集里會被合并成一個類如果你需要細(xì)分得自己改標(biāo)注。一個判斷技巧如果訓(xùn)練集圖片數(shù)量在 5000 張上下、目標(biāo)實例在 2 萬到 5 萬這個量級那這批數(shù)據(jù)對單卡訓(xùn)練來說剛夠用不用急著上額外預(yù)訓(xùn)練。數(shù)量低于 1000 張就要考慮用預(yù)訓(xùn)練權(quán)重做遷移學(xué)習(xí)后面會具體講參數(shù)。3. 訓(xùn)練自己的 YOLOv8 模型從數(shù)據(jù)劃分到參數(shù)調(diào)試數(shù)據(jù)集看清了接下來走完整訓(xùn)練鏈路。YOLOv8 是現(xiàn)在跑這類數(shù)據(jù)集最省事的框架之一不只是因為它訓(xùn)練快還因為它的數(shù)據(jù)增強策略和處理小目標(biāo)的邏輯比老版本 YOLOv5 成熟一些。下面從數(shù)據(jù)劃分開始到訓(xùn)練參數(shù)的選擇最后集中講幾個無人機場景的常見坑。3.1 數(shù)據(jù)劃分與路徑修正別被中文文件名坑了無論是直接提供 YOLO 格式還是 JSON 格式第一步保證路徑正確。常見問題是Windows 解壓出來的路徑帶反斜杠Linux 下訓(xùn)練腳本讀不到文件名帶中文或空格ultralytics 在解析時容易翻車。我一般把整個流程固定為兩步import os import random random.seed(42) images os.listdir(drone_traffic/images/train) random.shuffle(images) train_ratio 0.8 train_files images[:int(len(images) * train_ratio)] val_files images[int(len(images) * train_ratio):] def write_split(file_list, out_path): with open(out_path, w) as f: for name in file_list: abs_path os.path.abspath(os.path.join(drone_traffic/images/train, name)) f.write(abs_path \n) write_split(train_files, train.txt) write_split(val_files, val.txt)這段腳本的作用是把圖片絕對路徑寫進文本文件供后續(xù) YOLO 格式的 txt 標(biāo)注對齊使用。為什么要用絕對路徑因為 YOLOv8 的 data.yaml 里如果是相對路徑換一臺機器跑就得改絕對路徑至少在當(dāng)前機器上不會出歧義。然后寫 data.yamlpath: /home/user/drone_traffic train: images/train val: images/val test: images/test nc: 4 # 按類別數(shù)改 names: [car, truck, pedestrian, cyclist]參數(shù)說明path是數(shù)據(jù)集根目錄的絕對路徑train和val是相對路徑nc是類別數(shù)量必須和標(biāo)注文件的類別 id 對應(yīng)上names順序也直接影響訓(xùn)練日志里類別名的顯示別排錯。3.2 YOLOv8 訓(xùn)練參數(shù)img 尺寸、epochs 與優(yōu)化器無人機視角的模型訓(xùn)練參數(shù)選擇和普通目標(biāo)檢測有區(qū)別。我直接給一套可復(fù)現(xiàn)的配置from ultralytics import YOLO model YOLO(yolov8m.pt) results model.train( datadrone_traffic/data.yaml, epochs100, imgsz896, batch8, device0, lr00.001, optimizerAdamW, mosaic0.5, augmentTrue, patience20, )幾個關(guān)鍵參數(shù)的選擇邏輯imgsz896是無人機場景最重要的一個值。默認(rèn) 640 對高空俯視圖來說偏小一輛車在 640 分辨率下只有 20 像素傳到網(wǎng)絡(luò)深層特征圖后可能只剩個把像素檢測頭根本沒法回歸。提到 896 能讓小目標(biāo)的特征保留多一倍顯存不夠就 768低于 640 就不要玩了。batch8是 896 分辨率下 24GB 顯存的常見選擇如果你的卡是 12GB 的batch 降到 4或者把 imgsz 降回 768。mosaic0.5要注意mosaic 增強對俯視小目標(biāo)不是越多越好它把四張圖拼在一起目標(biāo)會被縮小四倍小目標(biāo)更容易被增強成“看不見的噪聲”。我一般會控制在 0.5 而不是默認(rèn)的 1.0。優(yōu)化器和學(xué)習(xí)率無人機場景下默認(rèn)的 SGD 也能收斂但 AdamW 在批量較小、目標(biāo)較小時更穩(wěn)。lr00.001是遷移學(xué)習(xí)的一個折中點如果是從隨機初始化開始訓(xùn)練調(diào)到 0.01 也行但沒必要——你是在 YOLOv8m 的 COCO 預(yù)訓(xùn)練權(quán)重上繼續(xù)訓(xùn)練初始學(xué)習(xí)率太大容易把前面的特征毀掉。patience20意味著 20 輪指標(biāo)沒提升就提前停止防止在數(shù)據(jù)不大時后段過擬合。3.3 避坑手冊無人機視角目標(biāo)檢測的 5 條血淚經(jīng)驗這一節(jié)是我自己跑這類數(shù)據(jù)集和看別人翻車總結(jié)出來的高頻問題按“現(xiàn)象 → 原因 → 解決”寫???1驗證集 mAP 很高俯視真實場景卻瘋狂漏檢現(xiàn)象模型在測試集上 mAP 超過 0.75部署到無人機拍攝的新視頻里小目標(biāo)漏檢率超過 50%。原因數(shù)據(jù)集劃分時有隨機性但無人機航拍數(shù)據(jù)往往相鄰幀高度相關(guān)隨機劃分會把相似圖片同時放進訓(xùn)練和驗證集分?jǐn)?shù)虛高。解決劃分時按“視頻序列”或“拍攝區(qū)域”分組不要讓同一個序列的圖同時出現(xiàn)在訓(xùn)練和驗證里。代碼上可以先按文件名前綴分組再劃分???2中文或空格路徑導(dǎo)致訓(xùn)練中斷現(xiàn)象訓(xùn)練到一半報FileNotFoundError或者 ultralytics 直接卡在讀圖階段。原因Windows 解壓的路徑含中文目錄名或者文件名帶空格Python 的 glob 和 YOLO 的 LoadImages 在某些場景下解析異常。解決解壓后立即統(tǒng)一重命名全部轉(zhuǎn)成英文和下劃線訓(xùn)練前做一次路徑校驗with open(train.txt) as f: for line in f: line line.strip() if not os.path.exists(line): print(缺失:, line)坑 3小目標(biāo)在標(biāo)注里是“噪聲”現(xiàn)象訓(xùn)練后 loss 降不下去val loss 在某個值附近震蕩。畫出來看小目標(biāo)區(qū)域預(yù)測框亂飄。原因有些無人機數(shù)據(jù)集從視頻按幀抽運動模糊和遠(yuǎn)距離小目標(biāo)標(biāo)注本身就不準(zhǔn)框偏移幾個像素對 loss 的影響相對大。解決訓(xùn)練前做標(biāo)注清洗篩掉寬度或高度小于 5 像素的框或者用自動化工具重新標(biāo)注一遍模糊幀。寧可少而精不要多而臟???4車輛密集區(qū)域的 NMS 后框被誤刪現(xiàn)象路口的車輛挨得近預(yù)測框重疊度超過 NMS 閾值后處理階段留下一個框把旁邊的車丟了。原因俯視圖下車頂視圖相似度高多個目標(biāo)的特征趨同NMS 只按 IoU 判重直接把低置信度的鄰近目標(biāo)刪了。解決測試時調(diào)低conf閾值到 0.15 左右iou閾值從默認(rèn)的 0.5 提到 0.6如果密集程度特別高考慮上旋轉(zhuǎn)框方案第 4 章展開???5模型在夜間和陰天識別崩塌現(xiàn)象白天訓(xùn)練的模型一遇到陰天或黃昏漏檢率大幅上升。原因無人機數(shù)據(jù)集大多在白天采集光照分布單一模型學(xué)到的是“強光照下的紋理”不是“物體本身的結(jié)構(gòu)特征”。解決訓(xùn)練時把光照增強打開包含亮度、對比度擾動如果有余力用簡單色彩空間處理把部分訓(xùn)練圖轉(zhuǎn)成低光照效果做偽樣本。4. 旋轉(zhuǎn)框與多尺度用 MMRotate 處理密集排列目標(biāo)如果你解壓數(shù)據(jù)集時發(fā)現(xiàn)標(biāo)注是四點格式或者訓(xùn)練后車輛邊框重疊嚴(yán)重那就該考慮旋轉(zhuǎn)框檢測了。無人機俯視場景里目標(biāo)在圖像中的角度是任意的水平框表示會引入大量背景旋轉(zhuǎn)框能把框緊貼目標(biāo)顯著降低誤檢和漏檢。4.1 旋轉(zhuǎn)框標(biāo)注轉(zhuǎn)換從 HBB 到 OBB 的代價水平框HBB轉(zhuǎn)旋轉(zhuǎn)框OBB不是公式調(diào)用就行要處理角度定義問題。常見做法是使用 OpenCV 的minAreaRect把水平框內(nèi)所有標(biāo)注點的最小外接矩形求出來import cv2 import numpy as np points np.array([[x1, y1], [x2, y2], [x3, y3], [x4, y4]], dtypenp.float32) rect cv2.minAreaRect(points) (cx, cy), (w, h), angle rect # 轉(zhuǎn)換為 MMRotate 或 YOLOv8-obb 的格式 if w h: w, h h, w angle 90 obb [cx, cy, w, h, angle] print(obb)這段代碼的核心邏輯是先求四點的最小外接矩形再對角度做歸一化因為minAreaRect返回的角度范圍是 [-90, 0)轉(zhuǎn)成訓(xùn)練需要的格式時要把長邊對準(zhǔn) x 軸角度范圍統(tǒng)一到 [0, 90) 或 [-90, 90)具體看訓(xùn)練框架讀什么格式。注意四點坐標(biāo)必須按順序給出否則minAreaRect的結(jié)果是錯的。用 MMRotate 時推薦直接用occluded_obbox格式更穩(wěn)定。4.2 多尺度推理與切片把 896 分辨率用出性價比旋轉(zhuǎn)框模型訓(xùn)練完推理階段要解決另一個問題原始無人機圖像往往超過 4000×3000 像素直接縮放整圖再推理小目標(biāo)基本廢掉。兩個方案方案一TTA 多尺度融合——測試時把圖片同時縮放到 0.8、1.0、1.2 倍分別推理后融合結(jié)果。這個方法實現(xiàn)簡單但對顯存要求高耗時也長。方案二滑窗切片推理——更像是工程做法。把大圖切成 896×896 的塊每塊重疊 10%推理后根據(jù)塊的原始坐標(biāo)把框映射回大圖坐標(biāo)系。切片的好處是把每輛車的像素面積放大模型能提取到更多特征。切片的代價是目標(biāo)靠近邊緣時會被切半需要靠重疊區(qū)域來兜底。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) img cv2.imread(drone_frame_001.jpg) H, W img.shape[:2] window 896 overlap 0.1 results_all [] for y in range(0, H - window // 2, int(window * (1 - overlap))): for x in range(0, W - window // 2, int(window * (1 - overlap))): crop img[y:y window, x:x window] results model(crop, conf0.2, iou0.5) for r in results: for box in r.boxes.data: x1, y1, x2, y2, conf, cls box.tolist() # 映射回原始坐標(biāo) results_all.append([x x1, y y1, x x2, y y2, conf, int(cls)])映射這段代碼容易出錯切片的坐標(biāo)偏移量x和y在重疊區(qū)域不要累加過頭循環(huán)步長用的是int(window * (1 - overlap))而不是window這樣重疊區(qū)域的目標(biāo)不會因為被切掉一半而丟失。如果目標(biāo)的中心在重疊區(qū)域內(nèi)會重復(fù)檢測一次后處理時按置信度保留最高那個即可。MMRotate 和 YOLOv8-obb 怎么選我是這么判斷的數(shù)據(jù)量大上萬張、類別雜優(yōu)先 YOLOv8-obb因為它訓(xùn)練速度快、生態(tài)成熟數(shù)據(jù)量中等但車輛密集度極高MMRotate 的 Oriented R-CNN 在精度上限上還是高一點但代價是配置時間長、跑一輪要看一堆報錯。實際項目趕進度YOLOv8-obb 已經(jīng)能覆蓋 90% 的需求了。5. 進階驗證與調(diào)優(yōu)技巧讓小目標(biāo)檢測再漲兩三個點模型訓(xùn)出來了mAP 也挺好看但部署前必須做一輪“對抗性驗證”。這一章給兩個具體技巧可視化找病灶、用數(shù)據(jù)增強邊界換精度提升。5.1 可視化與錯誤分析先改 Loss 還是先加數(shù)據(jù)很多人的習(xí)慣是看 mAP 不好就換模型、調(diào)學(xué)習(xí)率但真正的病灶在看圖才能發(fā)現(xiàn)。我每輪訓(xùn)練完都會強制跑一次批量推理存成圖片逐張看。import os from ultralytics import YOLO model YOLO(best.pt) val_images os.listdir(drone_traffic/images/val)[:50] for name in val_images: path os.path.join(drone_traffic/images/val, name) model.predict(path, saveTrue, imgsz896, conf0.15, iou0.6)把預(yù)測結(jié)果和原圖對齊翻一遍重點看三類錯誤漏檢的是小目標(biāo)還是遮擋目標(biāo)誤檢集中在樹蔭、樓頂還是車輛陰影密集區(qū)域是漏檢多還是框重疊多。這個判斷直接決定下一步是調(diào) NMS、加數(shù)據(jù)還是換 Loss。如果是密集場景漏檢、同時單個目標(biāo)的置信度并不低那就先從 NMS 入手調(diào)iou0.6后重測如果是小目標(biāo)整體漏檢MAE 類的 Loss 替代 BCE 也許是方向但在 YOLOv8 上直接改 Loss 是個大工程我更傾向于先補數(shù)據(jù)更穩(wěn)。5.2 數(shù)據(jù)增強的邊界Mosaic 在俯視圖上的翻車現(xiàn)場上一章提到 Mosaic 會縮小目標(biāo)這里展開講邊界。在無人機俯視圖里mosaic 增強拼接四張航拍圖的反應(yīng)和地面視角不一樣地面目標(biāo)本來就在 40 到 100 像素區(qū)間縮小四倍后依然有 10 到 25 像素還能認(rèn)但無人機小目標(biāo)原本只有 20 到 40 像素縮小四倍后掉到 5 到 10 像素人眼都難分辨模型更學(xué)不到東西。我的做法是訓(xùn)練時開mosaic0.5讓模型在前半段學(xué)多尺度后 20 輪把 Mosaic 關(guān)閉用原始尺度精修r(nóng)esults model.train( datadrone_traffic/data.yaml, epochs80, imgsz896, batch8, mosaic0.5, close_mosaic15, )close_mosaic15的意思是在最后 15 個 epoch 自動關(guān)閉 Mosaic 增強。效果相當(dāng)于前半段學(xué)抗尺度擾動后半段回歸真實分布。這個參數(shù)在 ultralytics 里是原生支持的屬于花小錢辦大事的參數(shù)。完成這輪調(diào)優(yōu)后我會把驗證集重新跑一遍把每張圖的置信度閾值、推理耗時報個表再決定要不要上 TensorRT。用 YOLOv8 訓(xùn)練無人機視角數(shù)據(jù)集這件事數(shù)據(jù)分布理解比模型選型更能決定最終效果。從那以后我每次拿到新的航拍數(shù)據(jù)集都強制先做類別統(tǒng)計和小目標(biāo)占比分析再決定要不要上 OBB、Mosaic 要開多大——這個順序反過來走十次有八次要返工重訓(xùn)。希望這篇筆記能幫你少走這幾個來回。本文還有配套的精品資源點擊獲取