python将labelme标注的json数据转换为labelImg标注的xml格式

创建一个文件夹命名json_to_xml,文件夹内共有三个py文件,分别是create_xml_anno.py,main.py,read_json_anno.py,如下所示:
在这里插入图片描述
输入:由labelme的rectangle或polygon方式标注生成的json文件,如下所示:
在这里插入图片描述
json文件内容形式如下:
在这里插入图片描述
输出:类似于labelImg的rectangle方式标注生成的xml文件,是左上角和右下角的坐标,如下所示:
在这里插入图片描述
转换后的xml文件内容形式如下:
在这里插入图片描述
create_xml_anno.py

# -*- coding: utf-8 -*-
from xml.dom.minidom import Document
 
class CreateAnno:
    def __init__(self,):
        self.doc = Document()  # 创建DOM文档对象
        self.anno = self.doc.createElement('annotation')  # 创建根元素
        self.doc.appendChild(self.anno)
 
        self.add_folder()
        self.add_path()
        self.add_source()
        self.add_segmented()
 
        # self.add_filename()
        # self.add_pic_size(width_text_str=str(width), height_text_str=str(height), depth_text_str=str(depth))
 
    def add_folder(self, floder_text_str='JPEGImages'):
        floder = self.doc.createElement('floder')  ##建立自己的开头
        floder_text = self.doc.createTextNode(floder_text_str)  ##建立自己的文本信息
        floder.appendChild(floder_text)  ##自己的内容
        self.anno.appendChild(floder)
 
    def add_filename(self, filename_text_str='00000.jpg'):
        filename = self.doc.createElement('filename')
        filename_text = self.doc.createTextNode(filename_text_str)
        filename.appendChild(filename_text)
        self.anno.appendChild(filename)
 
    def add_path(self, path_text_str="None"):
        path = self.doc.createElement('path')
        path_text = self.doc.createTextNode(path_text_str)
        path.appendChild(path_text)
        self.anno.appendChild(path)
 
    def add_source(self, database_text_str="Unknow"):
        source = self.doc.createElement('source')
        database = self.doc.createElement('database')
        database_text = self.doc.createTextNode(database_text_str)  # 元素内容写入
        database.appendChild(database_text)
        source.appendChild(database)
        self.anno.appendChild(source)
 
    def add_pic_size(self, width_text_str="0", height_text_str="0", depth_text_str="3"):
        size = self.doc.createElement('size')
        width = self.doc.createElement('width')
        width_text = self.doc.createTextNode(width_text_str)  # 元素内容写入
        width.appendChild(width_text)
        size.appendChild(width)
 
        height = self.doc.createElement('height')
        height_text = self.doc.createTextNode(height_text_str)
        height.appendChild(height_text)
        size.appendChild(height)
 
        depth = self.doc.createElement('depth')
        depth_text = self.doc.createTextNode(depth_text_str)
        depth.appendChild(depth_text)
        size.appendChild(depth)
 
        self.anno.appendChild(size)
 
    def add_segmented(self, segmented_text_str="0"):
        segmented = self.doc.createElement('segmented')
        segmented_text = self.doc.createTextNode(segmented_text_str)
        segmented.appendChild(segmented_text)
        self.anno.appendChild(segmented)
 
    def add_object(self,
                   name_text_str="None",
                   xmin_text_str="0",
                   ymin_text_str="0",
                   xmax_text_str="0",
                   ymax_text_str="0",
                   pose_text_str="Unspecified",
                   truncated_text_str="0",
                   difficult_text_str="0"):
        object = self.doc.createElement('object')
        name = self.doc.createElement('name')
        name_text = self.doc.createTextNode(name_text_str)
        name.appendChild(name_text)
        object.appendChild(name)
 
        pose = self.doc.createElement('pose')
        pose_text = self.doc.createTextNode(pose_text_str)
        pose.appendChild(pose_text)
        object.appendChild(pose)
 
        truncated = self.doc.createElement('truncated')
        truncated_text = self.doc.createTextNode(truncated_text_str)
        truncated.appendChild(truncated_text)
        object.appendChild(truncated)
 
        difficult = self.doc.createElement('Difficult')
        difficult_text = self.doc.createTextNode(difficult_text_str)
        difficult.appendChild(difficult_text)
        object.appendChild(difficult)
 
        bndbox = self.doc.createElement('bndbox')
        xmin = self.doc.createElement('xmin')
        xmin_text = self.doc.createTextNode(xmin_text_str)
        xmin.appendChild(xmin_text)
        bndbox.appendChild(xmin)
 
        ymin = self.doc.createElement('ymin')
        ymin_text = self.doc.createTextNode(ymin_text_str)
        ymin.appendChild(ymin_text)
        bndbox.appendChild(ymin)
 
        xmax = self.doc.createElement('xmax')
        xmax_text = self.doc.createTextNode(xmax_text_str)
        xmax.appendChild(xmax_text)
        bndbox.appendChild(xmax)
 
        ymax = self.doc.createElement('ymax')
        ymax_text = self.doc.createTextNode(ymax_text_str)
        ymax.appendChild(ymax_text)
        bndbox.appendChild(ymax)
        object.appendChild(bndbox)
 
        self.anno.appendChild(object)
 
    def get_anno(self):
        return self.anno
 
    def get_doc(self):
        return self.doc
 
    def save_doc(self, save_path):
        with open(save_path, "w") as f:
            self.doc.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')

