XML转YOLO格式数据集教程

准备工作:

确保你有一个包含所有 .xml 文件的文件夹。

明确你的数据集包含哪些类别(Classes),并按顺序填入代码中。

Python 转换脚本(XML转YOLO格式)

bash 复制代码
import xml.etree.ElementTree as ET
import glob
import os

# ================= 配置区域 =================
# 1. 这里填入xml文件所在的文件夹路径
xml_dir = './xml_data/' 

# 2. 这里填入输出txt文件的文件夹路径(会自动创建)
save_dir = './yolo_txt_data/'

# 3. 【关键】修改为你的数据集类别名称,必须与xml里的<name>标签一致
# 注意:列表的顺序决定了YOLO的类别索引(0, 1, 2...)
classes = ['cat', 'dog', 'person'] 

# ===========================================

def convert(size, box):
    """
    将 bbox (xmin, ymin, xmax, ymax) 转换为 yolo (x, y, w, h)
    size: (width, height) 图像的宽和高
    box: (xmin, xmax, ymin, ymax)
    """
    dw = 1.0 / size[0]
    dh = 1.0 / size[1]
    
    # 计算中心点和宽高
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    
    # 归一化
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)

def convert_annotation(xml_file):
    in_file = open(xml_file, encoding='utf-8')
    tree = ET.parse(in_file)
    root = tree.getroot()
    
    # 获取图片尺寸
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    # 准备输出文件名
    filename = os.path.basename(xml_file)[:-4]
    out_file = open(os.path.join(save_dir, filename + '.txt'), 'w', encoding='utf-8')

    for obj in root.iter('object'):
        difficult = obj.find('difficult')
        cls = obj.find('name').text
        
        # 如果xml里标记为difficult且你想忽略,可以取消注释下面这行
        # if difficult and int(difficult.text) == 1: continue
        
        if cls not in classes:
            continue
            
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        
        # 解析 VOC 坐标
        b = (float(xmlbox.find('xmin').text), 
             float(xmlbox.find('xmax').text), 
             float(xmlbox.find('ymin').text), 
             float(xmlbox.find('ymax').text))
        
        # 转换为 YOLO 格式
        bb = convert((w, h), b)
        
        # 写入文件: class_id x_center y_center width height
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
        
    in_file.close()
    out_file.close()

if __name__ == '__main__':
    # 创建输出文件夹
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    # 获取所有xml文件列表
    xml_files = glob.glob(os.path.join(xml_dir, '*.xml'))
    
    print(f"找到 {len(xml_files)} 个XML文件,开始转换...")
    
    for xml_file in xml_files:
        convert_annotation(xml_file)
        
    print(f"转换完成!文件已保存在 {save_dir}")
    print("记得生成 classes.txt 文件,内容如下:")
    for c in classes:
        print(c)

修改如下所示

运行结果

可视化转换后的YOLO格式数据(在图片上画框)

这个脚本会自动读取图片和它对应的 YOLO 格式 .txt 文件,逆向计算回绝对坐标,并在图片上画出框和类别名称。如果画出来的框精准地贴合目标,说明你的转换是成功的。

运行后会弹出一个窗口(按任意键切换下一张图片,按q键退出程序 ):
位置准确性 :检查框是否严丝合缝地包围了物体。如果框发生了整体偏移或者大小不对(比如框比物体大很多,或者只有物体的一半),说明之前的转换公式或者图片宽高读取有问题。
类别正确性 :看框上的文字标签(如 cat)是否和图片里的物体对应。如果狗被标成了猫,说明 classes 列表的顺序填错了。
YOLO 格式校验/可视化脚本

bash 复制代码
import cv2
import os
import random
import glob

# ================= 配置区域 =================

# 1. 图片所在的文件夹路径 (注意是文件夹)
img_dir = r'E:\GC10-DET\images' 

# 2. txt标签所在的文件夹路径 (注意是文件夹)
# 如果图片和txt在同一个文件夹,这里就填一样的路径
txt_dir = r'E:\GC10-DET\labels'

# 3. 你的数据集类别 (GC10-DET通常包含10类,请根据你的classes.txt填写)
# 示例类别,请替换为你自己的:
classes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 

