news 2026/6/2 8:31:00

保姆级教程:用Python脚本一键搞定DIOR遥感数据集到YOLO格式的转换(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级教程:用Python脚本一键搞定DIOR遥感数据集到YOLO格式的转换(附完整代码)

从DIOR到YOLO:零基础实现遥感目标检测数据集的自动化转换

遥感影像中的目标检测一直是计算机视觉领域的热门研究方向,而DIOR数据集作为当前最全面的遥感目标检测基准之一,包含了20个类别的23463张图像。但对于刚接触YOLO系列模型的新手来说,如何将DIOR的XML标注格式转换为YOLO所需的TXT格式,往往成为第一个技术门槛。本文将提供一个完整、可复现的Python解决方案,不仅包含详细的代码解析,还会深入讲解每个步骤的原理和常见问题处理。

1. 环境准备与数据目录结构

在开始转换之前,我们需要确保拥有正确的数据结构和Python环境。DIOR数据集的原始目录通常如下所示:

DIOR/ ├── Annotations/ # 存放XML格式的标注文件 ├── JPEGImages/ # 存放原始图像文件 ├── ImageSets/ │ └── Main/ # 包含train.txt, val.txt, test.txt划分文件

第一步是将JPEGImages文件夹重命名为images(全小写),这是YOLO模型的默认要求。同时,我们需要创建一个新的labels文件夹来存放转换后的TXT标注文件。

# 在DIOR根目录下执行 mv JPEGImages images mkdir labels

Python环境需要安装以下基础库:

import xml.etree.ElementTree as ET import os from os import getcwd

这些库都是Python标准库的一部分,通常不需要额外安装。但如果你使用的是Miniconda或虚拟环境,建议创建一个新的环境:

conda create -n dior2yolo python=3.8 conda activate dior2yolo

2. 核心转换代码解析

转换脚本的核心逻辑可以分为三个部分:坐标转换、XML解析和文件组织。让我们深入分析每个部分的技术细节。

2.1 坐标转换原理

YOLO格式要求标注使用归一化的中心坐标和宽高(0-1之间),而DIOR的XML标注使用的是像素坐标下的左上角和右下角坐标。转换函数如下:

def convert(size, box): """将边界框从像素坐标转换为YOLO格式 Args: size: 图像的宽和高 (w, h) box: 边界框坐标 (xmin, xmax, ymin, ymax) Returns: 归一化的中心坐标和宽高 (x_center, y_center, w, h) """ dw = 1. / (size[0]) dh = 1. / (size[1]) x = (box[0] + box[1]) / 2.0 - 1 # 计算中心x坐标 y = (box[2] + box[3]) / 2.0 - 1 # 计算中心y坐标 w = box[1] - box[0] # 计算宽度 h = box[3] - box[2] # 计算高度 x = x * dw # 归一化x坐标 w = w * dw # 归一化宽度 y = y * dh # 归一化y坐标 h = h * dh # 归一化高度 return x, y, w, h

注意:YOLO的坐标归一化是基于图像尺寸的,这意味着无论原始图像分辨率如何,转换后的坐标都在0-1范围内,这使得YOLO模型能够处理不同尺寸的输入图像。

2.2 XML解析与标注处理

DIOR的XML文件包含了丰富的标注信息,我们需要从中提取出类别和边界框数据:

def convert_annotation(image_id): in_file = open(f'{datasetpath}/Annotations/{image_id}.xml', encoding='UTF-8') out_file = open(f'{datasetpath}/labels/{image_id}.txt', 'w') tree = ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): cls = obj.find('name').text if cls not in classes: continue # 跳过不在类别列表中的对象 cls_id = classes.index(cls) # 获取类别ID 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)) # 边界越界检查 b = list(b) if b[1] > w: b[1] = w if b[3] > h: b[3] = h b = tuple(b) bb = convert((w, h), b) out_file.write(f"{cls_id} {' '.join([str(a) for a in bb])}\n")

提示:DIOR数据集中的某些标注可能存在边界越界问题(即标注框超出图像范围),上述代码包含了自动修正机制,确保转换后的标注不会出现非法值。

3. 完整脚本与路径配置

将各个部分组合起来,我们得到完整的转换脚本。以下是带有详细注释的版本:

