1. 介绍
之前在做目标检测任务的时候,发现很多的数据集仅有数据(只有图片+标注的xml文件),没有关于类别的json文件,为了以后方便使用,这里记录一下
一般来说,yolo标注的数据集,只有第一个是数字类别,要是没有classes对应的类别,只能根据图片一个个输入。
对于xml解释性标签文件,标注的时候,object下面的name就是目标检测框的分类,所以这里只有xml生成类别json文件的代码
2. 实现代码
代码实现简单,仅有50行,这里简单介绍
这里root传入的是数据集的xml目录,因为训练集包含本检测任务的所有分类,这里传入的是目录
if __name__ == "__main__":
root = './my_xml_dataset/train/annotations' # 数据集的 xml 目录
xml2json(root)
下面读取xml文件的内容,这里的data以及将单个xml文件全部解析出来
- open里面的encoding和errors参数是因为本实验的xml包含中文字符,这样可以防止报错,正常的话不需要这两个参数,如果xml编码不一样,根据报错信息,百度一下传入不同编码就行了
- parse_xml_to_dict 为自定义函数,后面会贴所有代码,这里只需要知道利用递归将xml文件解析成字典文件即可,看下面的data打印信息
接着开始读取单个xml的所有目标类别,如下
classes需要去除重复的目标,生成单个的classes文件
最好生成json文件即可
可以看出,测试数据的目标共有10347个
生成的json文件如下:
3. 完整代码
如下:
import os
from tqdm import tqdm
from lxml import etree
import json
# 读取 xml 文件信息,并返回字典形式
def parse_xml_to_dict(xml):
if len(xml) == 0: # 遍历到底层,直接返回 tag对应的信息
return {xml.tag: xml.text}
result = {}
for child in xml:
child_result = parse_xml_to_dict(child) # 递归遍历标签信息
if child.tag != 'object':
result[child.tag] = child_result[child.tag]
else:
if child.tag not in result: # 因为object可能有多个,所以需要放入列表里
result[child.tag] = []
result[child.tag].append(child_result[child.tag])
return {xml.tag: result}
# 提取xml中name保留为json文件
def xml2json(data):
xml_path = [os.path.join(data, i) for i in os.listdir(data)]
classes = [] # 目标类别
num_object = 0
for xml_file in tqdm(xml_path, desc="loading..."):
with open(xml_file,encoding='gb18030',errors='ignore') as fid: # 防止出现非法字符报错
xml_str = fid.read()
xml = etree.fromstring(xml_str)
data = parse_xml_to_dict(xml)["annotation"] # 读取xml文件信息
for j in data['object']: # 获取单个xml文件的目标信息
ob = j['name']
num_object +=1
if ob not in classes:
classes.append(ob)
print(num_object)
# 生成json文件
labels = {}
for index,object in enumerate(classes):
labels[index] = object
labels = json.dumps(labels,indent=4)
with open('class_indices.json','w') as f:
f.write(labels)
if __name__ == "__main__":
root = './my_xml_dataset/train/annotations' # 数据集的 xml 目录
xml2json(root)
下载地址:关于目标检测:如何根据XML标签文件生成检测类别的json字典文件,包含数据集、测试代码以及生成好的json文件
如果出现编码问题,将这一行增加