Source code for zokyo.utils.data_format_conversions

# -*- coding: utf-8 -*-
# Contributors : [srinivas.v@toyotaconnected.co.in,srivathsan.govindarajan@toyotaconnected.co.in,
# harshavardhan.thirupathi@toyotaconnected.co.in,
# ashok.ramadass@toyotaconnected.com ]

from pathlib import Path
import json
import xml.etree.ElementTree as ET


[docs]def coco_std_2_voc(coco_ann_path, save_folder=None, database=None): """ Function convert given standard COCO annotation json file to Pascal VOC annotation. If save_folder is not given then output is saved in the same folder """ coco_ann_path = Path(coco_ann_path) if not database: database = 'Unspecified' if not save_folder: save_folder = coco_ann_path.parent else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') with open(coco_ann_path, 'r') as f: coco_ann = json.load(f) categories = {cat['id']: cat['name'] for cat in coco_ann['categories']} categories = dict(sorted(categories.items())) voc_names = '' for i, cat in categories.items(): voc_names += cat + '\n' with open(f'{save_folder}/voc.names', 'w') as f: f.write(voc_names) for i, img in enumerate(coco_ann['images']): root = ET.Element('annotation') img_path = Path(img['file_name']) fold = ET.Element('folder') fold.text = str(img_path.parent) root.append(fold) file_name = ET.Element('filename') file_name.text = img_path.name root.append(file_name) path = ET.Element('path') path.text = str(img_path) root.append(path) source = ET.Element('source') db = ET.SubElement(source, 'database') db.text = database root.append(source) size = ET.Element('size') width = ET.SubElement(size, 'width') width.text = str(int(img['width'])) height = ET.SubElement(size, 'height') height.text = str(int(img['height'])) depth = ET.SubElement(size, 'depth') depth.text = str(3) root.append(size) for ann in coco_ann['annotations']: if img['id'] == ann['image_id']: obj = ET.Element('object') name = ET.Element('name') name.text = categories[ann['category_id']] obj.append(name) pose = ET.Element('pose') if 'pose' in ann: pose.text = str(ann['pose']) else: pose.text = 'Unspecified' obj.append(pose) truncated = ET.Element('truncated') if 'truncated' in ann: truncated.text = str(ann['truncated']) else: truncated.text = 'Unspecified' obj.append(truncated) bndbox = ET.Element('bndbox') xmin = ET.SubElement(bndbox, 'xmin') xmin.text = str(int(ann['bbox'][0])) ymin = ET.SubElement(bndbox, 'ymin') ymin.text = str(int(ann['bbox'][1])) xmax = ET.SubElement(bndbox, 'xmax') xmax.text = str(int(ann['bbox'][0] + ann['bbox'][2])) ymax = ET.SubElement(bndbox, 'ymax') ymax.text = str(int(ann['bbox'][1] + ann['bbox'][3])) obj.append(bndbox) root.append(obj) tree = ET.ElementTree(root) with open(f'{save_folder}/{i}.xml', 'wb') as f: tree.write(f)
[docs]def voc_2_coco_std(voc_folder_path, save_folder=None, info=None): """ Function convert given Pascal VOC annotations to standard COCO annotation json file. If save_folder is not given then output is saved in the same folder """ voc_folder_path = Path(voc_folder_path) if not info: info = {} if not save_folder: save_folder = voc_folder_path else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') coco_ann = {} voc_names_path = list(voc_folder_path.glob('*.names'))[0] with open(voc_names_path, 'r') as f: voc_names = [n.rstrip('\n') for n in f.readlines()] categories = [{"id": i, "name": cat} for i, cat in enumerate(voc_names, 1)] coco_ann['info'] = info coco_ann['categories'] = categories voc_ann_paths = sorted(list(voc_folder_path.glob('*.xml'))) if len(voc_ann_paths) == 0: raise Exception('Empty Voc directory') imgs = [] anns = [] j = 0 for i, voc_ann_path in enumerate(voc_ann_paths): root = ET.parse(voc_ann_path).getroot() img = {} img['id'] = i size = root.find('size') img['width'] = int(size.find('width').text) img['height'] = int(size.find('height').text) img['file_name'] = root.find('path').text imgs.append(img) for obj in root.findall('object'): ann = {} ann['id'] = j ann['image_id'] = i ann['category_id'] = voc_names.index(obj.find('name').text) + 1 bbox = obj.find('bndbox') x = int(bbox.find('xmin').text) y = int(bbox.find('ymin').text) w = int(bbox.find('xmax').text) - x h = int(bbox.find('ymax').text) - y ann['area'] = w * h ann['bbox'] = [x, y, w, h] j += 1 anns.append(ann) coco_ann['images'] = imgs coco_ann['annotations'] = anns with open(f'{save_folder}/coco_ann.json', 'w') as f: json.dump(coco_ann, f)
[docs]def coco_std_2_coco_toyo(coco_ann_path, save_folder=None): """ Function convert given standard COCO annotation json file to Toyo COCO annotation json files. If save_folder is not given then output is saved in the same folder """ coco_ann_path = Path(coco_ann_path) if not save_folder: save_folder = coco_ann_path.parent else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') with open(coco_ann_path, 'r') as f: coco_ann = json.load(f) coco_toyo_ann = {} coco_toyo_ann['info'] = coco_ann['info'] coco_toyo_ann['categories'] = coco_ann['categories'] for i, img in enumerate(coco_ann['images']): coco_toyo_ann['images'] = [img] anns = [] for j, ann in enumerate(coco_ann['annotations']): if img['id'] == ann['image_id']: anns.append(ann) coco_toyo_ann['annotations'] = anns with open(f'{save_folder}/{i}.json', 'w') as f: json.dump(coco_toyo_ann, f)
[docs]def coco_toyo_2_coco_std(coco_toyo_ann_folder, save_folder=None): """ Function convert given Toyo COCO annotation json files to standard COCO annotation json file. If save_folder is not given then output is saved in the same folder """ coco_toyo_ann_folder = Path(coco_toyo_ann_folder) if not save_folder: save_folder = coco_toyo_ann_folder.parent else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') coco_toyo_ann_paths = sorted(list(coco_toyo_ann_folder.glob('*.json'))) coco_ann = {} imgs = [] anns = [] for _, coco_toyo_ann_path in enumerate(coco_toyo_ann_paths): with open(coco_toyo_ann_path, 'r') as f: coco_toyo_ann = json.load(f) coco_ann['info'] = coco_toyo_ann['info'] coco_ann['categories'] = coco_toyo_ann['categories'] imgs.append(coco_toyo_ann['images'][0]) anns.extend(coco_toyo_ann['annotations']) coco_ann['images'] = sorted(imgs, key=lambda x: x['id']) coco_ann['annotations'] = sorted(anns, key=lambda x: x['id']) with open(f'{save_folder}/coco_ann.json', 'w') as f: json.dump(coco_ann, f)
[docs]def coco_toyo_2_voc(coco_toyo_ann_folder, save_folder=None, database=None): """ Function convert given Toyo COCO annotation json files to Pascal VOC annotation. If save_folder is not given then output is saved in the same folder """ coco_toyo_ann_folder = Path(coco_toyo_ann_folder) if not database: database = 'Unspecified' if not save_folder: save_folder = coco_toyo_ann_folder.parent else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') coco_toyo_ann_paths = sorted(list(coco_toyo_ann_folder.glob('*.json'))) with open(coco_toyo_ann_paths[0], 'r') as f: coco_toyo_ann = json.load(f) categories = {cat['id']: cat['name'] for cat in coco_toyo_ann['categories']} categories = dict(sorted(categories.items())) voc_names = '' for i, cat in categories.items(): voc_names += cat + '\n' with open(f'{save_folder}/voc.names', 'w') as f: f.write(voc_names) for i, coco_toyo_ann_path in enumerate(coco_toyo_ann_paths): with open(coco_toyo_ann_path, 'r') as f: coco_toyo_ann = json.load(f) img = coco_toyo_ann['images'][0] root = ET.Element('annotation') img_path = Path(img['file_name']) fold = ET.Element('folder') fold.text = str(img_path.parent) root.append(fold) file_name = ET.Element('filename') file_name.text = img_path.name root.append(file_name) path = ET.Element('path') path.text = str(img_path) root.append(path) source = ET.Element('source') db = ET.SubElement(source, 'database') db.text = database root.append(source) size = ET.Element('size') width = ET.SubElement(size, 'width') width.text = str(int(img['width'])) height = ET.SubElement(size, 'height') height.text = str(int(img['height'])) depth = ET.SubElement(size, 'depth') depth.text = str(3) root.append(size) for ann in coco_toyo_ann['annotations']: if img['id'] == ann['image_id']: obj = ET.Element('object') name = ET.Element('name') name.text = categories[ann['category_id']] obj.append(name) pose = ET.Element('pose') if 'pose' in ann: pose.text = str(ann['pose']) else: pose.text = 'Unspecified' obj.append(pose) truncated = ET.Element('truncated') if 'truncated' in ann: truncated.text = str(ann['truncated']) else: truncated.text = 'Unspecified' obj.append(truncated) bndbox = ET.Element('bndbox') xmin = ET.SubElement(bndbox, 'xmin') xmin.text = str(int(ann['bbox'][0])) ymin = ET.SubElement(bndbox, 'ymin') ymin.text = str(int(ann['bbox'][1])) xmax = ET.SubElement(bndbox, 'xmax') xmax.text = str(int(ann['bbox'][0] + ann['bbox'][2])) ymax = ET.SubElement(bndbox, 'ymax') ymax.text = str(int(ann['bbox'][1] + ann['bbox'][3])) obj.append(bndbox) root.append(obj) tree = ET.ElementTree(root) with open(f'{save_folder}/{coco_toyo_ann_path.stem}.xml', 'wb') as f: tree.write(f)
[docs]def voc_2_coco_toyo(voc_folder_path, save_folder=None, info=None): """ Function convert given Pascal VOC annotation to Toyo COCO annotation json files. If save_folder is not given then output is saved in the same folder """ voc_folder_path = Path(voc_folder_path) if not info: info = {} if not save_folder: save_folder = voc_folder_path else: save_folder = Path(save_folder) if not save_folder.is_dir(): raise Exception('Save path should be a directory') coco_toyo_ann = {} voc_names_path = list(voc_folder_path.glob('*.names'))[0] with open(voc_names_path, 'r') as f: voc_names = [n.rstrip('\n') for n in f.readlines()] categories = [{"id": i, "name": cat} for i, cat in enumerate(voc_names, 1)] coco_toyo_ann['info'] = info coco_toyo_ann['categories'] = categories voc_ann_paths = sorted(list(voc_folder_path.glob('*.xml'))) if len(voc_ann_paths) == 0: raise Exception('Empty Voc directory') imgs = [] anns = [] j = 0 for i, voc_ann_path in enumerate(voc_ann_paths): root = ET.parse(voc_ann_path).getroot() img = {} img['id'] = i size = root.find('size') img['width'] = int(size.find('width').text) img['height'] = int(size.find('height').text) img['fil_ename'] = root.find('path').text imgs.append(img) for obj in root.findall('object'): ann = {} ann['id'] = j ann['image_id'] = i ann['category_id'] = voc_names.index(obj.find('name').text) + 1 bbox = obj.find('bndbox') x = int(bbox.find('xmin').text) y = int(bbox.find('ymin').text) w = int(bbox.find('xmax').text) - x h = int(bbox.find('ymax').text) - y ann['area'] = w * h ann['bbox'] = [x, y, w, h] j += 1 anns.append(ann) coco_toyo_ann['images'] = imgs coco_toyo_ann['annotations'] = anns imgs = [] anns = [] with open(f'{save_folder}/{i}.json', 'w') as f: json.dump(coco_toyo_ann, f)