read_json_anno.py

# -*- coding: utf-8 -*-
import numpy as np
import json

class ReadAnno:
    def __init__(self, json_path, process_mode="rectangle"):
        with open(json_path,'r',encoding='gb18030')as fp:
            self.json_data = json.load(fp)
            #self.json_data = json.load(open(json_path))
        self.filename = self.json_data['imagePath']
        self.width = self.json_data['imageWidth']
        self.height = self.json_data['imageHeight']
 
        self.coordis = []
        assert process_mode in ["rectangle", "polygon"]
        if process_mode == "rectangle":
            self.process_polygon_shapes()
        elif process_mode == "polygon":
            self.process_polygon_shapes()
 
    def process_rectangle_shapes(self):
        for single_shape in self.json_data['shapes']:
            bbox_class = single_shape['label']
            xmin = single_shape['points'][0][0]
            ymin = single_shape['points'][0][1]
            xmax = single_shape['points'][1][0]
            ymax = single_shape['points'][1][1]
            self.coordis.append([xmin,ymin,xmax,ymax,bbox_class])
 
    def process_polygon_shapes(self):
        for single_shape in self.json_data['shapes']:
            bbox_class = single_shape['label']
            temp_points = []
            for couple_point in single_shape['points']:
                x = float(couple_point[0])
                y = float(couple_point[1])
                temp_points.append([x,y])
            temp_points = np.array(temp_points)
            xmin, ymin = temp_points.min(axis=0)
            xmax, ymax = temp_points.max(axis=0)
            self.coordis.append([xmin,ymin,xmax,ymax,bbox_class])
 
    def get_width_height(self):
        return self.width, self.height
 
    def get_filename(self):
        return self.filename
 
    def get_coordis(self):
        return self.coordis

其中有2种模式,一种rectangle,表示json文件是通过labelme的rectangle方式标注,一种polygon,表示json文件是通过labelme的polygon方式标注。根据实际情况进行变换。

main.py
三个重要参数:json所在的文件夹,将要保存的xml文件夹,原数据的标注方式。

import os
from tqdm import tqdm
 
from read_json_anno import ReadAnno
from create_xml_anno import CreateAnno

def json_transform_xml(json_path, xml_path,imagePath, process_mode="rectangle"):
    json_path = json_path
    print(json_path)
    json_anno = ReadAnno(json_path, process_mode=process_mode)
    width, height = json_anno.get_width_height()
    filename = json_anno.get_filename()
    coordis = json_anno.get_coordis()
 
    xml_anno = CreateAnno()
    xml_anno.add_filename(imagePath)
    xml_anno.add_pic_size(width_text_str=str(width), height_text_str=str(height), depth_text_str=str(3))
    for xmin,ymin,xmax,ymax,label in coordis:
        if((xmax-xmin)<(width*2/3)):
            # xml_anno.add_object(name_text_str=str("text"),
            xml_anno.add_object(name_text_str=str(label),
                                xmin_text_str=str(int(xmin)),
                                ymin_text_str=str(int(ymin)),
                                xmax_text_str=str(int(xmax)),
                                ymax_text_str=str(int(ymax)))
 
    xml_anno.save_doc(xml_path)
 
