json 转 coco 数据集格式

impo

rt os import json import PIL.Image import PIL.ImageDraw import numpy as np from labelme2coco.utils import create_dir, list_jsons_recursively from labelme2coco.image_utils import read_image_shape_as_dict class Labelme2Coco: def __init__(self, labelme_folder='', save_json_path='./new.json'): self.save_json_path = save_json_path self.images = [] self.categories = [] self.annotations = [] self.label_set = set() self.annID = 1 self.height = 0 self.width = 0 save_json_dir = os.path.dirname(save_json_path) create_dir(save_json_dir) _, labelme_json = list_jsons_recursively(labelme_folder) self.labelme_json = labelme_json self.save_json() def data_transfer(self): for num, json_path in enumerate(self.labelme_json): with open(json_path, 'r') as fp: data = json.load(fp) self.images.append(self.image(data, num, json_path)) for shapes in data['shapes']: label = shapes['label'] if label not in self.label_set: self.categories.append(self.category(label)) self.label_set.add(label) points = shapes['points'] self.annotations.append(self.annotation(points, label, num)) self.annID += 1 def image(self, data, num, json_path): image = {} _, img_extension = os.path.splitext(data["imagePath"]) image_path = json_path.replace(".json", img_extension) img_shape = read_image_shape_as_dict(image_path) height, width = img_shape['height'], img_shape['width'] image['height'] = height image['width'] = width image['id'] = int(num + 1) image['file_name'] = os.path.basename(image_path) print(image_path) self.height = height self.width = width return image def category(self, label): category = { 'supercategory': label, 'id': int(len(self.label_set) + 1), 'name': label } return category def annotation(self, points, label, num): annotation = { 'iscrowd': 0, 'image_id': int(num + 1), 'bbox': list(map(float, self.getbbox(points))), 'segmentation': [np.asarray(points).flatten().tolist()], 'category_id': self.getcatid(label), 'id': int(self.annID), 'area': self.height * self.width } return annotation def getcatid(self, label): for category in self.categories: if label == category['name']: return category['id'] return -1 def getbbox(self, points): polygons = points mask = self.polygons_to_mask([self.height, self.width], polygons) return self.mask2box(mask) def mask2box(self, mask): index = np.argwhere(mask == 1) rows = index[:, 0] cols = index[:, 1] left_top_row = np.min(rows) left_top_col = np.min(cols) right_bottom_row = np.max(rows) right_bottom_col = np.max(cols) return [left_top_col, left_top_row, right_bottom_col - left_top_col, right_bottom_row - left_top_row] def polygons_to_mask(self, img_shape, polygons): mask = np.zeros(img_shape, 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) return mask def data2coco(self): data_coco = { 'images': self.images, 'categories': self.categories, 'annotations': self.annotations } return data_coco def save_json(self): self.data_transfer() self.data_coco = self.data2coco() json.dump(self.data_coco, open(self.save_json_path, 'w', encoding='utf-8'), indent=4, separators=(',', ': '), cls=MyEncoder) 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) if __name__ == "__main__": labelme_folder = "./datasets/images_json/train" save_json_path = "./train_coco_format.json" labelme2coco(labelme_folder, save_json_path)