# ===========================================

def check_random_sample():
    # 支持的图片格式
    img_formats = ['*.jpg', '*.jpeg', '*.png', '*.bmp']
    images = []
    for fmt in img_formats:
        images.extend(glob.glob(os.path.join(img_dir, fmt)))
    
    if len(images) == 0:
        print(f"错误:在 {img_dir} 下没找到任何图片!")
        return

    # 随机选一张图片
    img_path = random.choice(images)
    print(f"正在检查图片: {img_path}")
    
    # 推导对应的txt路径
    # 获取文件名(不带后缀),例如 'img_01'
    basename = os.path.basename(img_path).rsplit('.', 1)[0]
    txt_path = os.path.join(txt_dir, basename + ".txt")
    
    if not os.path.exists(txt_path):
        print(f"错误:找不到对应的标签文件: {txt_path}")
        print("请检查:\n1. txt文件是否在指定目录下?\n2. txt文件名是否与图片一致?")
        return

    # === 开始可视化 ===
    img = cv2.imread(img_path)
    if img is None:
        print("图片文件损坏,无法读取")
        return
        
    h, w, _ = img.shape
    print(f"图片尺寸: {w}x{h}")

    with open(txt_path, 'r') as f:
        lines = f.readlines()
        
    if not lines:
        print("警告:该图片对应的txt文件是空的(即没有标注目标)")

    # 生成随机颜色
    colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(classes) + 10)]

    for line in lines:
        parts = line.strip().split()
        if len(parts) != 5: continue
        
        cls_idx = int(parts[0])
        cx, cy, bw, bh = map(float, parts[1:])
        
        # 反归一化坐标
        x_center = cx * w
        y_center = cy * h
        width = bw * w
        height = bh * h
        
        x_min = int(x_center - width / 2)
        y_min = int(y_center - height / 2)
        x_max = int(x_center + width / 2)
        y_max = int(y_center + height / 2)
        
        # 获取类别名
        label_name = classes[cls_idx] if cls_idx < len(classes) else f"Class {cls_idx}"
        color = colors[cls_idx]

        # 画框
        cv2.rectangle(img, (x_min, y_min), (x_max, y_max), color, 2)
        # 画标签
        cv2.putText(img, label_name, (x_min, y_min - 5), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
        
        print(f"  -> 类别: {label_name} | 坐标: {x_min},{y_min},{x_max},{y_max}")

    # 显示 (按任意键查看下一张,按 'q' 退出)
    window_name = 'Press Any Key for Next, Q to Quit'
    cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) # 允许调整窗口大小
    cv2.resizeWindow(window_name, 1024, 768) # 防止图片过大占满屏幕
    cv2.imshow(window_name, img)
    
    key = cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    # 如果没按q,就递归调用自己再看一张
    if key != ord('q'):
        check_random_sample()

if __name__ == '__main__':
    check_random_sample()

我的修改,按照自己的路径去进行修改

运行结果

相关推荐
yunhuibin1 小时前
yolov8通过百度飞桨AIstudio平台搭建
yolo·百度·paddlepaddle
橙序员小站1 小时前
Java 接入Pinecone搭建知识库踩坑实记
java·开发语言·人工智能
楚兴1 小时前
使用 Eino 和 Ollama 构建智能 Go 应用:从简单问答到复杂 Agent
人工智能·后端
Love__Tay1 小时前
使用Upsonic实现金融合规任务自动化:技术实践与思考
人工智能·金融·自动化
腾飞开源1 小时前
23_Spring AI 干货笔记之 NVIDIA 聊天
人工智能·nvidia·spring ai·聊天模型·llm api·openai客户端·配置属性
智链RFID1 小时前
RFID资产管理系统:智能管理新利器
大数据·人工智能
DatGuy1 小时前
Week 28: 机器学习补遗:MoE 原理与时序路由策略
人工智能·机器学习
roman_日积跬步-终至千里1 小时前
【计算机视觉(5)】特征检测与匹配基础篇:从Harris到SIFT的完整流程
人工智能·深度学习·计算机视觉
工藤学编程1 小时前
零基础学AI大模型之相似度Search与MMR最大边界相关搜索实战
人工智能