if __name__ == "__main__":
    root_json_dir = "E:/PycharmProjects/modify_json/json"     # json文件夹路径
    root_save_xml_dir = "E:/PycharmProjects/modify_json/xml"  # 转换后保存的xml文件夹路径

    for json_filename in tqdm(os.listdir(root_json_dir)):
        json_path = os.path.join(root_json_dir, json_filename)
        save_xml_path = os.path.join(root_save_xml_dir, json_filename.replace(".json", ".xml"))
        filepath, tmpfilename = os.path.split(json_filename)
        shotname, extension = os.path.splitext(tmpfilename)
        img_path=shotname+".jpg"
        json_transform_xml(json_path, save_xml_path,img_path, process_mode="polygon")
        # json_transform_xml(json_path, save_xml_path, process_mode="polygon")

使用时,只需修改main.py中json文件和xml文件的路径,然后运行main.py文件即可。

  • 19
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
好的,您可以使用以下代码实现: ```python import os import json import xml.etree.ElementTree as ET # 定义标签和颜色 LABELS = {'circle': 0} COLORS = {'circle': '0,255,0'} # 定义json文件路径和xml文件路径 json_dir = '/path/to/json/dir' xml_dir = '/path/to/xml/dir' # 遍历json文件夹中的所有文件 for json_file in os.listdir(json_dir): # 如果不是json文件,则跳过 if not json_file.endswith('.json'): continue # 读取json文件内容 with open(os.path.join(json_dir, json_file), 'r') as f: data = json.load(f) # 获取文件名(去掉扩展名) filename = os.path.splitext(json_file)[0] # 创建xml文件 root = ET.Element('annotation') # 添加filename元素 ET.SubElement(root, 'filename').text = filename + '.jpg' # 添加size元素 size = ET.SubElement(root, 'size') ET.SubElement(size, 'width').text = str(data['imageWidth']) ET.SubElement(size, 'height').text = str(data['imageHeight']) ET.SubElement(size, 'depth').text = '3' # 遍历shapes for shape in data['shapes']: label = shape['label'] if label not in LABELS: continue # 添加object元素 obj = ET.SubElement(root, 'object') ET.SubElement(obj, 'name').text = label ET.SubElement(obj, 'pose').text = 'Unspecified' ET.SubElement(obj, 'truncated').text = '0' ET.SubElement(obj, 'difficult').text = '0' # 添加bndbox元素 bndbox = ET.SubElement(obj, 'bndbox') if shape['shape_type'] == 'circle': # 如果是圆形,获取外切矩形 x, y = shape['points'][0] r = shape['points'][1][0] - x ET.SubElement(bndbox, 'xmin').text = str(round(x - r)) ET.SubElement(bndbox, 'ymin').text = str(round(y - r)) ET.SubElement(bndbox, 'xmax').text = str(round(x + r)) ET.SubElement(bndbox, 'ymax').text = str(round(y + r)) else: # 否则,获取矩形 x1, y1 = shape['points'][0] x2, y2 = shape['points'][1] ET.SubElement(bndbox, 'xmin').text = str(round(min(x1, x2))) ET.SubElement(bndbox, 'ymin').text = str(round(min(y1, y2))) ET.SubElement(bndbox, 'xmax').text = str(round(max(x1, x2))) ET.SubElement(bndbox, 'ymax').text = str(round(max(y1, y2))) # 添加difficult元素 ET.SubElement(obj, 'difficult').text = '0' # 添加bndbox颜色 ET.SubElement(obj, 'color').text = COLORS[label] # 保存xml文件 xml_file = os.path.join(xml_dir, filename + '.xml') tree = ET.ElementTree(root) tree.write(xml_file) ``` 这段代码会将指定文件夹中的所有json文件转换xml文件,并将xml文件保存到指定文件夹中。处理圆形标注时,会将圆形转换为外切矩形。同时,会为每个标注添加颜色信息,以便在标注时更加直观。
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值