xml格式数据转coco格式,并与另一份coco格式数据集合并

coco格式数据集A:image6671张,一个coco格式的json文件:instance_train.json,四个类别

xml格式数据集B:image文件夹下图片9000张,box文件夹里xml标注文件9000个,与A一样的四个类别

任务:B转化为coco格式,并与A合并

1、如果只需求B转coco格式,不考虑合并,如下:

import os
import cv2
import json
import xml.dom.minidom
import xml.etree.ElementTree as ET

data_dir = 'D:\\goole\\forUser_A\\train'  # 根目录文件,其中包含image文件夹和box文件夹(根据自己的情况修改这个路径)

image_file_dir = os.path.join(data_dir, 'image')
#print(image_file_dir)

xml_file_dir = os.path.join(data_dir, 'box')

annotations_info = {'images': [], 'annotations': [], 'categories': []}

categories_map = {'holothurian': 1, 'echinus': 2, 'scallop': 3, 'starfish': 4}

for key in categories_map:
    categoriy_info = {"id": categories_map[key], "name": key}
    annotations_info['categories'].append(categoriy_info)

all_file_names = [image_file_name.split('.')[0]
              for image_file_name in os.listdir(image_file_dir)]

all_file_names.sort(key=lambda x: int(x.split('.')[0]))
#print(os.listdir(image_file_dir))
print(all_file_names)

ann_id = 1
for i, file_name in enumerate(all_file_names):

    image_file_name = file_name + '.jpg'
    xml_file_name = file_name + '.xml'
    image_file_path = os.path.join(image_file_dir, image_file_name)
    xml_file_path = os.path.join(xml_file_dir, xml_file_name)

    image_info = dict()
    image = cv2.cvtColor(cv2.imread(image_file_path), cv2.COLOR_BGR2RGB)
    height, width, _ = image.shape
    image_info = {'file_name': image_file_name, 'id': i + 1,
                  'height': height, 'width': width}
    annotations_info['images'].append(image_info)

    DOMTree = xml.dom.minidom.parse(xml_file_path)
    collection = DOMTree.documentElement

    names = collection.getElementsByTagName('name')
    names = [name.firstChild.data for name in names]

    xmins = collection.getElementsByTagName('xmin')
    xmins = [xmin.firstChild.data for xmin in xmins]
    ymins = collection.getElementsByTagName('ymin')
    ymins = [ymin.firstChild.data for ymin in ymins]
    xmaxs = collection.getElementsByTagName('xmax')
    xmaxs = [xmax.firstChild.data for xmax in xmaxs]
    ymaxs = collection.getElementsByTagName('ymax')
    ymaxs = [ymax.firstChild.data for ymax in ymaxs]

    object_num = len(names)

    for j in range(object_num):
        if names[j] in categories_map:
            image_id = i + 1
            x1, y1, x2, y2 = int(xmins[j]), int(ymins[j]), int(xmaxs[j]), int(ymaxs[j])
            x1, y1, x2, y2 = x1 - 1, y1 - 1, x2 - 1, y2 - 1

            if x2 == width:
                x2 -= 1
            if y2 == height:
                y2 -= 1

            x, y = x1, y1
            w, h = x2 - x1 + 1, y2 - y1 + 1
            category_id = categories_map[names[j]]
            area = w * h
            annotation_info = {"id": ann_id, "image_id": image_id, "bbox": [x, y, w, h], "category_id": category_id,
                               "area": area, "iscrowd": 0}
            annotations_info['annotations'].append(annotation_info)
            ann_id += 1

with  open('./annotations.json', 'w')  as f:
    json.dump(annotations_info, f, indent=4)

print('---整理后的标注文件---')
print('所有图片的数量:', len(annotations_info['images']))
print('所有标注的数量:', len(annotations_info['annotations']))
print('所有类别的数量:', len(annotations_info['categories']))

2、B转化为coco格式,并与A合并

(1)先通过另外的脚本先把B中image文件夹的9000张图片按6672.......15671重新命名,xml文件夹亦是如此,脚本文件如下:

