mydata
├── Annotations
├── JPEGImages
├── label_list.txt
├── train.txt
└── valid.txt
2 directories, 3 files
以上是数据处理完成后的目标检测数据信的结构,label_list.txt中存放按首字母排序的类字符串,一个类一行;划分训练和验证集的train.txt和valid.txt则是存放图片的图片咱径和标注文件路径,大概是这样:
mydata/JPEGImages/1.jpg mydata/Annotations/1.xml 一张片一行。
以上边我们的xml数据集为例(其它也可以,反正是一个文件夹放图片,一个文件夹放标注,还是一个是标签文件.本文整个全流程只提供一个小的参考,由于自定义数据格式多样,只要接照流程能获取相应的要素就可以。
import glob
ann_path = "mydata/Annotations" # 相对路径或绝对路径都可以只要能该问到就可以
labels_path = "mydata/label_list.txt"
def voc_get_label_anno(ann_path, labels_path):
with open(labels_path, 'r') as f:
labels_str = f.read().split()
labels_ids = list(range(1, len(labels_str) + 1))
with open(ann_path,'r') as f:
all_lines = f.readlines()
rootdir = os.path.dirname(ann_path)
ann_paths = [os.path.join(rootdir,i.strip().split(' ')[-1][2:]) for i in all_lines]
return dict(zip(labels_str, labels_ids)), ann_paths
label2id, ann_paths = voc_get_label_anno("/data/VOCdevkit/train.txt","/data/VOCdevkit/label_list.txt")
label2id
{'screen': 1}
ann_paths[:3]
['/data/VOCdevkit/d1/Annotations/微信截图_20220317104310.xml',
'/data/VOCdevkit/d1/Annotations/微信截图_20220228173530.xml',
'/data/VOCdevkit/d1/Annotations/微信截图_20220313163312.xml']
from tqdm import tqdm
import xml.etree.ElementTree as ET
import json
def voc_xmls_to_cocojson(annotation_paths, label2id, output_dir, output_file):
output_json_dict = {
"images": [],
"type": "instances",
"annotations": [],
"categories": []
}
bnd_id = 1 # bounding box start id
im_id = 0
print('Start converting !')
for a_path in tqdm(annotation_paths):
# Read annotation xml
ann_tree = ET.parse(a_path)
ann_root = ann_tree.getroot()
filename = ann_root.findtext('filename')
assert filename is not None
img_name = os.path.basename(filename)
size = ann_root.find('size')
width = float(size.findtext('width'))
height = float(size.findtext('height'))
img_info = {
'file_name': filename,
'height': height,
'width': width,
'id': im_id
}
output_json_dict['images'].append(img_info)
for obj in ann_root.findall('object'):
label = obj.findtext('name')
assert label in label2id, "label is not in label2id."
category_id = label2id[label]
bndbox = obj.find('bndbox')
xmin = float(bndbox.findtext('xmin'))
ymin = float(bndbox.findtext('ymin'))
xmax = float(bndbox.findtext('xmax'))
ymax = float(bndbox.findtext('ymax'))
assert xmax > xmin and ymax > ymin, "Box size error."
o_width = xmax - xmin
o_height = ymax - ymin
anno = {
'area': o_width * o_height,
'iscrowd': 0,
'bbox': [xmin, ymin, o_width, o_height],
'category_id': category_id,
'ignore': 0,
}
anno.update({'image_id': im_id, 'id': bnd_id})
output_json_dict['annotations'].append(anno)
bnd_id = bnd_id + 1
im_id += 1
for label, label_id in label2id.items():
category_info = {'supercategory': 'none', 'id': label_id, 'name': label}
output_json_dict['categories'].append(category_info)
output_file = os.path.join(output_dir, output_file)
with open(output_file, 'w',encoding='utf-8') as f:
output_json = json.dumps(output_json_dict,ensure_ascii=False,indent=4)
f.write(output_json)
output_dir = '/data/VOCdevkit/'
output_file = "instance_train.json"
voc_xmls_to_cocojson(ann_paths, label2id, output_dir, output_file)
Start converting !
100%|██████████| 47102/47102 [00:05<00:00, 7998.80it/s]
同理验证集也跑一次
label2id, ann_paths = voc_get_label_anno("/data/VOCdevkit/valid.txt","/data/VOCdevkit/label_list.txt")
output_dir = '/data/VOCdevkit/'
output_file = "instance_valid.json"
voc_xmls_to_cocojson(ann_paths, label2id, output_dir, output_file)
Start converting !
100%|██████████| 5237/5237 [00:01<00:00, 4246.70it/s]