├── README.md ├── coco_categories.csv ├── coco_get_annotations_xml_format.py └── pascal_voc_template.xml /README.md: -------------------------------------------------------------------------------- 1 | # coco-annotations-to-xml 2 | Convert COCO annotations to xml format 3 | 4 | 5 | COCO is a well-known detection dataset: 6 | http://cocodataset.org/ 7 | 8 | Overview: 9 | ** 10 | 11 | Annotation files are provided for train and validation images for COCO. These are in the form of .json files - 'JavaScript Object Notation' format- the information is in the form of key-value pairs, and if you are familiar with Python, you might recognize this as having a similar format to that of a Python dictionary. 12 | The code in this repository will convert that information to a PASCAL VOC -type .xml file. 13 | 14 | ![image](https://user-images.githubusercontent.com/58288779/78465340-06d0d280-7727-11ea-90b7-0a612f6f8c36.png) 15 | 16 | Procedure: 17 | ** 18 | 19 | Annotations are read after the .json file is loaded. 20 | There are several annotations present, and it is important to note that each annotation doesn't correspond necessarily to one image, but to one object. This object again could be a single object, or an amalgamation of objects (in this case, the attribute 'iscrowd' is set to one). 21 | This code is agnostic to the 'iscrowd' parameter- but you might want to change this depending on your use-case. 22 | Xml files are generated for each image, after the annotations are pooled. 23 | 24 | Why is this useful: 25 | ** 26 | 27 | Several reasons. 28 | -> You might want to train a detector like Yolov2, which uses .xml files 29 | https://github.com/thtrieu/darkflow 30 | 31 | -> You might want to visualize annotations using tools like labelImg, which use .xml files 32 | https://github.com/tzutalin/labelImg 33 | 34 | -> You might just want to do this for fun, and improve your Python skills :-) 35 | 36 | 37 | USAGE 38 | ** 39 | 40 | -> Download the required annotation files- you may do so from the official COCO dataset (link given above) 41 | 42 | -> Change the code accordingly based on whether the annotation is from train/val (or something else. If something else, the coco annotation format MUST be maintained, .json file and all) 43 | 44 | -> Run coco_get_annotations_xml_format.py 45 | 46 | -> Get your .xml files, and do what you need to do with them. 47 | 48 | ![labelimg](https://user-images.githubusercontent.com/58288779/78465309-95911f80-7726-11ea-9a6b-71155412b21e.png) 49 | -------------------------------------------------------------------------------- /coco_categories.csv: -------------------------------------------------------------------------------- 1 | supercategory,id,name 2 | person,1,person 3 | vehicle,2,bicycle 4 | vehicle,3,car 5 | vehicle,4,motorcycle 6 | vehicle,5,airplane 7 | vehicle,6,bus 8 | vehicle,7,train 9 | vehicle,8,truck 10 | vehicle,9,boat 11 | outdoor,10,traffic light 12 | outdoor,11,fire hydrant 13 | outdoor,13,stop sign 14 | outdoor,14,parking meter 15 | outdoor,15,bench 16 | animal,16,bird 17 | animal,17,cat 18 | animal,18,dog 19 | animal,19,horse 20 | animal,20,sheep 21 | animal,21,cow 22 | animal,22,elephant 23 | animal,23,bear 24 | animal,24,zebra 25 | animal,25,giraffe 26 | accessory,27,backpack 27 | accessory,28,umbrella 28 | accessory,31,handbag 29 | accessory,32,tie 30 | accessory,33,suitcase 31 | sports,34,frisbee 32 | sports,35,skis 33 | sports,36,snowboard 34 | sports,37,sports ball 35 | sports,38,kite 36 | sports,39,baseball bat 37 | sports,40,baseball glove 38 | sports,41,skateboard 39 | sports,42,surfboard 40 | sports,43,tennis racket 41 | kitchen,44,bottle 42 | kitchen,46,wine glass 43 | kitchen,47,cup 44 | kitchen,48,fork 45 | kitchen,49,knife 46 | kitchen,50,spoon 47 | kitchen,51,bowl 48 | food,52,banana 49 | food,53,apple 50 | food,54,sandwich 51 | food,55,orange 52 | food,56,broccoli 53 | food,57,carrot 54 | food,58,hot dog 55 | food,59,pizza 56 | food,60,donut 57 | food,61,cake 58 | furniture,62,chair 59 | furniture,63,couch 60 | furniture,64,potted plant 61 | furniture,65,bed 62 | furniture,67,dining table 63 | furniture,70,toilet 64 | electronic,72,tv 65 | electronic,73,laptop 66 | electronic,74,mouse 67 | electronic,75,remote 68 | electronic,76,keyboard 69 | electronic,77,cell phone 70 | appliance,78,microwave 71 | appliance,79,oven 72 | appliance,80,toaster 73 | appliance,81,sink 74 | appliance,82,refrigerator 75 | indoor,84,book 76 | indoor,85,clock 77 | indoor,86,vase 78 | indoor,87,scissors 79 | indoor,88,teddy bear 80 | indoor,89,hair drier 81 | indoor,90,toothbrush 82 | -------------------------------------------------------------------------------- /coco_get_annotations_xml_format.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import os 4 | import xml.etree.ElementTree as ET 5 | import pandas as pd 6 | import cv2 7 | import json 8 | 9 | def write_to_xml(image_name, image_dict, data_folder, save_folder, xml_template='pascal_voc_template.xml'): 10 | 11 | 12 | # get bboxes 13 | bboxes = image_dict[image_name] 14 | 15 | # read xml file 16 | tree = ET.parse(xml_template) 17 | root = tree.getroot() 18 | 19 | # modify 20 | folder = root.find('folder') 21 | folder.text = 'Annotations' 22 | 23 | fname = root.find('filename') 24 | fname.text = image_name.split('.')[0] 25 | 26 | src = root.find('source') 27 | database = src.find('database') 28 | database.text = 'COCO2017' 29 | 30 | 31 | # size 32 | img = cv2.imread(os.path.join(data_folder, image_name)) 33 | h,w,d = img.shape 34 | 35 | size = root.find('size') 36 | width = size.find('width') 37 | width.text = str(w) 38 | height = size.find('height') 39 | height.text = str(h) 40 | depth = size.find('depth') 41 | depth.text = str(d) 42 | 43 | for box in bboxes: 44 | # append object 45 | obj = ET.SubElement(root, 'object') 46 | 47 | name = ET.SubElement(obj, 'name') 48 | name.text = box[0] 49 | 50 | pose = ET.SubElement(obj, 'pose') 51 | pose.text = 'Unspecified' 52 | 53 | truncated = ET.SubElement(obj, 'truncated') 54 | truncated.text = str(0) 55 | 56 | difficult = ET.SubElement(obj, 'difficult') 57 | difficult.text = str(0) 58 | 59 | bndbox = ET.SubElement(obj, 'bndbox') 60 | 61 | xmin = ET.SubElement(bndbox, 'xmin') 62 | xmin.text = str(int(box[1])) 63 | 64 | ymin = ET.SubElement(bndbox, 'ymin') 65 | ymin.text = str(int(box[2])) 66 | 67 | xmax = ET.SubElement(bndbox, 'xmax') 68 | xmax.text = str(int(box[3])) 69 | 70 | ymax = ET.SubElement(bndbox, 'ymax') 71 | ymax.text = str(int(box[4])) 72 | 73 | # save .xml to anno_path 74 | anno_path = os.path.join(save_folder, image_name.split('.')[0] + '.xml') 75 | print(anno_path) 76 | tree.write(anno_path) 77 | 78 | 79 | # main routine 80 | if __name__=='__main__': 81 | 82 | # read annotations file 83 | annotations_path = 'instances_val2017.json' 84 | 85 | # read coco category list 86 | df = pd.read_csv('coco_categories.csv') 87 | df.set_index('id', inplace=True) 88 | 89 | # specify image locations 90 | image_folder = 'val2017' 91 | 92 | # specify savepath - where to save .xml files 93 | savepath = 'saved' 94 | if not os.path.exists(savepath): 95 | os.makedirs(savepath) 96 | 97 | # read in .json format 98 | with open(annotations_path,'rb') as file: 99 | doc = json.load(file) 100 | 101 | # get annotations 102 | annotations = doc['annotations'] 103 | 104 | # iscrowd allowed? 1 for ok, else set to 0 105 | iscrowd_allowed = 1 106 | 107 | # initialize dict to store bboxes for each image 108 | image_dict = {} 109 | 110 | # loop through the annotations in the subset 111 | for anno in annotations: 112 | # get annotation for image name 113 | image_id = anno['image_id'] 114 | image_name = '{0:012d}.jpg'.format(image_id) 115 | 116 | # get category 117 | category = df.loc[anno['category_id']]['name'] 118 | 119 | # add as a key to image_dict 120 | if not image_name in image_dict.keys(): 121 | image_dict[image_name]=[] 122 | 123 | # append bounding boxes to it 124 | box = anno['bbox'] 125 | # since bboxes = [xmin, ymin, width, height]: 126 | image_dict[image_name].append([category, box[0], box[1], box[0]+box[2], box[1]+box[3]]) 127 | 128 | # generate .xml files 129 | for image_name in image_dict.keys(): 130 | write_to_xml(image_name, image_dict, image_folder, savepath) 131 | print('generated for: ', image_name) 132 | -------------------------------------------------------------------------------- /pascal_voc_template.xml: -------------------------------------------------------------------------------- 1 | 2 | n02814533 3 | n02814533_62180 4 | 5 | ILSVRC_2012 6 | 7 | 8 | 1280 9 | 960 10 | 3 11 | 12 | 0 13 | 14 | --------------------------------------------------------------------------------