def write(self, loc): f = File(loc, self.root, suffix='.json') imfile = self.imfiles[loc] lmdict = LabelmeDict.gen_data(imfile) for label, ann in self.data[loc].items(): a = ann.copy() DictTool.isub(a, ['img']) shape = LabelmeDict.gen_shape(json.dumps(a, ensure_ascii=False), a['points'], a['shape_type'], group_id=a['group_id'], flags=a['flags']) lmdict['shapes'].append(shape) f.write(lmdict, indent=2)
def add_shape(name, refdict, add_keys, drop_keys=('bbox', )): """ 生成一个标注框 """ msgdict = {'category_name': name} msgdict.update(add_keys) DictTool.ior(msgdict, refdict) DictTool.isub(msgdict, drop_keys) bbox = [round_int(v * scale) for v in refdict['bbox']] if 'size' in msgdict: x = round_unit(msgdict['size'], 0.5) msgdict['size'] = round_int( x) if (x * 10) % 10 < 1 else x # 没有小数的时候,优先展示为11,而不是11.0 if 'color' in msgdict: # 把color映射为直观的(r, g, b) # 这个pdf解析器获取的color,不一定精确等于原值,可能会有偏差,小一个像素 v = msgdict['color'] msgdict['color'] = (v // 256 // 256, (v // 256) % 256, v % 256) if 'origin' in msgdict: msgdict['origin'] = [round_int(v) for v in msgdict['origin']] sp = LabelmeDict.gen_shape(json.dumps(msgdict), bbox) shapes.append(sp)
def to_coco_gt_dict(self, categories=None): """ 将labelme转成 coco gt 标注的格式 分两种大情况 1、一种是raw原始数据转labelme标注后,首次转coco格式,这种编号等相关数据都可以重新生成 raw_data --可视化--> labelme --转存--> coco 2、还有种原来就是coco,转labelme修改标注后,又要再转回coco,这种应该尽量保存原始值 coco --> labelme --手动修改--> labelme' --> coco' 这种在coco转labelme时,会做一些特殊标记,方便后续转回coco 3、 1, 2两种情况是可以连在一起,然后形成 labelme 和 coco 之间的多次互转的 :param categories: 类别 默认只设一个类别 {'id': 0, 'name': 'text', 'supercategory'} 支持自定义,所有annotations的category_id :return: gt_dict 注意,如果对文件顺序、ann顺序有需求的,请先自行操作self.data数据后,再调用该to_coco函数 对image_id、annotation_id有需求的,需要使用CocoData进一步操作 """ from pyxllib.data.coco import CocoGtData if not categories: if 'categories' in self.extdata: # coco 转过来的labelme,存储有原始的 categories categories = self.extdata['categories'] else: categories = [{'id': 0, 'name': 'text', 'supercategory': ''}] # 1 第一轮遍历:结构处理 jsonfile, lmdict --> data(image, shapes) img_id, ann_id, data = 0, 0, [] for jsonfile, lmdict in self.rp2data.items(): # 1.0 升级为字典类型 lmdict = LabelmeDict.update_labelattr(lmdict, points=True) for sp in lmdict['shapes']: # label转成字典 sp['label'] = json.loads(sp['label']) # 1.1 找shapes里的image image = None # 1.1.1 xltype='image' for sp in filter(lambda x: x.get('xltype', None) == 'image', lmdict['shapes']): image = DictTool.json_loads(sp['label']) if not image: raise ValueError(sp['label']) # TODO 删除 coco_eval 等字段? del image['xltype'] break # 1.1.2 shapes里没有图像级标注则生成一个 if image is None: # TODO file_name 加上相对路径? image = CocoGtData.gen_image(-1, lmdict['imagePath'], lmdict['imageHeight'], lmdict['imageWidth']) img_id = max(img_id, image.get('id', -1)) # 1.2 遍历shapes shapes = [] for sp in lmdict['shapes']: label = sp['label'] if 'xltype' not in label: # 普通的标注框 d = sp['label'].copy() # DictTool.isub_(d, '') ann_id = max(ann_id, d.get('id', -1)) shapes.append(d) elif label['xltype'] == 'image': # image,图像级标注数据;之前已经处理了,这里可以跳过 pass elif label['xltype'] == 'seg': # seg,衍生的分割标注框,在转回coco时可以丢弃 pass else: raise ValueError data.append([image, shapes]) # 2 第二轮遍历:处理id等问题 images, annotations = [], [] for image, shapes in data: # 2.1 image if image.get('id', -1) == -1: img_id += 1 image['id'] = img_id images.append(image) # 2.2 annotations for sp in shapes: sp['image_id'] = img_id if sp.get('id', -1) == -1: ann_id += 1 sp['id'] = ann_id # 如果没有框类别,会默认设置一个。 (强烈建议外部业务功能代码自行设置好category_id) if 'category_id' not in sp: sp['category_id'] = categories[0]['id'] DictTool.isub(sp, ['category_name']) ann = CocoGtData.gen_annotation(**sp) annotations.append(ann) # 3 result gt_dict = CocoGtData.gen_gt_dict(images, annotations, categories) return gt_dict