由于最近任务的模型需要采用coco数据集格式,只能将现有数据的xml格式进行转换。查阅了网上很多xml转coco数据集的资料,由于每个人都数据集格式都不一样,发现其实很多细节都对不上,还是得自己重新写一个代码确保最后数据集格式的正确性。记录一下自己的工作。
此处反复研究了coco数据集的格式,主要参考以下两个帖子:
https://blog.csdn.net/weixin_44052271/article/details/120475779
https://blog.csdn.net/weixin_50727642/article/details/122892088
首先先创建一个用于储存数据的图片类似coco数据集的文件夹,包括了以下几个文件夹,我这里训练和验证集已经分好了,不用重新分,所以直接把图片复制粘贴到对应文件夹下就好了
然后再把所有图片和对应xml的名字都改成000000000001 这种形式,一开始没改,名字里面有字母,对应json文件里面的id就是一串字符,然后模型训练就报错了,所以经验就是改了最好。然后再统一一下图片格式都转化为jpg。
xml标注文件类似:
以下是进行转换完整代码
import json
from xml.dom.minidom import parse
import os
def open_xml(xml_path,id):#从xml获得filename,height,width
domTree = parse(xml_path)
# 获得根节点
rootNode = domTree.documentElement
filename=rootNode.getElementsByTagName('filename')[0].childNodes[0].data
size=rootNode.getElementsByTagName('size')
h=size[0].getElementsByTagName('height')[0].childNodes[0].data
w=size[0].getElementsByTagName('width')[0].childNodes[0].data
id=id #id获取重复了,懒得删
return filename,h,w,id
def images_json(filename,h,w,id):#每张图片生成一个image字典添加到dict_total={'images':[]中
images={
'file_name': '',
'height': 0,
'width': 0,
'id':0
}
images['file_name']=filename
images['height']=int(h)
images['width'] =int(w)
images['id']=int(id)
return images
def categories_json():
categories=[
{'supercategory': 'person', 'id': 1, 'name': 'mask'},
{'supercategory': 'person', 'id': 2, 'name': 'nomask'}]
return categories
def extract_xml(xml_path,id):#得到annotations里的对应信息
id=id
area=[]
box=[]
name=[]
domTree = parse(xml_path)
# 获得根节点
rootNode = domTree.documentElement
object = rootNode.getElementsByTagName('object')
for i in range(len(object)):
name_item=object[i].getElementsByTagName('name')[0].childNodes[0].data
name.append(name_item)
box_xmin=object[i].getElementsByTagName('bndbox')[0].getElementsByTagName('xmin')[0].childNodes[0].data
box_ymin=object[i].getElementsByTagName('bndbox')[0].getElementsByTagName('ymin')[0].childNodes[0].data
box_xmax=object[i].getElementsByTagName('bndbox')[0].getElementsByTagName('xmax')[0].childNodes[0].data
box_ymax=object[i].getElementsByTagName('bndbox')[0].getElementsByTagName('ymax')[0].childNodes[0].data
area_item=(float(box_xmax)-float(box_xmin))*(float(box_ymax)-float(box_ymin))
area.append(float(area_item))
w=float(box_xmax)-float(box_xmin)
h=float(box_ymax)-float(box_ymin)
box_item=[float(box_xmin),float(box_ymin),w,h]
box.append(box_item)
return area,id,box,name,len(object)
def annotations_json(area,id,box,name,count):
annotations={
'segmentation': [[]], #忽略
'area': 240.000, #面积需要计算
'iscrowd': 0, #忽略
'image_id': 289343, #就是id
'bbox': [0., 0., 60., 40.],
'category_id': 1,
'id': 1768} #bbbox序号
annotations['area']=float(area)
annotations['image_id'] = int(id)
annotations['bbox'] = box
if name=='mask':
annotations['category_id'] = 1
else:
annotations['category_id'] = 2
annotations['id'] = count
return annotations
url=r"C:\Users\dogbark\Desktop\datasets\val\Annotations"
file = os.listdir(url)
dict_total={'images':[],'annotations':[],'categories':[]}#总的json字典
for f in file:#这部分操作只生成了images字段
real_url = os.path.join(url, f)
id = os.path.splitext(f)
_, h, w, id0 = open_xml(real_url, id[0])
filename=id[0]+'.jpg'
image = images_json(filename, h, w, id0)
dict_total['images'].append(image)
print(len(dict_total['images'])) #检验生成字段数量是否完整
#接下来是categories字段
categories=categories_json()
dict_total['categories']=categories
#最后是annotations字段
count=0
for f in file:#这部分操作只生成了images字段
real_url = os.path.join(url, f)
id = os.path.splitext(f)
area, id0, box, name,n= extract_xml(real_url, id[0])
for j in range(n):
count+=1
annotations = annotations_json(area[j], id0, box[j], name[j], count)
dict_total['annotations'].append(annotations)
print(count)
with open(r"C:\\Users\dogbark\Desktop\datasets\\record.json", "w") as f:
json.dump(dict_total, f) #写入json文件
print("加载入文件完成...")
编程能力有待增强,有错的或者写的不简洁的地方勿怪。以上许多地方出现重复,主要因为是一个字段一个字段地生成,然后再在原本代码上添加新的字段生成的代码,还有一个比较悲惨的原因是以为队友能接手一下我的工作,每人完成一个字段生成的代码,结果发现他太慢了只能含泪自己一个人搞完,虽然工作不多,但是扣的细节不少还是很让人心烦。