├── README.md ├── yolotovoc.py └── voctococo.py /README.md: -------------------------------------------------------------------------------- 1 | # yolo_to_coco 2 | Convert yolo format to coco format 3 | 4 | 5 | 运行步骤: 6 | 1、将要转化的数据放到当前目录下,在当前目录创建文件夹Annotations。在yolotovoc.py主函数中更改路径,运行yolotovoc.py。 7 | 成功运行后,Annotations里会生成相应的xml格式数据。 8 | 2、把所有图片复制到Annotations中,voctococo.py中的train_ratio控制train和val的比例,train_ratio=1是全部生成为train数据。运voctococo.py即可。 9 | -------------------------------------------------------------------------------- /yolotovoc.py: -------------------------------------------------------------------------------- 1 | from xml.dom.minidom import Document 2 | from lxml.etree import Element, SubElement, tostring 3 | import pprint 4 | from xml.dom.minidom import parseString 5 | import cv2 6 | class XmlMaker: 7 | 8 | def __init__(self,txtpath,xmlpath): 9 | self.txtPath = txtpath 10 | self.xmlPath = xmlpath 11 | self.txtList = [] 12 | 13 | def readtxt(self): 14 | jpg = [] 15 | txtfile = open(self.txtPath,"r",encoding='gbk',errors='ignore') 16 | self.txtList = txtfile.readlines() 17 | for i in self.txtList: 18 | jpg = i.strip().split(" ")[0] 19 | xys = i.strip().split(" ")[1:] 20 | 21 | node_root = Element('annotation') 22 | node_folder = SubElement(node_root, 'folder') 23 | node_folder.text = 'VOC2012' 24 | node_filename = SubElement(node_root, 'filename') 25 | node_filename.text = jpg 26 | img = cv2.imread(jpg) 27 | shape = img.shape 28 | 29 | node_size = SubElement(node_root, 'size') 30 | node_width = SubElement(node_size, 'width') 31 | 32 | node_width.text = str(shape[1]) 33 | 34 | node_height = SubElement(node_size, 'height') 35 | node_height.text = str(shape[0]) 36 | 37 | node_depth = SubElement(node_size, 'depth') 38 | node_depth.text = '3' 39 | 40 | for xy in xys: 41 | list_xy = xy.split(",") 42 | 43 | x_min = list_xy[0] 44 | y_min = list_xy[1] 45 | x_max = list_xy[2] 46 | y_max = list_xy[3] 47 | classes = list_xy[4] 48 | node_object = SubElement(node_root, 'object') 49 | node_name = SubElement(node_object, 'name') 50 | node_name.text = 'person' 51 | node_difficult = SubElement(node_object, 'difficult') 52 | node_difficult.text = '0' 53 | node_bndbox = SubElement(node_object, 'bndbox') 54 | node_xmin = SubElement(node_bndbox, 'xmin') 55 | node_xmin.text = str(x_min) 56 | node_ymin = SubElement(node_bndbox, 'ymin') 57 | node_ymin.text = str(y_min) 58 | node_xmax = SubElement(node_bndbox, 'xmax') 59 | node_xmax.text = str(x_max) 60 | node_ymax = SubElement(node_bndbox, 'ymax') 61 | node_ymax.text = str(y_max) 62 | 63 | 64 | xml = tostring(node_root, pretty_print=True) # 格式化显示,该换行的换行 65 | xml_name = jpg.split("/")[-1][:-4]+".xml" 66 | print(xml_name) 67 | with open(self.xmlPath+"/"+xml_name, "wb") as f: 68 | f.write(xml) 69 | f.close() 70 | 71 | if __name__ == "__main__": 72 | read =XmlMaker("train.txt","Annotations") 73 | read.readtxt() 74 | 75 | -------------------------------------------------------------------------------- /voctococo.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | # pip install lxml 4 | 5 | import os 6 | import glob 7 | import json 8 | import shutil 9 | import numpy as np 10 | import xml.etree.ElementTree as ET 11 | 12 | 13 | 14 | path2 = "." 15 | 16 | 17 | START_BOUNDING_BOX_ID = 1 18 | 19 | 20 | def get(root, name): 21 | return root.findall(name) 22 | 23 | 24 | def get_and_check(root, name, length): 25 | vars = root.findall(name) 26 | if len(vars) == 0: 27 | raise NotImplementedError('Can not find %s in %s.'%(name, root.tag)) 28 | if length > 0 and len(vars) != length: 29 | raise NotImplementedError('The size of %s is supposed to be %d, but is %d.'%(name, length, len(vars))) 30 | if length == 1: 31 | vars = vars[0] 32 | return vars 33 | 34 | 35 | def convert(xml_list, json_file): 36 | json_dict = {"images": [], "type": "instances", "annotations": [], "categories": []} 37 | categories = pre_define_categories.copy() 38 | bnd_id = START_BOUNDING_BOX_ID 39 | all_categories = {} 40 | for index, line in enumerate(xml_list): 41 | # print("Processing %s"%(line)) 42 | xml_f = line 43 | tree = ET.parse(xml_f) 44 | root = tree.getroot() 45 | 46 | filename = os.path.basename(xml_f)[:-4] + ".jpg" 47 | image_id = 1 + index 48 | size = get_and_check(root, 'size', 1) 49 | width = int(get_and_check(size, 'width', 1).text) 50 | height = int(get_and_check(size, 'height', 1).text) 51 | image = {'file_name': filename, 'height': height, 'width': width, 'id':image_id} 52 | json_dict['images'].append(image) 53 | ## Cruuently we do not support segmentation 54 | # segmented = get_and_check(root, 'segmented', 1).text 55 | # assert segmented == '0' 56 | for obj in get(root, 'object'): 57 | category = get_and_check(obj, 'name', 1).text 58 | if category in all_categories: 59 | all_categories[category] += 1 60 | else: 61 | all_categories[category] = 1 62 | if category not in categories: 63 | if only_care_pre_define_categories: 64 | continue 65 | new_id = len(categories) + 1 66 | print("[warning] category '{}' not in 'pre_define_categories'({}), create new id: {} automatically".format(category, pre_define_categories, new_id)) 67 | categories[category] = new_id 68 | category_id = categories[category] 69 | bndbox = get_and_check(obj, 'bndbox', 1) 70 | xmin = int(float(get_and_check(bndbox, 'xmin', 1).text)) 71 | ymin = int(float(get_and_check(bndbox, 'ymin', 1).text)) 72 | xmax = int(float(get_and_check(bndbox, 'xmax', 1).text)) 73 | ymax = int(float(get_and_check(bndbox, 'ymax', 1).text)) 74 | assert(xmax > xmin), "xmax <= xmin, {}".format(line) 75 | assert(ymax > ymin), "ymax <= ymin, {}".format(line) 76 | o_width = abs(xmax - xmin) 77 | o_height = abs(ymax - ymin) 78 | ann = {'area': o_width*o_height, 'iscrowd': 0, 'image_id': 79 | image_id, 'bbox':[xmin, ymin, o_width, o_height], 80 | 'category_id': category_id, 'id': bnd_id, 'ignore': 0, 81 | 'segmentation': []} 82 | json_dict['annotations'].append(ann) 83 | bnd_id = bnd_id + 1 84 | 85 | for cate, cid in categories.items(): 86 | cat = {'supercategory': 'none', 'id': cid, 'name': cate} 87 | json_dict['categories'].append(cat) 88 | json_fp = open(json_file, 'w') 89 | json_str = json.dumps(json_dict) 90 | json_fp.write(json_str) 91 | json_fp.close() 92 | print("------------create {} done--------------".format(json_file)) 93 | print("find {} categories: {} -->>> your pre_define_categories {}: {}".format(len(all_categories), all_categories.keys(), len(pre_define_categories), pre_define_categories.keys())) 94 | print("category: id --> {}".format(categories)) 95 | print(categories.keys()) 96 | print(categories.values()) 97 | 98 | 99 | if __name__ == '__main__': 100 | classes = ['person'] 101 | pre_define_categories = {} 102 | for i, cls in enumerate(classes): 103 | pre_define_categories[cls] = i + 1 104 | # pre_define_categories = {'a1': 1, 'a3': 2, 'a6': 3, 'a9': 4, "a10": 5} 105 | only_care_pre_define_categories = True 106 | # only_care_pre_define_categories = False 107 | 108 | train_ratio = 1 109 | save_json_train = 'instances_train2014.json' 110 | save_json_val = 'instances_val2014.json' 111 | xml_dir = "Annotations" 112 | 113 | xml_list = glob.glob(xml_dir + "/*.xml") 114 | xml_list = np.sort(xml_list) 115 | np.random.seed(100) 116 | np.random.shuffle(xml_list) 117 | 118 | train_num = int(len(xml_list)*train_ratio) 119 | xml_list_train = xml_list[:train_num] 120 | xml_list_val = xml_list[train_num:] 121 | 122 | convert(xml_list_train, save_json_train) 123 | convert(xml_list_val, save_json_val) 124 | 125 | if os.path.exists(path2 + "/annotations"): 126 | shutil.rmtree(path2 + "/annotations") 127 | os.makedirs(path2 + "/annotations") 128 | if os.path.exists(path2 + "/images/train2014"): 129 | shutil.rmtree(path2 + "/images/train2014") 130 | os.makedirs(path2 + "/images/train2014") 131 | if os.path.exists(path2 + "/images/val2014"): 132 | shutil.rmtree(path2 +"/images/val2014") 133 | os.makedirs(path2 + "/images/val2014") 134 | 135 | f1 = open("train.txt", "w") 136 | for xml in xml_list_train: 137 | img = xml[:-4] + ".jpg" 138 | f1.write(os.path.basename(xml)[:-4] + "\n") 139 | shutil.copyfile(img, path2 + "/images/train2014/" + os.path.basename(img)) 140 | 141 | f2 = open("test.txt", "w") 142 | for xml in xml_list_val: 143 | img = xml[:-4] + ".jpg" 144 | f2.write(os.path.basename(xml)[:-4] + "\n") 145 | shutil.copyfile(img, path2 + "/images/val2014/" + os.path.basename(img)) 146 | f1.close() 147 | f2.close() 148 | print("-------------------------------") 149 | print("train number:", len(xml_list_train)) 150 | print("val number:", len(xml_list_val)) 151 | --------------------------------------------------------------------------------