#!/usr/bin/env python # -*- coding: utf-8 -*- import xml.etree.ElementTree as ET import os from os import getcwd # 数据集划分:训练集、验证集、测试集 sets = ['train', 'val', 'test'] # DIOR数据集的20个类别 classes = ['airplane', 'airport', 'baseballfield', 'basketballcourt', 'bridge', 'chimney', 'dam', 'Expressway-Service-area', 'Expressway-toll-station', 'golffield', 'groundtrackfield', 'harbor', 'overpass', 'ship', 'stadium', 'storagetank', 'tenniscourt', 'trainstation', 'vehicle', 'windmill'] # 配置你的路径 ----------------------------- datasetpath = "E:/dataset/DIOR" # DIOR数据集根目录 imgpath = "E:/dataset/DIOR/images" # 图像文件夹路径 outpath = "E:/dataset/DIOR/myyolo" # 输出路径 # 确保输出目录存在 os.makedirs(outpath, exist_ok=True) # 转换主循环 for image_set in sets: # 创建labels目录(如果不存在) os.makedirs(f'{datasetpath}/labels', exist_ok=True) # 读取划分文件中的图像ID列表 with open(f'{datasetpath}/ImageSets/Main/{image_set}.txt') as f: image_ids = f.read().strip().split() # 创建输出文件(包含图像绝对路径) with open(f'{outpath}/{image_set}.txt', 'w') as list_file: for image_id in image_ids: # 写入图像绝对路径 list_file.write(f'{imgpath}/{image_id}.jpg\n') # 转换对应的标注文件 convert_annotation(image_id)

4. 创建YOLO配置文件与常见问题排查

转换完成后,我们需要创建一个YAML配置文件供YOLO模型训练使用:

# DIOR.yaml train: E:/dataset/DIOR/myyolo/train.txt val: E:/dataset/DIOR/myyolo/val.txt test: E:/dataset/DIOR/myyolo/test.txt # 可选 # 类别数量 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']

常见问题及解决方案:

  1. 文件夹命名错误

    • 症状:报错"No labels in xx./train.cache"
    • 原因:YOLO严格要求images和labels的文件夹名称
    • 解决:确保图像文件夹名为"images",标注文件夹名为"labels"
  2. 路径问题

    • 症状:FileNotFoundError或空输出
    • 检查:所有路径是否正确,特别是Windows下的反斜杠需要转义或使用原始字符串
  3. 标注越界

    • 症状:训练时出现"invalid bbox"警告
    • 解决:脚本中已包含越界检查,但仍建议可视化检查部分样本
  4. 类别ID不匹配

    • 症状:训练时类别预测混乱
    • 检查:确保YAML文件中的names顺序与转换脚本中的classes列表完全一致

5. 验证转换结果

为了确保转换正确,我们可以使用以下代码可视化检查几个样本:

import cv2 import random def plot_yolo_bbox(img_path, label_path, classes): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: lines = f.readlines() for line in lines: cls_id, xc, yc, bw, bh = map(float, line.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) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, classes[int(cls_id)], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.imshow('Preview', img) cv2.waitKey(0) cv2.destroyAllWindows() # 随机检查几个样本 sample_ids = random.sample(image_ids, 3) for img_id in sample_ids: img_path = f'{imgpath}/{img_id}.jpg' label_path = f'{datasetpath}/labels/{img_id}.txt' plot_yolo_bbox(img_path, label_path, classes)

这个可视化脚本可以帮助我们直观地确认标注转换是否正确,特别是边界框的位置和类别标签是否匹配。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 8:19:57

竞争定价智能:从数据采集到AI决策的完整实战指南

1. 从“自我感觉良好”到“市场真相”:为什么你的好生意可能只是幻觉每年利润报表看起来都挺漂亮,客户满意度调查也一片祥和,你可能会觉得自己的公司正行驶在一条稳健增长的轨道上。假设你每年能稳定赚取X百万的利润,这感觉确实不…

作者头像 李华
网站建设 2026/6/2 8:14:12

SAP S4 HANA供应商主数据BP屏幕增强实战:手把手教你给LFA1表加自定义字段

SAP S4 HANA供应商主数据BP屏幕增强实战:从表结构到UI集成的完整指南 在SAP S4 HANA项目实施过程中,供应商主数据的个性化扩展几乎是每个企业都会遇到的刚性需求。标准LFA1表提供的字段往往无法满足企业特有的业务场景——比如需要记录供应商的付款条件偏…

作者头像 李华