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。