據(jù)集與增強策略詳解)
1. 無人機視角下的目標檢測數(shù)據(jù)集概述在無人機航拍場景中目標檢測技術(shù)面臨著獨特的挑戰(zhàn)——小目標檢測。與常規(guī)視角不同無人機拍攝的物體往往只占畫面的極小比例通常小于32×32像素這對數(shù)據(jù)集的構(gòu)建提出了特殊要求。目前主流的小目標檢測數(shù)據(jù)集主要分為兩類通用型數(shù)據(jù)集如COCO、VOC的子集和專用型無人機數(shù)據(jù)集如VisDrone、UAVDT。關(guān)鍵區(qū)別無人機數(shù)據(jù)集通常包含更多1%圖像面積的目標且背景復(fù)雜度更高。以VisDrone為例其平均每個目標僅占0.008%的圖像面積是COCO數(shù)據(jù)集中小目標比例的1/50。2. 主流無人機小目標檢測數(shù)據(jù)集詳解2.1 VisDrone數(shù)據(jù)集數(shù)據(jù)規(guī)模10,209張圖片6,471訓(xùn)練集548驗證集3,190測試集標注格式同時提供VOC和YOLO格式類別特點行人占比37%車輛51%自行車/三輪車12%下載方式# 官方下載指令需注冊 wget http://aiskyeye.com/download/visdrone/VisDrone2019-DET-train.zip unzip VisDrone2019-DET-train.zip -d ./visdrone2.2 UAVDT數(shù)據(jù)集獨特價值包含30小時1080P視頻特別適合動態(tài)小目標檢測標注特點車輛邊界框運動軌跡光照條件標注晴天/陰天/夜間轉(zhuǎn)換YOLO格式示例import xml.etree.ElementTree as ET def voc2yolo(voc_path, yolo_path): tree ET.parse(voc_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) with open(yolo_path, w) as f: for obj in root.iter(object): cls obj.find(name).text bbox obj.find(bndbox) x_center (float(bbox.find(xmin).text) float(bbox.find(xmax).text)) / 2 / w y_center (float(bbox.find(ymin).text) float(bbox.find(ymax).text)) / 2 / h width (float(bbox.find(xmax).text) - float(bbox.find(xmin).text)) / w height (float(bbox.find(ymax).text) - float(bbox.find(ymin).text)) / h f.write(f{cls_id} {x_center} {y_center} {width} {height}\n)3. 小目標檢測數(shù)據(jù)增強策略3.1 專用數(shù)據(jù)增強技術(shù)多尺度切片增強Mosaic Augmentation將4張圖像隨機縮放后拼接顯著增加小目標出現(xiàn)頻率YOLOv5實現(xiàn)示例def mosaic_augmentation(images, labels): # 創(chuàng)建空白畫布 s 640 # 目標尺寸 mosaic_img np.full((s*2, s*2, 3), 114, dtypenp.uint8) # 隨機選取拼接中心點 xc, yc [int(random.uniform(s*0.25, s*0.75)) for _ in range(2)] # 處理4張圖像 for i in range(4): img, (lbl_h, lbl_w) images[i], labels[i].shape # 隨機縮放 r min(s/img.shape[0], s/img.shape[1]) img cv2.resize(img, (int(img.shape[1]*r), int(img.shape[0]*r))) # 計算放置位置 h, w img.shape[:2] if i 0: # 左上 x1a, y1a, x2a, y2a max(xc-w, 0), max(yc-h, 0), xc, yc x1b, y1b, x2b, y2b w-(x2a-x1a), h-(y2a-y1a), w, h elif i 1: # 右上 x1a, y1a, x2a, y2a xc, max(yc-h, 0), min(xcw, s*2), yc x1b, y1b, x2b, y2b 0, h-(y2a-y1a), min(w, x2a-x1a), h elif i 2: # 左下 x1a, y1a, x2a, y2a max(xc-w, 0), yc, xc, min(s*2, ych) x1b, y1b, x2b, y2b w-(x2a-x1a), 0, w, min(y2a-y1a, h) elif i 3: # 右下 x1a, y1a, x2a, y2a xc, yc, min(xcw, s*2), min(s*2, ych) x1b, y1b, x2b, y2b 0, 0, min(w, x2a-x1a), min(y2a-y1a, h) mosaic_img[y1a:y2a, x1a:x2a] img[y1b:y2b, x1b:x2b] return mosaic_img3.2 小目標專用損失函數(shù)Focal Loss改進版class SmallObjectFocalLoss(nn.Module): def __init__(self, alpha0.25, gamma2.0, small_obj_thresh32): super().__init__() self.alpha alpha self.gamma gamma self.thresh small_obj_thresh # 像素面積閾值 def forward(self, pred, target): BCE_loss F.binary_cross_entropy_with_logits(pred, target, reductionnone) # 計算目標大小權(quán)重 target_area (target[:, 2] - target[:, 0]) * (target[:, 3] - target[:, 1]) area_weight torch.where(target_area self.thresh, torch.tensor(2.0).to(device), torch.tensor(1.0).to(device)) pt torch.exp(-BCE_loss) focal_loss self.alpha * (1-pt)**self.gamma * BCE_loss * area_weight return focal_loss.mean()4. 數(shù)據(jù)集標注與質(zhì)量檢查4.1 LabelImg標注技巧小目標標注規(guī)范最小接受尺寸4×4像素模糊目標處理至少3人交叉驗證部分遮擋處理標注可見部分保存路徑設(shè)置# 啟動時指定路徑 labelimg --labels drone_labels.txt --autosave --savedir ./annotations4.2 標注質(zhì)量驗證腳本def verify_annotations(img_dir, label_dir): issues [] for label_file in os.listdir(label_dir): img_file os.path.join(img_dir, label_file.replace(.txt, .jpg)) if not os.path.exists(img_file): issues.append(fMissing image: {img_file}) continue img cv2.imread(img_file) h, w img.shape[:2] with open(os.path.join(label_dir, label_file)) as f: for line in f: cls, xc, yc, bw, bh map(float, line.strip().split()) x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) if x1 x2 or y1 y2: issues.append(fInvalid bbox in {label_file}: {line}) elif (x2-x1)*(y2-y1) 16: issues.append(fToo small bbox in {label_file}: {x2-x1}x{y2-y1}px) return issues5. 模型訓(xùn)練與部署實戰(zhàn)5.1 YOLOv8小目標專用配置# yolov8-drone.yaml nc: 10 # 類別數(shù) scales: small: depth: 0.33 width: 0.25 anchors: 3 anchors_new: [[3,4, 5,8, 7,12], [9,16, 12,32, 19,48]] # 更小的anchor尺寸 train: mosaic: 1.0 mixup: 0.1 small_object_scale: 2.0 # 小目標損失權(quán)重5.2 RK3588部署優(yōu)化模型量化python export.py --weights yolov8n.pt --include onnx --simplify --dynamic rknn-toolkit2/convert.py yolov8n.onnx --output yolov8n.rknn --mean-values 0,0,0 --std-values 255,255,255推理加速技巧使用NPU專用算子替換常規(guī)卷積將檢測頭改為共享權(quán)重結(jié)構(gòu)啟用異步DMA數(shù)據(jù)傳輸6. 常見問題解決方案問題現(xiàn)象可能原因解決方案小目標漏檢率高Anchor尺寸不匹配使用k-means重新聚類anchor虛警多背景復(fù)雜度高增加CutMix數(shù)據(jù)增強推理速度慢后處理耗時改用Batch NMS標注不一致標注標準模糊制定最小目標尺寸規(guī)范在實際無人機項目中我們發(fā)現(xiàn)最影響精度的三個關(guān)鍵因素標注一致性建議多人交叉驗證數(shù)據(jù)增強策略必須包含小目標專用增強檢測頭設(shè)計建議使用高分辨率特征圖