def apply(self): extractor = self._extractor images_dir = osp.join(self._save_dir, MotPath.IMAGE_DIR) os.makedirs(images_dir, exist_ok=True) self._images_dir = images_dir anno_dir = osp.join(self._save_dir, 'gt') os.makedirs(anno_dir, exist_ok=True) anno_file = osp.join(anno_dir, MotPath.GT_FILENAME) with open(anno_file, 'w', encoding="utf-8") as csv_file: writer = csv.DictWriter(csv_file, fieldnames=MotPath.FIELDS) track_id_mapping = {-1: -1} for idx, item in enumerate(extractor): log.debug("Converting item '%s'", item.id) frame_id = cast(item.id, int, 1 + idx) for anno in item.annotations: if anno.type != AnnotationType.bbox: continue track_id = int(anno.attributes.get('track_id', -1)) if track_id not in track_id_mapping: track_id_mapping[track_id] = len(track_id_mapping) track_id = track_id_mapping[track_id] writer.writerow({ 'frame_id': frame_id, 'track_id': track_id, 'x': anno.x, 'y': anno.y, 'w': anno.w, 'h': anno.h, 'confidence': int(anno.attributes.get('ignored') != True), 'class_id': 1 + cast(anno.label, int, -2), 'visibility': float( anno.attributes.get('visibility', 1 - float( anno.attributes.get('occluded', False) ) ) ) }) if self._save_images: if item.has_image and item.image.has_data: self._save_image(item, osp.join(self._images_dir, '%06d%s' % (frame_id, self._find_image_ext(item)))) else: log.debug("Item '%s' has no image", item.id) labels_file = osp.join(anno_dir, MotPath.LABELS_FILE) with open(labels_file, 'w', encoding='utf-8') as f: f.write('\n'.join(l.name for l in extractor.categories()[AnnotationType.label]) )
def _convert_label_categories(self, obj): converted = { 'labels': [], } for label in obj.items: converted['labels'].append({ 'name': cast(label.name, str), 'parent': cast(label.parent, str), }) return converted
def _convert_annotation(self, obj): assert isinstance(obj, Annotation) ann_json = { 'id': cast(obj.id, int), 'type': cast(obj.type.name, str), 'attributes': obj.attributes, 'group': cast(obj.group, int, 0), } return ann_json
def _parse_attr(cls, value): if value == 'true': return True elif value == 'false': return False elif str(cast(value, int, 0)) == value: return int(value) elif str(cast(value, float, 0)) == value: return float(value) else: return value
def save_categories(self, dataset): label_categories = dataset.categories().get(AnnotationType.label) if label_categories is None: return for idx, cat in enumerate(label_categories.items): self.categories.append({ 'id': 1 + idx, 'name': cast(cat.name, str, ''), 'supercategory': cast(cat.parent, str, ''), })
def _is_float(value): if isinstance(value, str): casted = cast(value, float) if casted is not None: if cast(casted, str) == value: return True return False elif isinstance(value, float): cast(value, float) return True return False
def save_categories(self, dataset): label_categories = dataset.categories().get(AnnotationType.label) if label_categories is None: return for idx, cat in enumerate(label_categories.items): self.categories.append({ 'id': 1 + idx, 'name': cast(cat.name, str, ''), 'supercategory': cast(cat.parent, str, ''), 'isthing': 0, # TODO: can't represent this information yet })
def _parse_attributes(attr_str): parsed = [] if not attr_str: return parsed for attr in [a.strip() for a in cls._escape(attr_str).split(',')]: if not attr: continue if '=' in attr: name, value = attr.split('=', maxsplit=1) if value.lower() in {'true', 'false'}: value = value.lower() == 'true' elif 1 < len(value) and value[0] == '"' and value[-1] == '"': value = value[1:-1] else: for t in [int, float]: casted = cast(value, t) if casted is not None and str(casted) == value: value = casted break if isinstance(value, str): value = cls._unescape(value) parsed.append((cls._unescape(name), value)) else: parsed.append((cls._unescape(attr), True)) return parsed
def _write_item(self, item, index): if not self._context._reindex: index = cast(item.attributes.get('frame'), int, index) image_info = OrderedDict([ ("id", str(index)), ]) filename = item.id + CvatPath.IMAGE_EXT image_info["name"] = filename if item.has_image: size = item.image.size if size: h, w = size image_info["width"] = str(w) image_info["height"] = str(h) if self._context._save_images: self._context._save_image( item, osp.join(self._context._images_dir, filename)) else: log.debug("Item '%s' has no image info", item.id) self._writer.open_image(image_info) for ann in item.annotations: if ann.type in { AnnotationType.points, AnnotationType.polyline, AnnotationType.polygon, AnnotationType.bbox }: self._write_shape(ann) elif ann.type == AnnotationType.label: self._write_tag(ann) else: continue self._writer.close_image()
def _convert_label_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), }) return converted
def _write_item(self, item, index): image_info = OrderedDict([ ("id", str(cast(item.id, int, index))), ]) if item.has_image: size = item.image.size if size: h, w = size image_info["width"] = str(w) image_info["height"] = str(h) filename = item.image.filename if self._context._save_images: filename = self._save_image(item) image_info["name"] = filename else: log.debug("Item '%s' has no image info" % item.id) self._writer.open_image(image_info) for ann in item.annotations: if ann.type in {AnnotationType.points, AnnotationType.polyline, AnnotationType.polygon, AnnotationType.bbox}: self._write_shape(ann) elif ann.type == AnnotationType.label: self._write_tag(ann) else: continue self._writer.close_image()
def _convert_caption_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'caption': cast(obj.caption, str), }) return converted
def _get_image_id(self, item): image_id = self._image_ids.get(item.id) if image_id is None: image_id = cast(item.attributes.get('id'), int, len(self._image_ids) + 1) self._image_ids[item.id] = image_id return image_id
def _write_item_annotations(self, item): key_id_data = self._key_id_data item_id = cast(item.attributes.get('frame'), int) if item_id is None or self._context._reindex: item_id = len(key_id_data['videos']) + 1 item_key = str(uuid.uuid4()) key_id_data['videos'][item_key] = item_id item_user_info = { k: item.attributes.get(k, default_v) for k, default_v in self._default_user_info.items() } item_ann_data = { 'description': item.attributes.get('description', ''), 'key': item_key, 'tags': [], 'objects': [], 'figures': [], } self._export_item_attributes(item, item_ann_data, item_user_info) self._export_item_annotations(item, item_ann_data, item_user_info) ann_path = osp.join(self._ann_dir, item.id + '.pcd.json') os.makedirs(osp.dirname(ann_path), exist_ok=True) dump_json_file(ann_path, item_ann_data, indent=True)
def match_dm_item(item, task_data, root_hint=None): is_video = task_data.meta['task']['mode'] == 'interpolation' frame_number = None if frame_number is None and item.has_image: frame_number = task_data.match_frame(item.image.path, root_hint) if frame_number is None: frame_number = task_data.match_frame(item.id, root_hint) if frame_number is None: frame_number = cast(item.attributes.get('frame', item.id), int) if frame_number is None and is_video: frame_number = cast(osp.basename(item.id)[len('frame_'):], int) if not frame_number in task_data.frame_info: raise Exception("Could not match item id: '%s' with any task frame" % item.id) return frame_number
def _convert_bbox_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), 'bbox': [float(p) for p in obj.get_bbox()], }) return converted
def _convert_polygon_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), 'points': [float(p) for p in obj.points], }) return converted
def _convert_points_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), 'points': [float(p) for p in obj.points], 'visibility': [int(v.value) for v in obj.visibility], }) return converted
def _convert_cuboid_3d_object(self, obj): converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), 'position': [float(p) for p in obj.position], 'rotation': [float(p) for p in obj.rotation], 'scale': [float(p) for p in obj.scale] }) return converted
def _save_image(self, item, index): if item.image.filename: frame_id = osp.splitext(item.image.filename)[0] else: frame_id = item.id frame_id = cast(frame_id, int, index) image_filename = '%06d%s' % (frame_id, MotPath.IMAGE_EXT) save_image(osp.join(self._images_dir, image_filename), item.image.data)
def _convert_shape_object(self, obj): assert isinstance(obj, _Shape) converted = self._convert_annotation(obj) converted.update({ 'label_id': cast(obj.label, int), 'points': [float(p) for p in obj.points], 'z_order': obj.z_order, }) return converted
def convert_instance(self, instance, item): ann, polygons, mask, bbox = instance is_crowd = mask is not None if is_crowd: segmentation = { 'counts': list(int(c) for c in mask['counts']), 'size': list(int(c) for c in mask['size']) } else: segmentation = [list(map(float, p)) for p in polygons] area = 0 if segmentation: if item.has_image: h, w = item.image.size else: # NOTE: here we can guess the image size as # it is only needed for the area computation w = bbox[0] + bbox[2] h = bbox[1] + bbox[3] rles = mask_utils.frPyObjects(segmentation, h, w) if is_crowd: rles = [rles] else: rles = mask_utils.merge(rles) area = mask_utils.area(rles) else: _, _, w, h = bbox segmentation = [] area = w * h elem = { 'id': self._get_ann_id(ann), 'image_id': self._get_image_id(item), 'category_id': cast(ann.label, int, -1) + 1, 'segmentation': segmentation, 'area': float(area), 'bbox': [round(float(n), _COORDINATE_ROUNDING_DIGITS) for n in bbox], 'iscrowd': int(is_crowd), } if 'score' in ann.attributes: try: elem['score'] = float(ann.attributes['score']) except Exception as e: log.warning("Item '%s': failed to convert attribute " "'score': %e" % (item.id, e)) if self._context._allow_attributes: attrs = self._convert_attributes(ann) if attrs: elem['attributes'] = attrs return elem
def _parse_label_count(s: str) -> Tuple[str, int]: label, count = s.split(':', maxsplit=1) count = cast(count, int, default=None) if not label: raise argparse.ArgumentError(None, "Class name cannot be empty") if count is None or count < 0: raise argparse.ArgumentError(None, f"Class '{label}' count is invalid") return label, count
def _convert_points_categories(self, obj): converted = { 'items': [], } for label_id, item in obj.items.items(): converted['items'].append({ 'label_id': int(label_id), 'labels': [cast(label, str) for label in item.labels], 'joints': [list(map(int, j)) for j in item.joints], }) return converted
def save_annotations(self, item): if not item.has_image: return ann_filename = item.id + CocoPath.PANOPTIC_EXT segments_info = list() masks = [] next_id = self._min_ann_id for ann in item.annotations: if ann.type != AnnotationType.mask: continue if not ann.id: ann.id = next_id next_id += 1 segment_info = {} segment_info['id'] = ann.id segment_info['category_id'] = cast(ann.label, int, -1) + 1 segment_info['area'] = float(ann.get_area()) segment_info['bbox'] = [float(p) for p in ann.get_bbox()] segment_info['iscrowd'] = cast(ann.attributes.get("is_crowd"), int, 0) segments_info.append(segment_info) masks.append(ann) if not masks: return pan_format = mask_tools.merge_masks((m.image, m.id) for m in masks) save_image(osp.join(self._context._segmentation_dir, ann_filename), mask_tools.index2bgr(pan_format), create_dir=True) elem = { 'image_id': self._get_image_id(item), 'file_name': ann_filename, 'segments_info': segments_info } self.annotations.append(elem)
def _convert_points_categories(self, obj): converted = { 'items': [], } for label_id, item in obj.items.items(): converted['items'].append({ 'label_id': int(label_id), 'labels': [cast(label, str) for label in item.labels], 'adjacent': [int(v) for v in item.adjacent], }) return converted
def save_categories(self, dataset): label_categories = dataset.categories().get(AnnotationType.label) if label_categories is None: return point_categories = dataset.categories().get(AnnotationType.points) for idx, label_cat in enumerate(label_categories.items): cat = { 'id': 1 + idx, 'name': cast(label_cat.name, str, ''), 'supercategory': cast(label_cat.parent, str, ''), 'keypoints': [], 'skeleton': [], } if point_categories is not None: kp_cat = point_categories.items.get(idx) if kp_cat is not None: cat.update({ 'keypoints': [str(l) for l in kp_cat.labels], 'skeleton': [list(map(int, j)) for j in kp_cat.joints], }) self.categories.append(cat)
def generate_next_name(names, basename, sep='.', suffix='', default=None): pattern = re.compile(r'%s(?:%s(\d+))?%s' % \ tuple(map(re.escape, [basename, sep, suffix]))) matches = [match for match in (pattern.match(n) for n in names) if match] max_idx = max([cast(match[1], int, 0) for match in matches], default=None) if max_idx is None: if default is not None: idx = sep + str(default) else: idx = '' else: idx = sep + str(max_idx + 1) return basename + idx + suffix
def save_image_info(self, item, filename): h = 0 w = 0 if item.has_image and item.image.size: h, w = item.image.size self._data['images'].append({ 'id': self._get_image_id(item), 'width': int(w), 'height': int(h), 'file_name': cast(filename, str, ''), 'license': 0, 'flickr_url': '', 'coco_url': '', 'date_captured': 0, })
def _convert_mask_object(self, obj): converted = self._convert_annotation(obj) if isinstance(obj, RleMask): rle = obj.rle else: rle = mask_utils.encode( np.require(obj.image, dtype=np.uint8, requirements='F')) converted.update({ 'label_id': cast(obj.label, int), 'rle': { # serialize as compressed COCO mask 'counts': rle['counts'].decode('ascii'), 'size': list(int(c) for c in rle['size']), } }) return converted