dota_to_coco.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import sys
  15. import os.path as osp
  16. import json
  17. import glob
  18. import cv2
  19. import argparse
  20. # add python path of PadleDetection to sys.path
  21. parent_path = osp.abspath(osp.join(__file__, *(['..'] * 3)))
  22. if parent_path not in sys.path:
  23. sys.path.append(parent_path)
  24. from ppdet.modeling.bbox_utils import poly2rbox
  25. from ppdet.utils.logger import setup_logger
  26. logger = setup_logger(__name__)
  27. class_name_15 = [
  28. 'plane', 'baseball-diamond', 'bridge', 'ground-track-field',
  29. 'small-vehicle', 'large-vehicle', 'ship', 'tennis-court',
  30. 'basketball-court', 'storage-tank', 'soccer-ball-field', 'roundabout',
  31. 'harbor', 'swimming-pool', 'helicopter'
  32. ]
  33. class_name_16 = [
  34. 'plane', 'baseball-diamond', 'bridge', 'ground-track-field',
  35. 'small-vehicle', 'large-vehicle', 'ship', 'tennis-court',
  36. 'basketball-court', 'storage-tank', 'soccer-ball-field', 'roundabout',
  37. 'harbor', 'swimming-pool', 'helicopter', 'container-crane'
  38. ]
  39. def dota_2_coco(image_dir,
  40. txt_dir,
  41. json_path='dota_coco.json',
  42. is_obb=True,
  43. dota_version='v1.0'):
  44. """
  45. image_dir: image dir
  46. txt_dir: txt label dir
  47. json_path: json save path
  48. is_obb: is obb or not
  49. dota_version: dota_version v1.0 or v1.5 or v2.0
  50. """
  51. img_lists = glob.glob("{}/*.png".format(image_dir))
  52. data_dict = {}
  53. data_dict['images'] = []
  54. data_dict['categories'] = []
  55. data_dict['annotations'] = []
  56. inst_count = 0
  57. # categories
  58. class_name2id = {}
  59. if dota_version == 'v1.0':
  60. for class_id, class_name in enumerate(class_name_15):
  61. class_name2id[class_name] = class_id + 1
  62. single_cat = {
  63. 'id': class_id + 1,
  64. 'name': class_name,
  65. 'supercategory': class_name
  66. }
  67. data_dict['categories'].append(single_cat)
  68. for image_id, img_path in enumerate(img_lists):
  69. single_image = {}
  70. basename = osp.basename(img_path)
  71. single_image['file_name'] = basename
  72. single_image['id'] = image_id
  73. img = cv2.imread(img_path)
  74. height, width, _ = img.shape
  75. single_image['width'] = width
  76. single_image['height'] = height
  77. # add image
  78. data_dict['images'].append(single_image)
  79. # annotations
  80. anno_txt_path = osp.join(txt_dir, osp.splitext(basename)[0] + '.txt')
  81. if not osp.exists(anno_txt_path):
  82. logger.warning('path of {} not exists'.format(anno_txt_path))
  83. for line in open(anno_txt_path):
  84. line = line.strip()
  85. # skip
  86. if line.find('imagesource') >= 0 or line.find('gsd') >= 0:
  87. continue
  88. # x1,y1,x2,y2,x3,y3,x4,y4 class_name, is_different
  89. single_obj_anno = line.split(' ')
  90. assert len(single_obj_anno) == 10
  91. single_obj_poly = [float(e) for e in single_obj_anno[0:8]]
  92. single_obj_classname = single_obj_anno[8]
  93. single_obj_different = int(single_obj_anno[9])
  94. single_obj = {}
  95. single_obj['category_id'] = class_name2id[single_obj_classname]
  96. single_obj['segmentation'] = []
  97. single_obj['segmentation'].append(single_obj_poly)
  98. single_obj['iscrowd'] = 0
  99. # rbox or bbox
  100. if is_obb:
  101. polys = [single_obj_poly]
  102. rboxs = poly2rbox(polys)
  103. rbox = rboxs[0].tolist()
  104. single_obj['bbox'] = rbox
  105. single_obj['area'] = rbox[2] * rbox[3]
  106. else:
  107. xmin, ymin, xmax, ymax = min(single_obj_poly[0::2]), min(single_obj_poly[1::2]), \
  108. max(single_obj_poly[0::2]), max(single_obj_poly[1::2])
  109. width, height = xmax - xmin, ymax - ymin
  110. single_obj['bbox'] = xmin, ymin, width, height
  111. single_obj['area'] = width * height
  112. single_obj['image_id'] = image_id
  113. data_dict['annotations'].append(single_obj)
  114. single_obj['id'] = inst_count
  115. inst_count = inst_count + 1
  116. # add annotation
  117. data_dict['annotations'].append(single_obj)
  118. with open(json_path, 'w') as f:
  119. json.dump(data_dict, f)
  120. if __name__ == '__main__':
  121. parser = argparse.ArgumentParser(description='dota anno to coco')
  122. parser.add_argument('--images_dir', help='path_to_images')
  123. parser.add_argument('--label_dir', help='path_to_labelTxt', type=str)
  124. parser.add_argument(
  125. '--json_path',
  126. help='save json path',
  127. type=str,
  128. default='dota_coco.json')
  129. parser.add_argument(
  130. '--is_obb', help='is_obb or not', type=bool, default=True)
  131. parser.add_argument(
  132. '--dota_version',
  133. help='dota_version, v1.0 or v1.5 or v2.0',
  134. type=str,
  135. default='v1.0')
  136. args = parser.parse_args()
  137. # process
  138. dota_2_coco(args.images_dir, args.label_dir, args.json_path, args.is_obb,
  139. args.dota_version)
  140. print('done!')