#-----------------------------批量重命名图片------------------------------------
#-----------重命名《图片》《xml文件》《任何格式的文件》都可以自定义序号来命名------------
import os
'''
该路径存储原始的图片,重命名后会覆盖掉原始的图片,所以在重命名之前选择复制一份,以免被失误重命名
建议在路径中使用:\\ 双斜杠
'''
path = 'D:\\goole\\forUser_A\\train\\box'
# 绝对路径
filelist = os.listdir(path)
'''
起始数字,重命名的第一个文件的名字会加1
'''
i =6671
# 仅用于数字开头的图片命名方法
for item in filelist:
        #print('item name is ',item)
        # jpg\png\bmp\xml  任何格式都支持,但是需要手动修改格式类型
        if item.endswith('.xml'):
                i = i + 1
                # 第一张图片命名为1.png
                name = str(i)
                # 将数字转换为字符串才能命名
                src = os.path.join(os.path.abspath(path),item)
                # 原始图像的路径
                dst = os.path.join(os.path.abspath(path),name + '.xml')
                # 目标图像路径
        try:
                os.rename(src,dst)
                print('rename from %s to %s'%(src,dst))
                # 将转换结果在终端打印出来以便检查
        except:
                continue

(2)考虑到还与另一份coco格式数据集合并,这里是将B转化后的json文件有针对的复制粘贴到A的json文件里,形成一个合并后的大json文件,然后把两者的所有image图片放在一起即可:

ps:要想B转化后的json文件能承接A,转化过程image_info里的 id ,    annotation里面的id , image_id都要接着前面考虑,直接看代码:

import os
import cv2
import json
import xml.dom.minidom
import xml.etree.ElementTree as ET

data_dir = 'D:\\goole\\forUser_A\\train'  # 根目录文件,其中包含image文件夹和box文件夹(根据自己的情况修改这个路径)

image_file_dir = os.path.join(data_dir, 'image')
#print(image_file_dir)

xml_file_dir = os.path.join(data_dir, 'box')

annotations_info = {'images': [], 'annotations': [], 'categories': []}

categories_map = {'holothurian': 1, 'echinus': 2, 'scallop': 3, 'starfish': 4}

for key in categories_map:
    categoriy_info = {"id": categories_map[key], "name": key}
    annotations_info['categories'].append(categoriy_info)

all_file_names = [image_file_name.split('.')[0]
              for image_file_name in os.listdir(image_file_dir)]

all_file_names.sort(key=lambda x: int(x.split('.')[0]))
#print(os.listdir(image_file_dir))
print(all_file_names)


#ps:ann_id表示instance的排序,从6399开始
ann_id = 6399
for i, file_name in enumerate(all_file_names):

    image_file_name = file_name + '.jpg'
    xml_file_name = file_name + '.xml'
    image_file_path = os.path.join(image_file_dir, image_file_name)
    xml_file_path = os.path.join(xml_file_dir, xml_file_name)

    image_info = dict()
    image = cv2.cvtColor(cv2.imread(image_file_path), cv2.COLOR_BGR2RGB)
    height, width, _ = image.shape

    #ps:id与file_name保持一致,所有加6672
    image_info = {'file_name': image_file_name, 'id': i + 6672, 
                  'height': height, 'width': width}
    annotations_info['images'].append(image_info)

    DOMTree = xml.dom.minidom.parse(xml_file_path)
    collection = DOMTree.documentElement

    names = collection.getElementsByTagName('name')
    names = [name.firstChild.data for name in names]

    xmins = collection.getElementsByTagName('xmin')
    xmins = [xmin.firstChild.data for xmin in xmins]
    ymins = collection.getElementsByTagName('ymin')
    ymins = [ymin.firstChild.data for ymin in ymins]
    xmaxs = collection.getElementsByTagName('xmax')
    xmaxs = [xmax.firstChild.data for xmax in xmaxs]
    ymaxs = collection.getElementsByTagName('ymax')
    ymaxs = [ymax.firstChild.data for ymax in ymaxs]

    object_num = len(names)

    for j in range(object_num):
        if names[j] in categories_map:
            
            #ps:这里image_id相当于上面image_info里的id
            image_id = i + 6672
            x1, y1, x2, y2 = int(xmins[j]), int(ymins[j]), int(xmaxs[j]), int(ymaxs[j])
            x1, y1, x2, y2 = x1 - 1, y1 - 1, x2 - 1, y2 - 1

            if x2 == width:
                x2 -= 1
            if y2 == height:
                y2 -= 1

            x, y = x1, y1
            w, h = x2 - x1 + 1, y2 - y1 + 1
            category_id = categories_map[names[j]]
            area = w * h

            annotation_info = {"id": ann_id, "image_id": image_id, "bbox": [x, y, w, h], "category_id": category_id,
                               "area": area, "iscrowd": 0}
            annotations_info['annotations'].append(annotation_info)
            ann_id += 1 #

