|
|
@@ -0,0 +1,226 @@
|
|
|
+#!/usr/bin/env python
|
|
|
+# coding: utf-8
|
|
|
+import argparse
|
|
|
+import glob
|
|
|
+import json
|
|
|
+import os
|
|
|
+import os.path as osp
|
|
|
+import sys
|
|
|
+
|
|
|
+import numpy as np
|
|
|
+import PIL.ImageDraw
|
|
|
+
|
|
|
+
|
|
|
+class MyEncoder(json.JSONEncoder):
|
|
|
+ def default(self, obj):
|
|
|
+ if isinstance(obj, np.integer):
|
|
|
+ return int(obj)
|
|
|
+ elif isinstance(obj, np.floating):
|
|
|
+ return float(obj)
|
|
|
+ elif isinstance(obj, np.ndarray):
|
|
|
+ return obj.tolist()
|
|
|
+ else:
|
|
|
+ return super(MyEncoder, self).default(obj)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def images(data, num):
|
|
|
+ image = {}
|
|
|
+ image['height'] = data['imageHeight']
|
|
|
+ image['width'] = data['imageWidth']
|
|
|
+ image['id'] = num + 1
|
|
|
+ image['file_name'] = data['imagePath'].split('/')[-1]
|
|
|
+ return image
|
|
|
+
|
|
|
+
|
|
|
+def categories(label, labels_list):
|
|
|
+ category = {}
|
|
|
+ category['supercategory'] = 'component'
|
|
|
+ category['id'] = len(labels_list) + 1
|
|
|
+ category['name'] = label
|
|
|
+ return category
|
|
|
+
|
|
|
+
|
|
|
+def annotations_rectangle(iscrowd, points, label, num, label_to_num, count):
|
|
|
+ annotation = {}
|
|
|
+ seg_points = np.asarray(points).copy()
|
|
|
+ seg_points[1, :] = np.asarray(points)[2, :]
|
|
|
+ seg_points[2, :] = np.asarray(points)[1, :]
|
|
|
+ annotation['segmentation'] = [list(seg_points.flatten())]
|
|
|
+ annotation['iscrowd'] = iscrowd
|
|
|
+ annotation['image_id'] = num + 1
|
|
|
+ annotation['bbox'] = list(
|
|
|
+ map(
|
|
|
+ float,
|
|
|
+ [
|
|
|
+ points[0][0],
|
|
|
+ points[0][1],
|
|
|
+ points[1][0] - points[0][0],
|
|
|
+ points[1][1] - points[0][1],
|
|
|
+ ], ), )
|
|
|
+ annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
|
|
|
+ annotation['category_id'] = label_to_num[label]
|
|
|
+ annotation['id'] = count
|
|
|
+ return annotation
|
|
|
+
|
|
|
+
|
|
|
+def annotations_polygon(annotation, iscrowd, height, width, points, label, num,
|
|
|
+ label_to_num, count):
|
|
|
+
|
|
|
+ if len(annotation) == 0:
|
|
|
+ annotation['segmentation'] = [list(np.asarray(points).flatten())]
|
|
|
+ annotation['iscrowd'] = iscrowd
|
|
|
+ annotation['image_id'] = num + 1
|
|
|
+ annotation['bbox'] = list(map(float, get_bbox(height, width, points)))
|
|
|
+ annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
|
|
|
+ annotation['category_id'] = label_to_num[label]
|
|
|
+ annotation['id'] = count
|
|
|
+ else:
|
|
|
+ annotation['segmentation'].append(list(np.asarray(points).flatten()))
|
|
|
+ box1 = annotation['bbox']
|
|
|
+ box2 = list(map(float, get_bbox(height, width, points)))
|
|
|
+ x11, y11, x12, y12 = box1[0], box1[1], box1[0] + box1[2], box1[1] + box1[3]
|
|
|
+ x21, y21, x22, y22 = box2[0], box2[1], box2[0] + box2[2], box2[1] + box2[3]
|
|
|
+ x1 = x21 if x11 > x21 else x11
|
|
|
+ y1 = y21 if y11 > y21 else y11
|
|
|
+ x2 = x22 if x12 < x22 else x12
|
|
|
+ y2 = y22 if y12 < y22 else y12
|
|
|
+ annotation['bbox'] = [x1, y1, x2 - x1, y2 - y1]
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def get_bbox(height, width, points):
|
|
|
+ polygons = points
|
|
|
+ mask = np.zeros([height, width], dtype=np.uint8)
|
|
|
+ mask = PIL.Image.fromarray(mask)
|
|
|
+ xy = list(map(tuple, polygons))
|
|
|
+ PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
|
|
|
+ mask = np.array(mask, dtype=bool)
|
|
|
+ index = np.argwhere(mask == 1)
|
|
|
+ rows = index[:, 0]
|
|
|
+ clos = index[:, 1]
|
|
|
+ left_top_r = np.min(rows)
|
|
|
+ left_top_c = np.min(clos)
|
|
|
+ right_bottom_r = np.max(rows)
|
|
|
+ right_bottom_c = np.max(clos)
|
|
|
+ return [
|
|
|
+ left_top_c,
|
|
|
+ left_top_r,
|
|
|
+ right_bottom_c - left_top_c,
|
|
|
+ right_bottom_r - left_top_r,
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def deal_json(img_path, json_path):
|
|
|
+ data_coco = {}
|
|
|
+ label_to_num = {}
|
|
|
+ images_list = []
|
|
|
+ categories_list = []
|
|
|
+ annotations_list = []
|
|
|
+ labels_list = []
|
|
|
+ num = -1
|
|
|
+ for img_file in os.listdir(img_path):
|
|
|
+ img_label = img_file.split('.')[0]
|
|
|
+ if img_label == '':
|
|
|
+ continue
|
|
|
+ label_file = osp.join(json_path, img_label + '.json')
|
|
|
+ assert os.path.exists(label_file), \
|
|
|
+ 'The .json file of {} is not exists!'.format(img_file)
|
|
|
+ print('Generating dataset from:', label_file)
|
|
|
+ num = num + 1
|
|
|
+ with open(label_file) as f:
|
|
|
+ data = json.load(f)
|
|
|
+ images_list.append(images(data, num))
|
|
|
+ count = 0
|
|
|
+ lmid_count = {}
|
|
|
+ for shapes in data['shapes']:
|
|
|
+ count += 1
|
|
|
+ label = shapes['label']
|
|
|
+ part = label.split('_')
|
|
|
+ iscrowd = int(part[-1][0])
|
|
|
+ label = label.split('_' + part[-1])[0]
|
|
|
+ if label not in labels_list:
|
|
|
+ categories_list.append(categories(label, labels_list))
|
|
|
+ labels_list.append(label)
|
|
|
+ label_to_num[label] = len(labels_list)
|
|
|
+ points = shapes['points']
|
|
|
+ p_type = shapes['shape_type']
|
|
|
+ if p_type == 'polygon':
|
|
|
+ if len(part[-1]) > 1:
|
|
|
+ lmid = part[-1][1:]
|
|
|
+ if lmid in lmid_count:
|
|
|
+ real_count = lmid_count[lmid]
|
|
|
+ real_anno = None
|
|
|
+ for anno in annotations_list:
|
|
|
+ if anno['id'] == real_count:
|
|
|
+ real_anno = anno
|
|
|
+ break
|
|
|
+ annotations_polygon(anno, iscrowd, data['imageHeight'], data[
|
|
|
+ 'imageWidth'], points, label, num, label_to_num,
|
|
|
+ real_count)
|
|
|
+ count -= 1
|
|
|
+ else:
|
|
|
+ lmid_count[lmid] = count
|
|
|
+ anno = {}
|
|
|
+ annotations_polygon(anno, iscrowd, data['imageHeight'], data[
|
|
|
+ 'imageWidth'], points, label, num, label_to_num,
|
|
|
+ count)
|
|
|
+ annotations_list.append(anno)
|
|
|
+ else:
|
|
|
+ anno = {}
|
|
|
+ annotations_polygon(anno, iscrowd, data['imageHeight'], data[
|
|
|
+ 'imageWidth'], points, label, num, label_to_num,
|
|
|
+ count)
|
|
|
+ annotations_list.append(anno)
|
|
|
+ if p_type == 'rectangle':
|
|
|
+ points.append([points[0][0], points[1][1]])
|
|
|
+ points.append([points[1][0], points[0][1]])
|
|
|
+ annotations_list.append(
|
|
|
+ annotations_rectangle(iscrowd, points, label, num,
|
|
|
+ label_to_num, count))
|
|
|
+ data_coco['images'] = images_list
|
|
|
+ data_coco['categories'] = categories_list
|
|
|
+ data_coco['annotations'] = annotations_list
|
|
|
+ return data_coco
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ parser = argparse.ArgumentParser(
|
|
|
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter, )
|
|
|
+ parser.add_argument('--json_input_dir', help='input annotated directory')
|
|
|
+ parser.add_argument('--image_input_dir', help='image directory')
|
|
|
+ args = parser.parse_args()
|
|
|
+ try:
|
|
|
+ assert os.path.exists(args.json_input_dir)
|
|
|
+ except AssertionError as e:
|
|
|
+ print('The json folder does not exist!')
|
|
|
+ os._exit(0)
|
|
|
+ try:
|
|
|
+ assert os.path.exists(args.image_input_dir)
|
|
|
+ except AssertionError as e:
|
|
|
+ print('The image folder does not exist!')
|
|
|
+ os._exit(0)
|
|
|
+
|
|
|
+ # Allocate the dataset.
|
|
|
+ total_num = len(glob.glob(osp.join(args.json_input_dir, '*.json')))
|
|
|
+
|
|
|
+ # Deal with the json files.
|
|
|
+ res_dir = os.path.abspath(os.path.join(args.image_input_dir, '..'))
|
|
|
+ if not os.path.exists(res_dir + '/annotations'):
|
|
|
+ os.makedirs(res_dir + '/annotations')
|
|
|
+ train_data_coco = deal_json(args.image_input_dir, args.json_input_dir)
|
|
|
+ train_json_path = osp.join(
|
|
|
+ res_dir + '/annotations',
|
|
|
+ 'instance_{}.json'.format(
|
|
|
+ os.path.basename(os.path.abspath(args.image_input_dir))))
|
|
|
+ json.dump(
|
|
|
+ train_data_coco,
|
|
|
+ open(
|
|
|
+ train_json_path,
|
|
|
+ 'w'),
|
|
|
+ indent=4,
|
|
|
+ cls=MyEncoder)
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ main()
|