从DIOR到YOLOv5遥感目标检测数据集转换实战指南遥感影像中的目标检测一直是计算机视觉领域的热点研究方向。DIOR作为当前主流的遥感数据集包含了20类常见地物目标但原始数据格式与YOLOv5的要求存在差异。本文将带你从零开始逐步完成数据格式转换、数据集划分以及目录结构调整的全过程并提供可直接运行的Python脚本。1. 理解DIOR数据集的结构与挑战初次接触DIOR数据集的研究者常会遇到几个典型问题为什么下载的数据集不能直接用于YOLOv5训练水平框和旋转框有什么区别如何正确处理XML标注文件让我们先剖析DIOR的原始结构。数据集通常包含以下关键文件夹Annotations存放XML格式的标注文件Horizontal Bounding Boxes水平矩形框标注Oriented Bounding Boxes旋转矩形框标注JPEGImages-test测试集图像约20%数据JPEGImages-trainval训练验证集图像约80%数据注意YOLOv5要求标注为TXT格式每行表示一个对象格式为class_id x_center y_center width height其中坐标值需归一化到[0,1]区间。常见问题排查表问题现象可能原因解决方案脚本报错FileNotFoundError文件路径不正确检查XML和图像路径是否匹配训练时提示标签缺失目录结构不符合YOLOv5要求确保images和labels同级目录评估指标异常坐标归一化错误验证convert()函数计算逻辑2. 环境准备与数据整理在开始转换前我们需要做好以下准备工作# 创建项目目录结构 mkdir -p DIOR_dataset/{images,labels}/{train,val,test}首先合并分散的图像文件from shutil import copyfile import os # 合并训练验证集和测试集图像 def merge_images(src_folders, dst_folder): if not os.path.exists(dst_folder): os.makedirs(dst_folder) for folder in src_folders: for img in os.listdir(folder): copyfile(os.path.join(folder, img), os.path.join(dst_folder, img)) merge_images([JPEGImages-trainval, JPEGImages-test], JPEGImages)关键检查点确认JPEGImages文件夹包含全部图像通常约23,463张检查文件名一致性如12345.jpg对应12345.xml准备类别列表DIOR的20个类别需按固定顺序排列3. XML到YOLO格式的深度转换核心转换脚本包含以下几个关键函数def convert(size, box): 将边界框坐标转换为YOLO格式 dw, dh 1./size[0], 1./size[1] x (box[0] box[1])/2.0 - 1 y (box[2] box[3])/2.0 - 1 w box[1] - box[0] h box[3] - box[2] return x*dw, y*dh, w*dw, h*dh def process_annotation(xml_file, txt_file): 处理单个XML文件的转换 tree ET.parse(xml_file) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) with open(txt_file, w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) xmlbox obj.find(bndbox) b (float(xmlbox.find(xmin).text), float(xmlbox.find(xmax).text), float(xmlbox.find(ymin).text), float(xmlbox.find(ymax).text)) bb convert((w,h), b) f.write(f{cls_id} { .join([str(a) for a in bb])}\n)边界框处理中的常见陷阱坐标越界xmax 图像宽度无效标注面积为0的框类别名称不一致如airplane vs Airplane4. 数据集划分与结构调整按照6:2:2的比例划分数据集时需要注意# 随机划分数据集 total_files os.listdir(xml_path) random.shuffle(total_files) n len(total_files) train total_files[:int(0.6*n)] val total_files[int(0.6*n):int(0.8*n)] test total_files[int(0.8*n):]最终目录结构调整为YOLOv5标准格式DIOR_dataset/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/迁移文件的实用技巧# 使用os.rename替代shutil.move可避免跨设备问题 for split in [train, val, test]: os.makedirs(fDIOR_dataset/{split}/images, exist_okTrue) os.makedirs(fDIOR_dataset/{split}/labels, exist_okTrue) # 移动图像文件 for img in os.listdir(fDIOR_dataset/images/{split}): src fDIOR_dataset/images/{split}/{img} dst fDIOR_dataset/{split}/images/{img} os.rename(src, dst) # 移动标签文件同理5. 配置文件与验证测试创建data.yaml文件是最后关键一步# DIOR_dataset/data.yaml train: ../train/images val: ../val/images test: ../test/images nc: 20 names: [airplane, airport, baseballfield, basketballcourt, bridge, chimney, dam, Expressway-Service-area, Expressway-toll-station, golffield, groundtrackfield, harbor, overpass, ship, stadium, storagetank, tenniscourt, trainstation, vehicle, windmill]验证数据集完整性的方法import yaml from PIL import Image # 检查图像与标签匹配 def verify_dataset(cfg_path): with open(cfg_path) as f: data yaml.safe_load(f) for split in [train, val, test]: img_dir data[split] label_dir img_dir.replace(images, labels) for img in os.listdir(img_dir): base os.path.splitext(img)[0] assert os.path.exists(f{label_dir}/{base}.txt), \ fMissing label for {img} # 验证图像可正常加载 try: Image.open(f{img_dir}/{img}).verify() except: print(fCorrupted image: {img_dir}/{img})在实际项目中我遇到过因路径符号不一致导致的训练失败Windows反斜杠 vs Linux正斜杠。建议使用pathlib库处理路径它能自动适应不同操作系统from pathlib import Path img_path Path(DIOR_dataset) / train / images label_path img_path.parent / labels