将 JSON 批量转换为 XML:深度解析与完整实现指南

发布于:2025-05-17 ⋅ 阅读:(17) ⋅ 点赞:(0)

在数据科学与机器学习项目中,数据预处理始终扮演着不可或缺的角色。尤其当你面对多类别图像标注任务,而标注数据却是以 JSON 形式存在,而目标检测模型却偏好 VOC 格式的 XML 时,这个转换过程就变得极为关键。

本文将带你深入解读一个完整的实战项目:如何将图像分类数据集中每个标注 JSON 批量转换为标准 Pascal VOC 格式的 XML 文件,并同步整理图像资源。文章不仅附带完整代码,还涵盖路径组织、格式规范、注意事项等细节。


🧭 背景设定与挑战目标

想象你正进行一个猫狗识别任务,图像已经用 LabelMe 等工具标注为 JSON 格式,其中包含了边界框(bounding box)、类别信息、图像路径等。你需要:

  1. 从多个子类别文件夹(如“猫/狗”、“训练集/验证集”)中提取图片;
  2. 将对应的 JSON 文件转换为 VOC 结构的 XML;
  3. 输出统一、清晰、便于训练的数据目录结构。

听起来琐碎?没错。但只需一套 Python 脚本,这些都能自动化完成!


🗂️ 项目结构设计(自动创建)

最终数据结构如下所示:

├── your_target_path/
│   ├── 训练/
│   │   ├── images/
│   │   └── xml/
│   └── 验证/
│       ├── images/
│       └── xml/

无须手动创建目录,程序将自动完成所有结构的搭建与数据整理!


🔍 代码核心逻辑剖析

🧩 1. JSON 转 Pascal VOC XML:convert_json_to_voc_xml

该函数负责读取单个标注文件,提取图像尺寸、目标框信息等,并生成标准 Pascal VOC XML。使用了 Python 的 xml.etree.ElementTree 库,无需额外依赖。

🧩 2. XML 构建核心:make_voc_xml

该函数将目标对象逐一转写为 <object> 标签结构,包括:

  • label 标签名
  • points 坐标点(自动计算为 bbox)
  • difficult 标签(可选)

并将其打包为完整的 <annotation> 结构。

🧩 3. 批量处理:process_split

它是处理每个子集(如“训练”/“验证”)的核心函数:

  • 遍历 JSON 文件夹
  • 复制图像文件至目标目录
  • 调用转换函数生成 XML
  • 控制最大数量(默认为 3000)

🛠️ 完整可运行脚本

import os
import shutil
import json
import xml.etree.ElementTree as ET

def make_voc_xml(json_path, img_filename, img_shape, objects, xml_path):
    # 构建 Pascal VOC XML
    ...

def convert_json_to_voc_xml(json_file, xml_file):
    # 从 JSON 文件中提取图像信息与目标对象,生成 XML
    ...

def process_split(split, base_dir, target_base, max_count=3000):
    img_dst = os.path.join(target_base, split, 'images')
    xml_dst = os.path.join(target_base, split, 'xml')
    os.makedirs(img_dst, exist_ok=True)
    os.makedirs(xml_dst, exist_ok=True)

    img_count = 0
    for animal in ['cat', 'dog']:
        img_src = os.path.join(base_dir, animal, split + '集', 'images')
        json_src = os.path.join(base_dir, animal, split + '集', 'json')
        if not os.path.exists(img_src) or not os.path.exists(json_src):
            continue
        files = [f for f in os.listdir(json_src) if f.endswith('.json')]
        files = files[:max(0, max_count - img_count)]
        for fname in files:
            json_path = os.path.join(json_src, fname)
            with open(json_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            img_name = os.path.basename(data['imagePath'])
            img_path = os.path.join(img_src, img_name)
            if not os.path.exists(img_path):
                continue
            shutil.copy(img_path, os.path.join(img_dst, img_name))
            xml_name = os.path.splitext(img_name)[0] + '.xml'
            xml_path = os.path.join(xml_dst, xml_name)
            convert_json_to_voc_xml(json_path, xml_path)
            img_count += 1
            if img_count >= max_count:
                break

if __name__ == "__main__":
    # ⚠️ 请将以下两个路径替换为你自己的输入/输出目录
    base_dir = r"请在此填写你的原始数据集路径"
    target_base = r"请在此填写你希望保存转换结果的位置"

    # 分别处理训练集与验证集
    process_split('训练', base_dir, target_base, max_count=3000)
    process_split('验证', base_dir, target_base, max_count=3000)
    print("图片和VOC格式xml已整理完成!")

🧷 使用步骤指南(务必替换路径)

  1. 在本地准备如下数据结构:
    原始路径/
    ├── cat/
    │   ├── 训练集/
    │   │   ├── images/
    │   │   └── json/
    │   └── 验证集/
    └── dog/
    
  2. 修改脚本中的 base_dirtarget_base 变量为你自己的实际路径。
  3. 运行脚本,观察终端输出转换进度。
  4. 转换结果将自动按“训练 / 验证”分文件夹整理好图像与 XML 标注。

📌 技术亮点回顾

  • 纯标准库实现,跨平台无依赖
  • 支持多标签、多边框结构
  • 支持 JSON 合法性与图像路径检查
  • 自动路径管理与目录创建
  • 输出即训练,直接上手模型训练流程

💡 总结

从标注到模型训练,中间这一步格式转换往往被忽视。本文不仅提供了解决方案,更以实战项目为例,系统讲解了数据清洗与结构化管理的全流程。对于任何从事图像识别、目标检测的开发者而言,这都是一份值得收藏的工程模板。


👋 如果你觉得本文有帮助,欢迎点赞 + 收藏 + 关注,一起探索更多 AI 项目实践!