The json file of the TinyPerson dataset is rewritten as an xml file

TinyPerson (NWPU VHR-10 or other equivalent) dataset files are rewritten as VOC type xml files

Code to python implementation

It's not easy to create, give it a thumbs up


In order to accomplish this goal, the following two things are required:
1. Write the xml file according to the specification
2. Rewrite it as an xml file according to the Annotation format of TinyPerson
(#The above problem is what I encountered and solved when trying to run out of the TinyPerson data set, I hope more Friends who use this data set to test small target detection can run out of this data set more conveniently#)

XML file reading and writing

related modules

from lxml import etree
from lxml.etree import Element,SubElement,tostring

read xml file

path_xml='your_xml_path'
with open(path_xml,'r') as file:
	xml_str=file.read()
	#<class 'str'>
xml=etree.fromstring(xml_str)
#<class 'lxml.etree._Element'>

# 下一步只需把xml文件析成dict

Analyze the xml file as dict

def parse_xml_to_dict(xml):
    if len(xml) == 0:  # 遍历到底层,直接返回tag对应的信息
        return {
    
    xml.tag: xml.text}
    result = {
    
    }
    for child in xml:
        #print(child.text)
        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}

write xml file

node_root=Element('annotation')#Element用来创建一个lxml.etree._Element类
node_folder=SubElement(node_root,'fold')#创建子类
node_folder.text='your xml file path'
node_object=SubElement(node_root,'object')
node_weight=SubElement(node_object,'weight')
node_wieght.text=256
node_height=SubElement(node_object,'height')
node_height.text=256
#当我们保存为xml文件时,只需要保存node_root即可
xml_byte=tostring(node_root)#虽然函数名为tostring但是得到的格式实际是bytes,可用type查看
with open('path you want to save','wb') as f:#此处需用wb,代表写入bytes,如果是'r'会报错
	f.write(xml_byte)
# 至此完成了xml的保存

There is another way of writing:

import xml.dom.minidom
dom=minidom.Document()
annotation=dom.createElement('annotation')#创建根节点
dom.appendChild(annotation)#添加根节点
size=dom.createElement('size')
annotation.appendChild('size')

width=dom.createElement('width')
size.appendChild(width)
width_text=dom.createTextNode('256')
width.appendChild(width_text)

height=dom.createElement('height')
size.appendChild(height)
height_text=dom.createTextNode('256')
height.appendChild(height_text)

depth=dom.createElement('depth')
size.appendChild(depth)
depth_text=dom.createTextNode('3')
depth.appendChild(depth_text)
#至此便创建了一个dom文件,以下将其保存为xml并展示效果
with open(path,'w') as f:
	dom.writexml(f)#这么保存格式不好看,推荐:
	dom.writexml(f,indent='',addindent='\t',newl='\n',encoding='UTF-8')

The effect is as shown in the figure:

Modify the xml file

Usually we write an xml file, which may need subsequent modification

Modify the value of an existing node

The following code modifies the value of height and width in the xml file to height, width

import xml.dom.minidom
dom=xml.dom.minidom.parse(path)
root=dom.documentElement
heights=root.getElementsByTagName('height')[0]
heights.firstChild.data=height
#print(height)

widths=root.getElementsByTagName('width')[0]
widths.firstChild.data=width
#print(width)
with open(path, 'w') as f:
    dom.writexml(f)

add node

dom=xml.dom.minidom.parse(path)
root=dom.documentElement
node1=dom.createElement('node1')
root.appendChild(node1)#如此便在root下添加了一个子节点
name_text=dom.createTextNode('this is node1 of root')
node1.appendChild(name_text)#如此便在node1中添加了一个文本节点

TinyPerson Dataset Combat

The purpose of this section: read the TinyPerson dataset annotation, and use the above method to write the xml file

TinyPerson dataset annotation example:

