# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import os.path as osp import json import glob import cv2 import numpy as np from PIL import Image import logging import argparse # add python path of PadleDetection to sys.path parent_path = osp.abspath(osp.join(__file__, *(['..'] * 3))) if parent_path not in sys.path: sys.path.append(parent_path) from ppdet.modeling.bbox_utils import poly_to_rbox from ppdet.utils.logger import setup_logger logger = setup_logger(__name__) class_name_15 = [ 'plane', 'baseball-diamond', 'bridge', 'ground-track-field', 'small-vehicle', 'large-vehicle', 'ship', 'tennis-court', 'basketball-court', 'storage-tank', 'soccer-ball-field', 'roundabout', 'harbor', 'swimming-pool', 'helicopter' ] class_name_16 = [ 'plane', 'baseball-diamond', 'bridge', 'ground-track-field', 'small-vehicle', 'large-vehicle', 'ship', 'tennis-court', 'basketball-court', 'storage-tank', 'soccer-ball-field', 'roundabout', 'harbor', 'swimming-pool', 'helicopter', 'container-crane' ] def dota_2_coco(image_dir, txt_dir, json_path='dota_coco.json', is_obb=True, dota_version='v1.0'): """ image_dir: image dir txt_dir: txt label dir json_path: json save path is_obb: is obb or not dota_version: dota_version v1.0 or v1.5 or v2.0 """ img_lists = glob.glob("{}/*.png".format(image_dir)) data_dict = {} data_dict['images'] = [] data_dict['categories'] = [] data_dict['annotations'] = [] inst_count = 0 # categories class_name2id = {} if dota_version == 'v1.0': for class_id, class_name in enumerate(class_name_15): class_name2id[class_name] = class_id + 1 single_cat = { 'id': class_id + 1, 'name': class_name, 'supercategory': class_name } data_dict['categories'].append(single_cat) for image_id, img_path in enumerate(img_lists): single_image = {} basename = osp.basename(img_path) single_image['file_name'] = basename single_image['id'] = image_id img = cv2.imread(img_path) height, width, _ = img.shape single_image['width'] = width single_image['height'] = height # add image data_dict['images'].append(single_image) # annotations anno_txt_path = osp.join(txt_dir, osp.splitext(basename)[0] + '.txt') if not osp.exists(anno_txt_path): logger.warn('path of {} not exists'.format(anno_txt_path)) for line in open(anno_txt_path): line = line.strip() # skip if line.find('imagesource') >= 0 or line.find('gsd') >= 0: continue # x1,y1,x2,y2,x3,y3,x4,y4 class_name, is_different single_obj_anno = line.split(' ') assert len(single_obj_anno) == 10 single_obj_poly = [float(e) for e in single_obj_anno[0:8]] single_obj_classname = single_obj_anno[8] single_obj_different = int(single_obj_anno[9]) single_obj = {} single_obj['category_id'] = class_name2id[single_obj_classname] single_obj['segmentation'] = [] single_obj['segmentation'].append(single_obj_poly) single_obj['iscrowd'] = 0 # rbox or bbox if is_obb: polys = [single_obj_poly] rboxs = poly_to_rbox(polys) rbox = rboxs[0].tolist() single_obj['bbox'] = rbox single_obj['area'] = rbox[2] * rbox[3] else: xmin, ymin, xmax, ymax = min(single_obj_poly[0::2]), min(single_obj_poly[1::2]), \ max(single_obj_poly[0::2]), max(single_obj_poly[1::2]) width, height = xmax - xmin, ymax - ymin single_obj['bbox'] = xmin, ymin, width, height single_obj['area'] = width * height single_obj['image_id'] = image_id data_dict['annotations'].append(single_obj) single_obj['id'] = inst_count inst_count = inst_count + 1 # add annotation data_dict['annotations'].append(single_obj) with open(json_path, 'w') as f: json.dump(data_dict, f) if __name__ == '__main__': parser = argparse.ArgumentParser(description='dota anno to coco') parser.add_argument('--images_dir', help='path_to_images') parser.add_argument('--label_dir', help='path_to_labelTxt', type=str) parser.add_argument( '--json_path', help='save json path', type=str, default='dota_coco.json') parser.add_argument( '--is_obb', help='is_obb or not', type=bool, default=True) parser.add_argument( '--dota_version', help='dota_version, v1.0 or v1.5 or v2.0', type=str, default='v1.0') args = parser.parse_args() # process dota_2_coco(args.images_dir, args.label_dir, args.json_path, args.is_obb, args.dota_version) print('done!')