labelme2coco.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3. import argparse
  4. import glob
  5. import json
  6. import os
  7. import os.path as osp
  8. import sys
  9. import numpy as np
  10. import PIL.ImageDraw
  11. class MyEncoder(json.JSONEncoder):
  12. def default(self, obj):
  13. if isinstance(obj, np.integer):
  14. return int(obj)
  15. elif isinstance(obj, np.floating):
  16. return float(obj)
  17. elif isinstance(obj, np.ndarray):
  18. return obj.tolist()
  19. else:
  20. return super(MyEncoder, self).default(obj)
  21. def images(data, num):
  22. image = {}
  23. image['height'] = data['imageHeight']
  24. image['width'] = data['imageWidth']
  25. image['id'] = num + 1
  26. image['file_name'] = data['imagePath'].split('/')[-1]
  27. return image
  28. def categories(label, labels_list):
  29. category = {}
  30. category['supercategory'] = 'component'
  31. category['id'] = len(labels_list) + 1
  32. category['name'] = label
  33. return category
  34. def annotations_rectangle(iscrowd, points, label, num, label_to_num, count):
  35. annotation = {}
  36. seg_points = np.asarray(points).copy()
  37. seg_points[1, :] = np.asarray(points)[2, :]
  38. seg_points[2, :] = np.asarray(points)[1, :]
  39. annotation['segmentation'] = [list(seg_points.flatten())]
  40. annotation['iscrowd'] = iscrowd
  41. annotation['image_id'] = num + 1
  42. annotation['bbox'] = list(
  43. map(
  44. float,
  45. [
  46. points[0][0],
  47. points[0][1],
  48. points[1][0] - points[0][0],
  49. points[1][1] - points[0][1],
  50. ], ), )
  51. annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
  52. annotation['category_id'] = label_to_num[label]
  53. annotation['id'] = count
  54. return annotation
  55. def annotations_polygon(annotation, iscrowd, height, width, points, label, num,
  56. label_to_num, count):
  57. if len(annotation) == 0:
  58. annotation['segmentation'] = [list(np.asarray(points).flatten())]
  59. annotation['iscrowd'] = iscrowd
  60. annotation['image_id'] = num + 1
  61. annotation['bbox'] = list(map(float, get_bbox(height, width, points)))
  62. annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
  63. annotation['category_id'] = label_to_num[label]
  64. annotation['id'] = count
  65. else:
  66. annotation['segmentation'].append(list(np.asarray(points).flatten()))
  67. box1 = annotation['bbox']
  68. box2 = list(map(float, get_bbox(height, width, points)))
  69. x11, y11, x12, y12 = box1[0], box1[1], box1[0] + box1[2], box1[1] + box1[3]
  70. x21, y21, x22, y22 = box2[0], box2[1], box2[0] + box2[2], box2[1] + box2[3]
  71. x1 = x21 if x11 > x21 else x11
  72. y1 = y21 if y11 > y21 else y11
  73. x2 = x22 if x12 < x22 else x12
  74. y2 = y22 if y12 < y22 else y12
  75. annotation['bbox'] = [x1, y1, x2 - x1, y2 - y1]
  76. def get_bbox(height, width, points):
  77. polygons = points
  78. mask = np.zeros([height, width], dtype=np.uint8)
  79. mask = PIL.Image.fromarray(mask)
  80. xy = list(map(tuple, polygons))
  81. PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
  82. mask = np.array(mask, dtype=bool)
  83. index = np.argwhere(mask == 1)
  84. rows = index[:, 0]
  85. clos = index[:, 1]
  86. left_top_r = np.min(rows)
  87. left_top_c = np.min(clos)
  88. right_bottom_r = np.max(rows)
  89. right_bottom_c = np.max(clos)
  90. return [
  91. left_top_c,
  92. left_top_r,
  93. right_bottom_c - left_top_c,
  94. right_bottom_r - left_top_r,
  95. ]
  96. def deal_json(img_path, json_path):
  97. data_coco = {}
  98. label_to_num = {}
  99. images_list = []
  100. categories_list = []
  101. annotations_list = []
  102. labels_list = []
  103. num = -1
  104. for img_file in os.listdir(img_path):
  105. img_label = img_file.split('.')[0]
  106. if img_label == '':
  107. continue
  108. label_file = osp.join(json_path, img_label + '.json')
  109. assert os.path.exists(label_file), \
  110. 'The .json file of {} is not exists!'.format(img_file)
  111. print('Generating dataset from:', label_file)
  112. num = num + 1
  113. with open(label_file) as f:
  114. data = json.load(f)
  115. images_list.append(images(data, num))
  116. count = 0
  117. lmid_count = {}
  118. for shapes in data['shapes']:
  119. count += 1
  120. label = shapes['label']
  121. part = label.split('_')
  122. iscrowd = int(part[-1][0])
  123. label = label.split('_' + part[-1])[0]
  124. if label not in labels_list:
  125. categories_list.append(categories(label, labels_list))
  126. labels_list.append(label)
  127. label_to_num[label] = len(labels_list)
  128. points = shapes['points']
  129. p_type = shapes['shape_type']
  130. if p_type == 'polygon':
  131. if len(part[-1]) > 1:
  132. lmid = part[-1][1:]
  133. if lmid in lmid_count:
  134. real_count = lmid_count[lmid]
  135. real_anno = None
  136. for anno in annotations_list:
  137. if anno['id'] == real_count:
  138. real_anno = anno
  139. break
  140. annotations_polygon(anno, iscrowd, data['imageHeight'], data[
  141. 'imageWidth'], points, label, num, label_to_num,
  142. real_count)
  143. count -= 1
  144. else:
  145. lmid_count[lmid] = count
  146. anno = {}
  147. annotations_polygon(anno, iscrowd, data['imageHeight'], data[
  148. 'imageWidth'], points, label, num, label_to_num,
  149. count)
  150. annotations_list.append(anno)
  151. else:
  152. anno = {}
  153. annotations_polygon(anno, iscrowd, data['imageHeight'], data[
  154. 'imageWidth'], points, label, num, label_to_num,
  155. count)
  156. annotations_list.append(anno)
  157. if p_type == 'rectangle':
  158. points.append([points[0][0], points[1][1]])
  159. points.append([points[1][0], points[0][1]])
  160. annotations_list.append(
  161. annotations_rectangle(iscrowd, points, label, num,
  162. label_to_num, count))
  163. data_coco['images'] = images_list
  164. data_coco['categories'] = categories_list
  165. data_coco['annotations'] = annotations_list
  166. return data_coco
  167. def main():
  168. parser = argparse.ArgumentParser(
  169. formatter_class=argparse.ArgumentDefaultsHelpFormatter, )
  170. parser.add_argument('--json_input_dir', help='input annotated directory')
  171. parser.add_argument('--image_input_dir', help='image directory')
  172. args = parser.parse_args()
  173. try:
  174. assert os.path.exists(args.json_input_dir)
  175. except AssertionError as e:
  176. print('The json folder does not exist!')
  177. os._exit(0)
  178. try:
  179. assert os.path.exists(args.image_input_dir)
  180. except AssertionError as e:
  181. print('The image folder does not exist!')
  182. os._exit(0)
  183. # Allocate the dataset.
  184. total_num = len(glob.glob(osp.join(args.json_input_dir, '*.json')))
  185. # Deal with the json files.
  186. res_dir = os.path.abspath(os.path.join(args.image_input_dir, '..'))
  187. if not os.path.exists(res_dir + '/annotations'):
  188. os.makedirs(res_dir + '/annotations')
  189. train_data_coco = deal_json(args.image_input_dir, args.json_input_dir)
  190. train_json_path = osp.join(
  191. res_dir + '/annotations',
  192. 'instance_{}.json'.format(
  193. os.path.basename(os.path.abspath(args.image_input_dir))))
  194. json.dump(
  195. train_data_coco,
  196. open(
  197. train_json_path,
  198. 'w'),
  199. indent=4,
  200. cls=MyEncoder)
  201. if __name__ == '__main__':
  202. main()