{“type”: “instance”, “annotations”: [{“segmentation”: [[1081.124389319407, 17.45930926910859, 1267.431666947439, 17.45930926910859, 1267.431666947439, 67.73270164492683, 1081.124389319407, 67.73270164492683]], “bbox”: [1081.124389319407, 17.45930926910859, 186.3072776280319, 50.27339237581825], “category_id”: 1, “area”: 9366.298870664552, “iscrowd”: 0, “image_id”: 0, “id”: 0, “ignore”: true, “uncertain”: false, “logo”: true, “in_dense_image”: false},

The following is the next {"segmentaion": #######}
to analyze the content of the following json file:
segmentation represents an instance
bbox is GT's x, y, width, height
image_id represents the mth image
id represents The nth object (cumulative, it will not return to 0 because the picture is cut to the next one)

How to find the image location corresponding to image_id
This requires the next json file

images”: [{“file_name”: “labeled_images/bb_V0032_I0001640.jpg”, “height”: 720, “width”: 1280, “id”: 0}, {“file_name”: “labeled_images/bb_V0014_I0002600.jpg”, “height”: 1080, “width”: 1920, “id”: 1},

From this json file, you can analyze the above image_id represented by the id here, OK now you can start

getting information

Writing an xml file in VOC format requires the following information:
dealpath stores the xml file location
filename stores the xml file name
num the number of objects in each picture
xmins, ymins, xmaxs, ymaxs, [4,n]
names [n] represents each The name height and width of the object
are the height and width of the picture.
Special attention should be paid to the above. The above must be in the form of a string (including xmins.
 dict1 = json.load(json_path)
Take this picture as an example, file_name, height, width, and dealpath can be uniquely determined,
but for each dict1['annotations' ][0] can only get one object
, so we can write through 'images', first write out the xml file, and then modify it according to the object read each time (nice idea)

Python implementation

import os
import json
from lxml import etree
from lxml.etree import Element,SubElement,tostring
from xml.dom import minidom
json_file=open('D:/CODE/data/tiny_set/tiny_set/annotations/tiny_set_train.json','r')
path1='D:/CODE/data/tiny_set/tiny_set/annotation'#path1代表生成annotations的位置
path2='D:/CODE/data/tiny_set/tiny_set/train/train'
dict1=json.load(json_file)#读取字典

#更改labeled_image文件夹中的图片名称(我个人习惯)
for i in range(746): # 746 = len(dict1['images'])
    file1=os.path.join(path2,dict1['images'][i]['file_name'])
    #file1=os.path.join(path2,'labeled_images',str(dict1['images'][i]['id'])+'.jpg')
    file2=os.path.join(path2,'labeled_images',str(dict1['images'][i]['id']).rjust(3,'0')+'.jpg')
    os.rename(file1,file2)
    
#在path1目录下创建xml文件
for i in range(746):
    annotation=Element('annotation')#Element用来创建一个lxml.etree._Element类
    folder=SubElement(annotation,'folder')#创建子类
    folder.text='tiny_set'
    
    filename=SubElement(annotation,'filename')
    filename.text=str(dict1['images'][i]['id'])+'.jpg'
    
    size=SubElement(annotation,'size')
    width=SubElement(size,'width')
    width.text=str(dict1['images'][i]['width'])
    height=SubElement(size,'height')
    height.text=str(dict1['images'][i]['height'])
    depth=SubElement(size,'depth')
    depth.text='3'
    
    xml_byte=tostring(annotation)#虽然函数名为tostring但是得到的格式实际是bytes,可用type查看
    file_path=os.path.join(path1,str(dict1['images'][i]['id']).rjust(3,'0')+'.xml')
    with open(file_path,'wb') as f:#此处需用wb,代表写入bytes,如果是'r'会报错
        f.write(xml_byte)

#根据每个object信息去修改xml文件
for i in range(len(dict1['annotations'])):
    img_id=str(dict1['annotations'][i]['image_id']).rjust(3,'0')
    xml_path=os.path.join(path1,img_id+'.xml')
    dom=minidom.parse(xml_path)
    annotation=dom.documentElement
    object_node=dom.createElement('object')
    annotation.appendChild(object_node)
    #为了省事,创建节点的代码写在一起
    name=dom.createElement('name')
    pose=dom.createElement('pose')
    truncated=dom.createElement('truncated')
    difficult=dom.createElement('difficule')
    bndbox=dom.createElement('bndbox')
    xmin=dom.createElement('xmin')
    ymin=dom.createElement('ymin')
    xmax=dom.createElement('xmax')
    ymax=dom.createElement('ymax')
    
    object_node.appendChild(name)
    object_node.appendChild(pose)
    object_node.appendChild(truncated)
    object_node.appendChild(difficult)
    object_node.appendChild(bndbox)
    bndbox.appendChild(xmin)
    bndbox.appendChild(ymin)
    bndbox.appendChild(xmax)
    bndbox.appendChild(ymax)
    
    obj_name=dict1['annotations'][i]['category_id']
    if obj_name==1:
        obj_name='sea_person'
    else:
        obj_name='earth_person'
    text=dom.createTextNode(obj_name)
    name.appendChild(text)
    
    text=dom.createTextNode('unspecified')
    pose.appendChild(text)
    
    text=dom.createTextNode('0')
    truncated.appendChild(text)
    
    obj_dif=dict1['annotations'][i]['ignore']
    if obj_dif:
        obj_dif='1'
    else:
        obj_dif='0'
    text=dom.createTextNode(obj_dif)
    difficult.appendChild(text)
    
    #x,y,weight,height
    
    bbox=dict1['annotations'][i]['bbox']
    half_w=bbox[2]
    half_h=bbox[3]
    text=dom.createTextNode(str(bbox[0]))
    xmin.appendChild(text)
    text=dom.createTextNode(str(bbox[1]))
    ymin.appendChild(text)
    text=dom.createTextNode(str(bbox[0]+half_w))
    xmax.appendChild(text)
    text=dom.createTextNode(str(bbox[1]+half_h))
    ymax.appendChild(text)
    
    #这几句代码的是为了打出来的格式好看。可以用一句dom.writexml(f)代替with:里面所有内容
    with open(xml_path, 'w') as f:
        if i==25287 : 
            dom.writexml(f,indent='',addindent='\t',newl='\n',encoding='UTF-8')
        elif dict1['annotations'][i+1]['image_id'] != dict1['annotations'][i]['image_id'] :
            dom.writexml(f,indent='',addindent='\t',newl='\n',encoding='UTF-8')
        else:
            dom.writexml(f)

Show results

xml file display:
insert image description here
annotation effect display diagram:
insert image description here

references

https://blog.csdn.net/summer2day/article/details/83064727?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control&dist_request_id=1619533822770_16111&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control

https://www.cnblogs.com/wcwnina/p/7222180.html

https://blog.csdn.net/mingyang_wang/article/details/82912636

Likes are a meaningful thing, not only for the author, but also for the readers.
If I could go back in time, I would definitely like those articles that guided me

Guess you like

Origin blog.csdn.net/fei_YuHuo/article/details/117264541