def _check_groups(self, annotations): check_groups = [] for check_group_raw in self.conf.groups: check_group = set(l[0] for l in check_group_raw) optional = set(l[0] for l in check_group_raw if l[1]) check_groups.append((check_group, optional)) def _check_group(group_labels, group): for check_group, optional in check_groups: common = check_group & group_labels real_miss = check_group - common - optional extra = group_labels - check_group if common and (extra or real_miss): self.add_item_error(WrongGroupError, group_labels, check_group, group) break groups = find_instances(annotations) for group in groups: group_labels = set() for ann in group: if not hasattr(ann, 'label'): continue label = self._get_label_name(ann.label) if ann.group: group_labels.add(label) else: _check_group({label}, [ann]) if not group_labels: continue _check_group(group_labels, group)
def _make_mergers(self, sources): def _make(c, **kwargs): kwargs.update(attr.asdict(self.conf)) fields = attr.fields_dict(c) return c(**{ k: v for k, v in kwargs.items() if k in fields }, context=self) def _for_type(t, **kwargs): if t is AnnotationType.label: return _make(LabelMerger, **kwargs) elif t is AnnotationType.bbox: return _make(BboxMerger, **kwargs) elif t is AnnotationType.mask: return _make(MaskMerger, **kwargs) elif t is AnnotationType.polygon: return _make(PolygonMerger, **kwargs) elif t is AnnotationType.polyline: return _make(LineMerger, **kwargs) elif t is AnnotationType.points: return _make(PointsMerger, **kwargs) elif t is AnnotationType.caption: return _make(CaptionsMerger, **kwargs) else: raise NotImplementedError("Type %s is not supported" % t) instance_map = {} for s in sources: s_instances = find_instances(s) for inst in s_instances: inst_bbox = max_bbox([a for a in inst if a.type in {AnnotationType.polygon, AnnotationType.mask, AnnotationType.bbox} ]) for ann in inst: instance_map[id(ann)] = [inst, inst_bbox] self._mergers = { t: _for_type(t, instance_map=instance_map) for t in AnnotationType }
def find_instances(cls, annotations): return anno_tools.find_instances(cls.find_instance_anns(annotations))
def _find_instances(annotations): return find_instances( a for a in annotations if a.type in {AnnotationType.bbox, AnnotationType.mask})
def find_instances(annotations): return find_instances( a for a in annotations if a.type in {AnnotationType.polygon, AnnotationType.mask})
def _save_item_annotations( self, item, label_description_writer, bbox_description_writer, mask_description_writer, label_categories, image_meta, ): next_box_id = 0 existing_box_ids = { annotation.attributes['box_id'] for annotation in item.annotations if annotation.type is AnnotationType.mask if 'box_id' in annotation.attributes } for instance in find_instances(item.annotations): instance_box = next( (a for a in instance if a.type is AnnotationType.bbox), None) for annotation in instance: if annotation.type is AnnotationType.label: label_description_writer.writerow({ 'ImageID': item.id, 'LabelName': label_categories[annotation.label].name, 'Confidence': str(annotation.attributes.get('score', 1)), }) elif annotation.type is AnnotationType.bbox: if item.has_image and item.image.size is not None: image_meta[item.id] = item.image.size height, width = item.image.size else: log.warning( "Can't encode box for item '%s' due to missing image file", item.id) continue bbox_description_writer.writerow({ 'ImageID': item.id, 'LabelName': label_categories[annotation.label].name, 'Confidence': str(annotation.attributes.get('score', 1)), 'XMin': annotation.x / width, 'YMin': annotation.y / height, 'XMax': (annotation.x + annotation.w) / width, 'YMax': (annotation.y + annotation.h) / height, **{ bool_attr.oid_name: int(annotation.attributes.get(bool_attr.datumaro_name, -1)) for bool_attr in OpenImagesPath.BBOX_BOOLEAN_ATTRIBUTES }, }) elif annotation.type is AnnotationType.mask: mask_dir = osp.join(self._save_dir, OpenImagesPath.MASKS_DIR, item.subset) box_id_str = annotation.attributes.get('box_id') if box_id_str: if _RE_INVALID_PATH_COMPONENT.fullmatch(box_id_str): raise UnsupportedBoxIdError(item_id=item.id, box_id=box_id_str) else: # find a box ID that isn't used in any other annotations while True: box_id_str = format(next_box_id, "08x") next_box_id += 1 if box_id_str not in existing_box_ids: break label_name = label_categories[annotation.label].name mask_file_name = '%s_%s_%s.png' % ( make_file_name(item.id), make_file_name(label_name), box_id_str, ) box_coords = {} if instance_box is not None: if item.has_image and item.image.size is not None: image_meta[item.id] = item.image.size height, width = item.image.size box_coords = { 'BoxXMin': instance_box.x / width, 'BoxXMax': (instance_box.x + instance_box.w) / width, 'BoxYMin': instance_box.y / height, 'BoxYMax': (instance_box.y + instance_box.h) / height, } else: log.warning( "Can't encode box coordinates for a mask" " for item '%s' due to missing image file", item.id) mask_description_writer.writerow({ 'MaskPath': mask_file_name, 'ImageID': item.id, 'LabelName': label_name, 'BoxID': box_id_str, **box_coords, 'PredictedIoU': annotation.attributes.get('predicted_iou', ''), }) save_image(osp.join(mask_dir, mask_file_name), annotation.image, create_dir=True)