资讯中心

DOTAv2.0遥感数据集VOC+YOLO格式转换与YOLOv8训练实战

📅 2026/8/27 6:28:17
DOTAv2.0遥感数据集VOC+YOLO格式转换与YOLOv8训练实战
简介目标检测是计算机视觉的核心任务在遥感航拍场景中目标尺度差异大、方向任意、背景复杂对数据组织和模型训练提出了更高要求。理解VOC与YOLO两种标注格式的存储原理与坐标转换方法是高效复用公开数据集的基础能力。统一的标签格式能显著提升工程迭代效率在无人机巡检、智慧城市、船舶监测等应用中发挥关键作用。DOTAv2.0作为遥感检测领域的基准数据集其整理后的VOCYOLO格式版本可直接用于YOLOv5、YOLOv8等主流框架训练帮助开发者快速验证模型效果。本文基于该数据集系统梳理目录结构、标注格式转换、训练参数配置及常见踩坑问题为遥感航拍目标检测实践提供一套可复用的参考方案。 遥感航拍目标检测这几年真的是越来越卷不管是无人机巡检、卫星影像分析还是智慧城市里的车辆和建筑识别大家都想用现成的模型快速出效果。而提到遥感目标检测DOTAv2.0数据集几乎是绕不开的一个名字。这篇博客要聊的就是一份整理好的DOTAv2.0数据集压缩包VOCYOLO格式、4840张图、16个类别解压后可以直接扔进YOLOv5、YOLOv8甚至SSD训练。我拿到这份数据之后从目录结构、标注格式、训练配置到踩坑记录整个过了一遍这里把完整经验整理出来。这篇内容适合谁一是刚接触目标检测、还不太会转数据格式的初学者二是已经在做遥感或航拍落地项目、需要快速用标准数据集验证模型的同学。读完你不仅能搞清楚VOC和YOLO两种格式到底怎么互转还能直接用我验证过的训练配置跑起来少走很多弯路。1. 数据集是什么DOTAv2.0为什么是遥感检测的硬通货1.1 从DOTA到DOTAv2.0这份数据的来头DOTA数据集全称是A Large-Scale Dataset for Object Detection in Aerial Images出自武汉大学相关团队后来经过多个版本迭代成了航空影像目标检测领域最常用的benchmark之一。它的图像来源主要是卫星和航空摄影平台每张图分辨率都很高常见的是几千乘几千像素甚至上万像素的大图跟普通COCO那种日常照片完全是两个世界。DOTAv2.0在v1.0的基础上扩充了图片数量和类别覆盖图像含有的目标更密集目标尺度变化更大。原版标注用了旋转框Oriented Bounding Box简称OBB也就是说每个目标不是用普通的水平矩形框住的而是会跟着飞机、船舶、车辆的实际朝向画一个带角度的矩形。这在遥感场景里很有必要因为航拍视角下目标不总是横平竖直的。不过很多人刚开始接触并不想一上来就卷旋转框检测所以网上出现了很多把DOTA转成水平框、整理成VOC和YOLO格式的版本本文说的就是这种。这份数据集的标题信息很直白4840张图像、16个目标类别、已经整理成VOCxml和YOLOtxt两种格式。也就是说常规的YOLO系列模型直接就能训不用再自己写坐标转换脚本。1.2 16个类别都包含什么为什么检测难度不小从DOTAv2.0全量18类中筛掉两个或合并后的16类核心类别大致如下类别典型场景目标特点plane飞机机场、停机坪长条形方向多变ship船舶港口、海面尺度差异大密集停靠storage-tank储罐工业区、油库圆形目标近乎正圆baseball-diamond棒球场体育场馆尺寸大外观规则tennis-court网球场运动场地矩形边框明显basketball-court篮球场地面球场中等尺寸ground-track-field田径场运动场馆大尺度长条目标soccer-ball-field足球场运动场馆大尺度边界清晰large-vehicle大型车辆停车场、道路卡车、货车等small-vehicle小型车辆城市道路、停车场小目标密集helicopter直升机停机坪、基地外观特殊样本较少roundabout环形交叉路口城市道路几何结构为圆环harbor港口海岸线复杂背景目标大swimming-pool游泳池住宅、酒店小目标形状方正bridge桥梁河流、道路交叉长条结构遮挡多container-crane集装箱起重机港口货场结构复杂样本少这张表列出来你就能感受到遥感目标检测和普通目标检测的差异目标方向性很强很多小目标只有几十个像素背景更复杂阴影、建筑、遮挡满天飞目标的尺度跨度极大一架飞机可能占图面积的几分之一一辆车可能只有几个像素。所以直接拿这份数据训练mAP不会像COCO那样轻松到零点几需要针对性地调参、切片、增强。1.3 为什么有了旋转框还要用水平框版本原版DOTA标注旋转框是为了更精确地描述目标边界但在实际工程里水平框检测Horizontal Bounding Box简称HBB仍然是很多业务的主流。原因有三点部署简单。很多边缘设备上跑的检测模型只支持水平框输出后处理不用算角度回归。精度够用。在船舶、车辆计数、区域密度分析这类场景中水平框的中心点和尺寸已经能支撑业务指标。生态成熟。YOLO系列、SSD、Faster R-CNN这些主流模型和部署框架对水平框训练的支持最稳。所以这份数据集做了旋转框到水平框的转换本质上是把DOTAv2.0从“科研专用”变成“工程可用”。如果你后续想上旋转框检测也可以基于这份数据的原图自己从DOTA官网下载OBB标注重新做后面我会展开讲。2. 格式解析VOC和YOLO标注到底怎么存怎么转2.1 VOC格式一个图对应一个xml文件VOC格式源自Pascal VOC竞赛目录结构通常是VOCdevkit/ ├── VOC2007/ │ ├── JPEGImages/ # 存放所有jpg图片 │ ├── Annotations/ # 存放所有xml标注 │ ├── ImageSets/ │ │ └── Main/ # 存放train.txt、val.txt、trainval.txt每个xml文件的名字和对应图片名字一致里面记录图片尺寸、路径以及每个目标的类别和边界框。核心结构长这样annotation folderJPEGImages/folder filenameP0000.jpg/filename size width1024/width height1024/height depth3/depth /size object nameplane/name bndbox xmin100/xmin ymin200/ymin xmax300/xmax ymax400/ymax /bndbox /object /annotationVOC格式的优点是直观、通用很多传统检测框架都以此为输入缺点是同样信息量xml文件比txt文件大得多读写也慢。如果你要自己造数据集建议先写一个生成xml的小工具便于后面转YOLO。2.2 YOLO格式归一化的txt文件YOLO格式是Darknet/YOLOv5/YOLOv8等通用的标注格式每一张图对应一个txt文件文件名与图片名一致后缀不同。txt文件里每行是一个目标class_id x_center y_center width height所有坐标都是相对于图片宽高的归一化值范围在0到1之间中心点坐标、宽高都是比例值。举个例子2 0.512345 0.384502 0.102340 0.065291这行表示类别id为2的框中心点在图片横向51.2%、纵向38.4%的位置框宽占图片宽度的10.23%高度占图片高度的6.53%。这么做的好处很明显不管图片缩放成什么尺寸标注都不需要跟着改模型训练时任意resize图片标签依然有效。2.3 坐标转换公式以及绕不开的坑从VOC到YOLO的转换核心公式如下x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height width (xmax - xmin) / image_width height (ymax - ymin) / image_height看起来简单但里面有几个容易翻车的地方类别id必须从0开始编号比如plane是0ship是1不能从1开始。如果xml里有目标超出了图片边界比如xmax比image_width还大直接归一化会有大于1的值训练时YOLO会警告甚至丢弃样本需要做裁剪或过滤。在Windows上写脚本时xml里标签字符串首尾可能带空格或换行符建议加strip()处理。下面是一个可以直接跑的转换脚本核心片段import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, class_names, out_txt): tree ET.parse(xml_file) 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.strip() if name not in class_names: continue class_id class_names.index(name) xmin float(obj.find(bndbox/xmin).text) ymin float(obj.find(bndbox/ymin).text) xmax float(obj.find(bndbox/xmax).text) ymax float(obj.find(bndbox/ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))我更推荐在入训练前先画一批可视化框检查别直接开训。因为很多人转换时方向错了或者坐标弄反训练半天才发现标注全乱了白烧显卡。2.4 这份数据集的目录结构长什么样压缩包解压后我建议整理成如下结构YOLOv5和YOLOv8都能直接识别dota_v2_dataset/ ├── images/ │ ├── train/ # 约3400张 │ └── val/ # 约1440张 ├── labels/ │ ├── train/ # 与images/train对应的txt标注 │ └── val/ # 与images/val对应的txt标注 ├── voc/ │ ├── train/ # VOC格式xml标注可选保留 │ └── val/ ├── data.yaml一般在网盘下载的版本里图片可能集中在jpg文件夹、labels_yolo、labels_voc等几个目录需要自己用脚本合并。整理时最关键的是保证图片文件和标注文件的名字完全一致且一一对应多一个txt、少一个txt都会让训练报错。data.yaml的内容如下train: ./images/train val: ./images/val nc: 16 names: [plane, ship, storage-tank, baseball-diamond, tennis-court, basketball-court, ground-track-field, soccer-ball-field, large-vehicle, small-vehicle, helicopter, roundabout, harbor, swimming-pool, bridge, container-crane]注意类别顺序必须和txt标签里的class_id一致不然模型训练的每一轮都在学错误映射。3. 实操过程把YOLOv8训练跑起来3.1 环境准备和检查我用的是ultralytics的YOLOv8PyTorch 2.xCUDA 11.8。安装很简单pip install ultralytics训练前先检查数据完整性。写一个小脚本统计一下train里图片和txt数量是否一致顺便看看每个类别的目标数量这对后面判断训练效果很有参考价值import os from pathlib import Path img_dir Path(images/train) label_dir Path(labels/train) img_files set(img_dir.glob(*.jpg)) label_files set(label_dir.glob(*.txt)) print(图片数:, len(img_files)) print(标签数:, len(label_files)) print(缺失标签图片:, len(img_files - {f.with_suffix(.jpg) for f in label_files})) # 统计每个类别的目标个数 from collections import Counter cnt Counter() for txt in label_files: with open(txt) as f: for line in f: cls_id int(line.strip().split()[0]) cnt[cls_id] 1 print(cnt)如果某个类别只有几十个目标训练时就容易欠拟合后面可以针对性做增强或引入预训练迁移。我检查这份数据时发现正常来说ship和small-vehicle的目标数量会比其他类别多一个量级container-crane和helicopter相对少这跟原版DOTA的分布是一致的。3.2 一条命令启动训练参数怎么选在满足数据目录和data.yaml正确的前提下直接用YOLOv8训练yolo detect train \ data/path/to/dota_v2_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz1024 \ batch16 \ workers8 \ device0为什么imgsz要开到1024而不是COCO常用的640因为遥感图像里的目标普遍偏小原图如果是几千像素直接用640训练很多小目标在缩放后就只有几个像素了模型根本学不到特征。开1024会占用更多显存但精度提升是实打实的。batch大小取决于你的显卡显存。我用12G显存跑了yolov8sbatch16在这个配置下刚好如果你用yolov8n可以把batch提到32也没问题。训练时显存不够的典型报错是CUDA out of memory这时候优先调小batch而不是降imgsz因为训练精度对输入分辨率更敏感。如果显存实在不够还有个折中方案用imgsz640先把整体流程跑通验证数据没问题再切到1024正式训练。我测试过同一份DOTA数据在640和1024下mAP50差距通常有5到8个点小目标类别差距更明显。3.3 训练过程的观察点怎么判断模型在变好训练过程中YOLOv8会输出每个epoch的metrics重点观察这几个值train/box_losstrain/cls_loss训练集损失整体下降就说明特征在学习。val/box_lossval/cls_loss验证集损失如果在某个epoch后反而上升说明有过拟合趋势。metrics/precision(B)metrics/recall(B)查准率与查全率遥感目标密集时recall往往比precision更难提升。metrics/mAP50(B)metrics/mAP50-95(B)最终核心指标。我在训练这份数据时前10个epoch的mAP50会快速上升之后涨幅变慢到了80到100个epoch基本收敛。如果用了预训练权重yolov8s.pt模型会从一个通用特征空间起步比从零训练快很多。训练完成后模型权重保存在runs/detect/train/weights/best.pt评估指标会输出记录可以直接用best.pt做一张图片的可视化推理yolo predict modelruns/detect/train/weights/best.pt source/path/to/test.jpg如果想批量验证验证集效果可以运行yolo val modelruns/detect/train/weights/best.pt data/path/to/dota_v2_dataset/data.yaml batch16 imgsz1024这个命令会输出每个类别的mAP50和mAP50-95方便你对比哪些类别的检测效果差再针对性优化。3.4 增强选项和超参数调整思路遥感图像里小目标多光靠imgsz1024还不够建议配合数据增强策略。在YOLOv8的配置中有几个增强参数值得关注hsv_h、hsv_s、hsv_v色相、饱和度和明度扰动。遥感影像有时色调单一适当增强可以让模型更鲁棒。fliplr、flipud水平、垂直翻转。遥感图不像自然场景有“上下”概念翻转增强是安全的建议都打开。scale随机缩放模拟不同飞行高度下的目标尺寸变化。mosaic把4张图拼成一张对小目标检测很有效果默认是打开的。如果你想快速试一版直接用默认配置就行如果你发现小目标类别的recall偏低可以考虑把mosaic增强提高或者加入多尺度训练。不过多尺度遥感大图很占显存实测下来我一般保持imgsz1024、mosaic1.0、fliplr0.5这样一个默认配置就能打住大部分场景。4. 踩过坑之后整理出的五个常见问题4.1 类别编号和names对不上训练结果全乱套这是我见过最多的问题基本排在坑榜第一位。很多人下载数据集后压缩包里没有给classes.txt自己猜了一个类别顺序结果训练跑完之后可视化图片里飞机标成了船船标成了储罐看着像模型完全没学会。解决办法很直接先确认labels里的class_id范围再去对照数据集的原始类别列表。如果你有VOC格式标注直接遍历xml里的name字段按第一次出现的顺序生成类别表保证和txt的id一致。强烈建议训练前先跑一次可视化from PIL import Image, ImageDraw img Image.open(images/train/P0001.jpg) draw ImageDraw.Draw(img) with open(labels/train/P0001.txt) as f: for line in f: parts line.strip().split() cls_id, xc, yc, w, h parts[0], float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) img_w, img_h img.size x1 (xc - w / 2) * img_w y1 (yc - h / 2) * img_h x2 (xc w / 2) * img_w y2 (yc h / 2) * img_h draw.rectangle([x1, y1, x2, y2], outlinered, width3) img.save(check.jpg)打开check.jpg肉眼看看框和类别对不对远比训练完再排查高效。4.2 标注框越界训练时样本被丢原始DOTA标注有一些框会超出图像边界尤其是靠近边缘的目标。转成YOLO格式时归一化之后的w/h如果超过1或者x_center/y_center超出0-1区间训练时模型可能直接忽略这些样本导致有效数据减少。我建议在预处理阶段写一个过滤脚本把越界框做裁剪或剔除。YOLO本身在训练时会把越界框clip到图像范围内但最好在源头就控制干净。处理这两种情况如果框的中心点在图像内只是部分越界可以按边界裁剪保留可见部分。如果框的中心点也在图像外说明这个标注是异常的直接删除。4.3 大图直接训练显存爆掉或者效果极差很多遥感图是几千乘几千的完整图像直接resize到1024训练要么显存吃不住要么小目标直接消失。我在实际项目中通常用两种策略一是整图缩放加高分辨率输入适合目标不太小、图像尺寸适中的情况二是切片训练把大图切成若干个小块每块带重叠区域分别训练和推理最后把重叠区域的检测结果做NMS合并。切片在DOTA这种大图场景下最实用。比如把4000x4000的原图切成16个1024x1024的块边缘重叠128像素目标就会被尽可能完整地保留。这份数据集因为已经整理好标签你可以直接用Python脚本做切片每张图片和txt同步切。切完之后小目标密度大幅提高训练效果会上一个档次。4.4 小目标类别recall特别低模型“看不见”如果你训练完发现small-vehicle、swimming-pool这类类别的recall很低首先别急着调模型结构先看看标注本身有没有问题。我去查证过某些转换版本里小目标框的中心坐标可能因为浮点精度丢失或者框太小归一化之后的w/h值接近0.001很多增强操作一下就把目标“洗”没了。一个实操性的调整是提高输入分辨率同时把mosaic增强保留并在训练时打开多尺度训练。如果还不行可以单独对小目标类别做过采样让模型多“看”几遍这种样本。4.5 数据集划分混乱验证集和训练集有重叠有些整理版压缩包没有划分好train/val/test或者某些图片既出现在训练集又出现在验证集这样训练出来的指标虚高换到新数据上效果就崩。好在标题里写了4840张一般train和val的划分是接近7:3或者8:2。你用之前先确认一下看两张图片的名字是否有重叠看train.txt和val.txt的图片列表是否有交集。如果划分不干净最好自己重新洗牌划分保证同一张大图切出来的几个块不要同时出现在训练集和验证集中否则会有数据泄漏。5. 从这份数据出发后续还能怎么做5.1 水平框版本升级成旋转框OBB训练完水平框模型后如果你发现目标紧邻密集场景下框的重叠很大比如港口里船挨着船、停车场里车挨着车水平框的“天花板”就会很明显。这时可以考虑上旋转框检测。原版DOTA的标注是四边形四角点格式如果要转成YOLOv8-OBB支持的格式需要把每个目标的四角点归一化坐标按顺序写入txt类别不变训练时用模型参数modelyolov8s-obb.pt。从水平框数据“升级”到旋转框最大的好处是能更精确统计目标数量和覆盖面积这在港口管理、航线规划、交通流量分析等场景非常有用。如果你只想在这份数据集上试可以先用Web标注工具把DOTA原版的旋转框转成YOLO-OBB格式。实际操作中因为DOTA原版每个目标有8个角点坐标转换脚本比VOC转YOLO复杂一些但逻辑是清晰的。5.2 迁移到自己的无人机/遥感项目这份数据集最值的部分不是用来刷榜而是作为预训练数据。我的建议是先用这份DOTA数据集训练一个基础模型再用你自己的无人机拍摄数据做fine-tune。因为遥感图像的域差距主要体现在传感器、分辨率和目标类别分布上但底层特征比如建筑的边缘、道路的纹理、车辆的轮廓是相通的。具体做法是用DOTA训练好的best.pt作为预训练权重而不是直接用COCO预训练权重。fine-tune时如果你的自定义类别数和16不一样把模型最后一层替换掉冻结backbone先训头10个epoch。解冻全部层用小学习率继续训练一般20到30个epoch就能收敛。我在一个城市车辆识别的项目里用DOTA的权重做初始化比直接用COCO权重初始化初期收敛速度快了接近30%最终mAP也高了3到5个点省了不少调参时间。5.3 切图、推理融合和部署落地如果你准备把这个模型接到无人机实时检测流程里建议先在推理阶段做切图策略而不是把整张大图直接塞给模型。我常用的做法是用小图块滑动窗口推理窗口大小和训练时的imgsz保持一致。相邻窗口之间留一定重叠比如10%到20%避免目标被拦腰截断。所有窗口的检测结果汇总后做一次全局NMS置信度阈值设低一点比如0.25把重复框抑制掉。部署到ONNX或者TensorRT时注意YOLOv8输出层的形状和坐标还原因为如果输入做了letterbox padding输出的坐标要按原图尺寸做等比例映射回来否则画框会偏移。这些细节在我用过的多个项目里都踩过写出来希望大家少走弯路。如果你手头正好拿到这份DOTAv2.0数据集我建议别急着无脑开训先花半小时检查数据格式、做可视化、确认类别映射再上训练。从我这些年的经验看目标检测项目里能让人熬夜的往往不是模型和算法而是脏乱差的数据。把这步做扎实了后面模型调起来会顺很多。本文还有配套的精品资源点击获取