with  open('./annotations.json', 'w')  as f:
    json.dump(annotations_info, f, indent=4)

print('---整理后的标注文件---')
print('所有图片的数量:', len(annotations_info['images']))
print('所有标注的数量:', len(annotations_info['annotations']))
print('所有类别的数量:', len(annotations_info['categories']))

转化后得到annotation.json文件,是一字典,3个key,'images', 'annotations',和 'categories'

A的json文件instance_train.json也是如此,只需复制annotation.json里'images'下的值接在instance_train.json里'images'下,对于'annotations'也是如此,这里两者'categories'都一样便不需要改动,如果不一样,取其并集即可,最终得到一个新的合并后的nstance_train.json。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的 Python 脚本,用于将 XML 数据格式换为 COCO 数据格式: ```python import xml.etree.ElementTree as ET import json import os # 设置类别标签 classes = ['class1', 'class2', 'class3', ...] # 设置 XML 数据集文件夹路径和输出 COCO 数据集文件路径 xml_folder = '/path/to/xml/folder' json_file = '/path/to/output/json/file' # 初始化 COCO 数据集字典 coco_dict = { "info": {}, "licenses": [], "categories": [], "images": [], "annotations": [] } # 添加类别标签到 COCO 数据集字典 for i, cls in enumerate(classes): coco_dict['categories'].append({ 'id': i + 1, 'name': cls, 'supercategory': 'object' }) # 遍历 XML 数据集文件夹 for xml_file in os.listdir(xml_folder): if xml_file.endswith('.xml'): # 解析 XML 文件 tree = ET.parse(os.path.join(xml_folder, xml_file)) root = tree.getroot() # 获取图像信息并添加到 COCO 数据集字典 image = { 'id': int(root.find('filename').text.split('.')[0]), 'width': int(root.find('size').find('width').text), 'height': int(root.find('size').find('height').text), 'file_name': root.find('filename').text } coco_dict['images'].append(image) # 遍历图像中的所有对象并添加到 COCO 数据集字典 for obj in root.findall('object'): bbox = obj.find('bndbox') annotation = { 'id': len(coco_dict['annotations']) + 1, 'image_id': image['id'], 'category_id': classes.index(obj.find('name').text) + 1, 'bbox': [int(bbox.find('xmin').text), int(bbox.find('ymin').text), int(bbox.find('xmax').text) - int(bbox.find('xmin').text), int(bbox.find('ymax').text) - int(bbox.find('ymin').text)], 'area': (int(bbox.find('xmax').text) - int(bbox.find('xmin').text)) * (int(bbox.find('ymax').text) - int(bbox.find('ymin').text)), 'iscrowd': 0 } coco_dict['annotations'].append(annotation) # 将 COCO 数据集字典保存为 JSON 格式文件 with open(json_file, 'w') as f: json.dump(coco_dict, f) ``` 请注意,这只是一个简单的脚本,可能无法处理所有情况。您可能需要根据您的特定需求进行修改或添加更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值