数据集转换
1、xml2txt
import xml.etree.ElementTree as ET
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile
class_names={'hat':0,'person':1}
TRAIN_RATIO = 80
def clear_hidden_files(path):
"""
清除隐藏文件
:param path: 文件路径
"""
dir_list = os.listdir(path)
for i in dir_list:
abspath = os.path.join(os.path.abspath(path), i)
if os.path.isfile(abspath):
if i.startswith("._"):
os.remove(abspath)
else:
clear_hidden_files(abspath)
def convert(size, box):
"""
将标注框从 VOC 格式转换为 YOLO 格式
:param size: 图像的宽和高
:param box: 标注框的位置 (xmin, xmax, ymin, ymax)
:return: 转换后的标注框 (x, y, w, h)
"""
dw = 1. / size[0]
dh = 1. / size[1]
x = (box[0] + box[1]) / 2.0 - 1
y = (box[2] + box[3]) / 2.0 - 1
w = box[1] - box[0]
h = box[3] - box[2]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
def convert_annotation(image_id):
"""
将单个图像的 XML 标注文件转换为 YOLO 格式的 txt 文件
:param image_id: 图像ID(文件名)
"""
in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' % image_id)
out_file = open('VOCdevkit/VOC2007/YOLOLabels/%s.txt' % image_id, 'w')
tree = ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in class_names or int(difficult) == 1:
continue
cls_id = class_names[cls]
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w, h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
in_file.close()
out_file.close()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
os.mkdir(data_base_dir)
work_space_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_space_dir):
os.mkdir(work_space_dir)
annotation_dir = os.path.join(work_space_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_space_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_space_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir)
for i in range(0, len(list_imgs)):
path = os.path.join(image_dir, list_imgs[i])
if os.path.isfile(path):
image_path = image_dir + list_imgs[i]
voc_path = list_imgs[i]
(nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
annotation_name = nameWithoutExtention + '.xml'
annotation_path = os.path.join(annotation_dir, annotation_name)
label_name = nameWithoutExtention + '.txt'
label_path = os.path.join(yolo_labels_dir, label_name)
prob = random.randint(1, 100)
print("Probability: %d" % prob)
if(prob < TRAIN_RATIO):
if os.path.exists(annotation_path):
train_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention)
copyfile(image_path, yolov5_images_train_dir + voc_path)
copyfile(label_path, yolov5_labels_train_dir + label_name)
else:
if os.path.exists(annotation_path):
test_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention)
copyfile(image_path, yolov5_images_test_dir + voc_path)
copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()
2、xml2json
"""
Author:DamonZheng
Function:xml2json(for labelme)
Edition:1.0
Date:2022.2.21
"""
import argparse
import glob
import os
import xml.etree.ElementTree as ET
import json
from tqdm import tqdm
def parse_args():
"""
参数配置
"""
parser = argparse.ArgumentParser(description='xml2json')
parser.add_argument('--raw_label_dir', help='the path of raw label', default='data/LabelmeData/VOC2007/Annotations')
parser.add_argument('--pic_dir', help='the path of picture', default='data/LabelmeData/VOC2007/JPEGImages')
parser.add_argument('--save_dir', help='the path of new label', default='data/coco/annotations')
args = parser.parse_args()
return args
def read_xml_gtbox_and_label(xml_path):
"""
读取xml内容
"""
tree = ET.parse(xml_path)
root = tree.getroot()
size = root.find('size')
width = int(size.find('width').text)
height = int(size.find('height').text)
depth = int(size.find('depth').text)
points = []
for obj in root.iter('object'):
cls = obj.find('name').text
pose = obj.find('pose').text
xmlbox = obj.find('bndbox')
xmin = float(xmlbox.find('xmin').text)
xmax = float(xmlbox.find('xmax').text)
ymin = float(xmlbox.find('ymin').text)
ymax = float(xmlbox.find('ymax').text)
box = [xmin, ymin, xmax, ymax]
point = [cls, box]
points.append(point)
return points, width, height
def main():
"""
主函数
"""
args = parse_args()
labels = glob.glob(args.raw_label_dir + '/*.xml')
for i, label_abs in tqdm(enumerate(labels), total=len(labels)):
_, label = os.path.split(label_abs)
label_name = label.rstrip('.xml')
img_path = os.path.join(args.pic_dir, label_name + '.jpg')
points, width, height = read_xml_gtbox_and_label(label_abs)
json_str = {}
json_str['version'] = '4.5.6'
json_str['flags'] = {}
shapes = []
for i in range(len(points)):
shape = {}
shape['label'] = points[i][0]
shape['points'] = [[points[i][1][0], points[i][1][1]],
[points[i][1][0], points[i][1][3]],
[points[i][1][2], points[i][1][3]],
[points[i][1][2], points[i][1][1]]]
shape['group_id'] = None
shape['shape_type'] = 'polygon'
shape['flags'] = {}
shapes.append(shape)
json_str['shapes'] = shapes
json_str['imagePath'] = img_path
json_str['imageData'] = None
json_str['imageHeight'] = height
json_str['imageWidth'] = width
with open(os.path.join(args.save_dir, label_name + '.json'), 'w') as f:
json.dump(json_str, f, indent=2)
if __name__ == '__main__':
main()
3、json2coco
import os
import json
import glob
def polygon_to_bbox(polygon):
x_coords = [point[0] for point in polygon]
y_coords = [point[1] for point in polygon]
x_min = min(x_coords)
x_max = max(x_coords)
y_min = min(y_coords)
y_max = max(y_coords)
width = x_max - x_min
height = y_max - y_min
return [x_min, y_min, width, height]
def convert_to_coco(input_folder, output_file):
coco_data = {
"images": [],
"annotations": [],
"categories": [],
}
category_map = {}
annotation_id = 1
image_id = 1
categories = ['hat','person']
for i, category in enumerate(categories):
coco_data['categories'].append({
"id": i + 1,
"name": category,
"supercategory": "none"
})
category_map[category] = i + 1
json_files = glob.glob(os.path.join(input_folder, "*.json"))
for json_file in json_files:
with open(json_file, 'r') as f:
content = f.read().replace('\\', '\\\\')
try:
data = json.loads(content)
print(data.keys())
except json.JSONDecodeError as e:
print(f"Error parsing {json_file}: {e}")
continue
image_info = {
"id": image_id,
"file_name": data["imagePath"],
"width": data["imageWidth"],
"height": data["imageHeight"]
}
coco_data["images"].append(image_info)
for ann in data["shapes"]:
bbox = polygon_to_bbox(ann["points"])
annotation_info = {
"id": annotation_id,
"image_id": image_id,
"category_id": category_map[ann["label"]],
"bbox": bbox,
"area": bbox[2] * bbox[3],
"iscrowd": 0
}
coco_data["annotations"].append(annotation_info)
annotation_id += 1
image_id += 1
if not output_file.endswith(".json"):
output_file += ".json"
with open(output_file, 'w') as f:
json.dump(coco_data, f, indent=4)
input_folder = 'data/LabelmeData/annotations/val'
output_file = 'data/coco/annotations'
convert_to_coco(input_folder, output_file)