def _load_recognition_items(self): items = {} with open(self._path, encoding='utf-8') as f: for line in f: line = line.strip() objects = line.split(', ') if len(objects) == 2: image = objects[0] captions = [] for caption in objects[1:]: if caption[0] != '\"' or caption[-1] != '\"': log.warning("Line %s: unexpected number " "of quotes" % line) else: captions.append(caption.replace('\\', '')[1:-1]) else: image = objects[0][:-1] captions = [] item_id = osp.splitext(image)[0] image_path = osp.join(osp.dirname(self._path), IcdarPath.IMAGES_DIR, image) if item_id not in items: items[item_id] = DatasetItem(item_id, subset=self._subset, image=image_path) annotations = items[item_id].annotations for caption in captions: annotations.append(Caption(caption)) return items
def transform_item(self, item): annotations = item.annotations anns = [p for p in annotations if 'text' in p.attributes] for ann in anns: annotations.append(Caption(ann.attributes['text'])) annotations.remove(ann) return item.wrap(annotations=annotations)
def test_can_import_captions(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='word_1', subset='train', image=np.ones((10, 15, 3)), annotations=[ Caption('PROPER'), ]), DatasetItem(id='word_2', subset='train', image=np.ones((10, 15, 3)), annotations=[ Caption("Canon"), ]), ]) dataset = Dataset.import_from( osp.join(DUMMY_DATASET_DIR, 'word_recognition'), 'icdar_word_recognition') compare_datasets(self, expected_dataset, dataset)
def test_can_save_and_load_captions_with_quotes(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='1', image=np.ones((5, 5, 3)), annotations=[Caption('caption\"')]) ]) with TestDir() as test_dir: self._test_save_and_load( expected_dataset, partial(IcdarWordRecognitionConverter.convert, save_images=True), test_dir, 'icdar_word_recognition')
def test_can_save_and_load_captions(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', image=np.ones((10, 15, 3)), annotations=[ Caption('caption 0'), ]), DatasetItem(id=2, subset='train', image=np.ones((10, 15, 3)), annotations=[ Caption('caption_1'), ]), ]) with TestDir() as test_dir: self._test_save_and_load( expected_dataset, partial(IcdarWordRecognitionConverter.convert, save_images=True), test_dir, 'icdar_word_recognition')
def _load_annotations(item): parsed = item['annotations'] loaded = [] for ann in parsed: ann_id = ann.get('id') ann_type = AnnotationType[ann['type']] attributes = ann.get('attributes') group = ann.get('group') label_id = ann.get('label_id') z_order = ann.get('z_order') points = ann.get('points') if ann_type == AnnotationType.label: loaded.append( Label(label=label_id, id=ann_id, attributes=attributes, group=group)) elif ann_type == AnnotationType.mask: rle = ann['rle'] rle['counts'] = rle['counts'].encode('ascii') loaded.append( RleMask(rle=rle, label=label_id, id=ann_id, attributes=attributes, group=group, z_order=z_order)) elif ann_type == AnnotationType.polyline: loaded.append( PolyLine(points, label=label_id, id=ann_id, attributes=attributes, group=group, z_order=z_order)) elif ann_type == AnnotationType.polygon: loaded.append( Polygon(points, label=label_id, id=ann_id, attributes=attributes, group=group, z_order=z_order)) elif ann_type == AnnotationType.bbox: x, y, w, h = ann['bbox'] loaded.append( Bbox(x, y, w, h, label=label_id, id=ann_id, attributes=attributes, group=group, z_order=z_order)) elif ann_type == AnnotationType.points: loaded.append( Points(points, label=label_id, id=ann_id, attributes=attributes, group=group, z_order=z_order)) elif ann_type == AnnotationType.caption: caption = ann.get('caption') loaded.append( Caption(caption, id=ann_id, attributes=attributes, group=group)) elif ann_type == AnnotationType.cuboid_3d: loaded.append( Cuboid3d(ann.get('position'), ann.get('rotation'), ann.get('scale'), label=label_id, id=ann_id, attributes=attributes, group=group)) else: raise NotImplementedError() return loaded
def _load_annotations(self, ann, image_info=None, parsed_annotations=None): if parsed_annotations is None: parsed_annotations = [] ann_id = ann['id'] attributes = ann.get('attributes', {}) if 'score' in ann: attributes['score'] = ann['score'] group = ann_id # make sure all tasks' annotations are merged if self._task is CocoTask.instances or \ self._task is CocoTask.person_keypoints or \ self._task is CocoTask.stuff: label_id = self._get_label_id(ann) attributes['is_crowd'] = bool(ann['iscrowd']) if self._task is CocoTask.person_keypoints: keypoints = ann['keypoints'] points = [] visibility = [] for x, y, v in take_by(keypoints, 3): points.append(x) points.append(y) visibility.append(v) parsed_annotations.append( Points(points, visibility, label=label_id, id=ann_id, attributes=attributes, group=group)) segmentation = ann['segmentation'] if segmentation and segmentation != [[]]: rle = None if isinstance(segmentation, list): if not self._merge_instance_polygons: # polygon - a single object can consist of multiple parts for polygon_points in segmentation: parsed_annotations.append( Polygon(points=polygon_points, label=label_id, id=ann_id, attributes=attributes, group=group)) else: # merge all parts into a single mask RLE rle = self._lazy_merged_mask(segmentation, image_info['height'], image_info['width']) elif isinstance(segmentation['counts'], list): # uncompressed RLE img_h = image_info['height'] img_w = image_info['width'] mask_h, mask_w = segmentation['size'] if img_h == mask_h and img_w == mask_w: rle = self._lazy_merged_mask([segmentation], mask_h, mask_w) else: log.warning( "item #%s: mask #%s " "does not match image size: %s vs. %s. " "Skipping this annotation.", image_info['id'], ann_id, (mask_h, mask_w), (img_h, img_w)) else: # compressed RLE rle = segmentation if rle: parsed_annotations.append( RleMask(rle=rle, label=label_id, id=ann_id, attributes=attributes, group=group)) else: x, y, w, h = ann['bbox'] parsed_annotations.append( Bbox(x, y, w, h, label=label_id, id=ann_id, attributes=attributes, group=group)) elif self._task is CocoTask.labels: label_id = self._get_label_id(ann) parsed_annotations.append( Label(label=label_id, id=ann_id, attributes=attributes, group=group)) elif self._task is CocoTask.captions: caption = ann['caption'] parsed_annotations.append( Caption(caption, id=ann_id, attributes=attributes, group=group)) else: raise NotImplementedError() return parsed_annotations
def test_annotation_comparison(self): a = Dataset.from_iterable( [ DatasetItem( id=1, annotations=[ Caption('hello'), # unmatched Caption('world', group=5), Label(2, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 3, 4, label=4, z_order=1, attributes={ 'score': 1.0, }), Bbox(5, 6, 7, 8, group=5), Points([1, 2, 2, 0, 1, 1], label=0, z_order=4), Mask(label=3, z_order=2, image=np.ones((2, 3))), ]), ], categories=['a', 'b', 'c', 'd']) b = Dataset.from_iterable( [ DatasetItem( id=1, annotations=[ Caption('world', group=5), Label(2, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 3, 4, label=4, z_order=1, attributes={ 'score': 1.0, }), Bbox(5, 6, 7, 8, group=5), Bbox(5, 6, 7, 8, group=5), # unmatched Points([1, 2, 2, 0, 1, 1], label=0, z_order=4), Mask(label=3, z_order=2, image=np.ones((2, 3))), ]), ], categories=['a', 'b', 'c', 'd']) comp = ExactComparator() matched, unmatched, _, _, errors = comp.compare_datasets(a, b) self.assertEqual(6, len(matched), matched) self.assertEqual(2, len(unmatched), unmatched) self.assertEqual(0, len(errors), errors)
def test_stats(self): dataset = Dataset.from_iterable([ DatasetItem(id=1, image=np.ones((5, 5, 3)), annotations=[ Caption('hello'), Caption('world'), Label(2, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 2, 2, label=2, attributes={ 'score': 0.5, }), Bbox(5, 6, 2, 2, attributes={ 'x': 1, 'y': '3', 'occluded': True, }), Points([1, 2, 2, 0, 1, 1], label=0), Mask(label=3, image=np.array([ [0, 0, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ])), ]), DatasetItem(id=2, image=np.ones((2, 4, 3)), annotations=[ Label(2, attributes={ 'x': 2, 'y': '2', }), Bbox(1, 2, 2, 2, label=3, attributes={ 'score': 0.5, }), Bbox(5, 6, 2, 2, attributes={ 'x': 2, 'y': '3', 'occluded': False, }), ]), DatasetItem(id=3), DatasetItem(id='2.2', image=np.ones((2, 4, 3))), ], categories=['label_%s' % i for i in range(4)]) expected = { 'images count': 4, 'annotations count': 10, 'unannotated images count': 2, 'unannotated images': ['3', '2.2'], 'annotations by type': { 'label': { 'count': 2, }, 'polygon': { 'count': 0, }, 'polyline': { 'count': 0, }, 'bbox': { 'count': 4, }, 'mask': { 'count': 1, }, 'points': { 'count': 1, }, 'caption': { 'count': 2, }, 'cuboid_3d': {'count': 0}, }, 'annotations': { 'labels': { 'count': 6, 'distribution': { 'label_0': [1, 1/6], 'label_1': [0, 0.0], 'label_2': [3, 3/6], 'label_3': [2, 2/6], }, 'attributes': { 'x': { 'count': 2, # annotations with no label are skipped 'values count': 2, 'values present': ['1', '2'], 'distribution': { '1': [1, 1/2], '2': [1, 1/2], }, }, 'y': { 'count': 2, # annotations with no label are skipped 'values count': 1, 'values present': ['2'], 'distribution': { '2': [2, 2/2], }, }, # must not include "special" attributes like "occluded" } }, 'segments': { 'avg. area': (4 * 2 + 9 * 1) / 3, 'area distribution': [ {'min': 4.0, 'max': 4.5, 'count': 2, 'percent': 2/3}, {'min': 4.5, 'max': 5.0, 'count': 0, 'percent': 0.0}, {'min': 5.0, 'max': 5.5, 'count': 0, 'percent': 0.0}, {'min': 5.5, 'max': 6.0, 'count': 0, 'percent': 0.0}, {'min': 6.0, 'max': 6.5, 'count': 0, 'percent': 0.0}, {'min': 6.5, 'max': 7.0, 'count': 0, 'percent': 0.0}, {'min': 7.0, 'max': 7.5, 'count': 0, 'percent': 0.0}, {'min': 7.5, 'max': 8.0, 'count': 0, 'percent': 0.0}, {'min': 8.0, 'max': 8.5, 'count': 0, 'percent': 0.0}, {'min': 8.5, 'max': 9.0, 'count': 1, 'percent': 1/3}, ], 'pixel distribution': { 'label_0': [0, 0.0], 'label_1': [0, 0.0], 'label_2': [4, 4/17], 'label_3': [13, 13/17], }, } }, } actual = compute_ann_statistics(dataset) self.assertEqual(expected, actual)
def test_can_compare_projects(self): # just a smoke test label_categories1 = LabelCategories.from_iterable(['x', 'a', 'b', 'y']) mask_categories1 = MaskCategories.generate(len(label_categories1)) point_categories1 = PointsCategories() for index, _ in enumerate(label_categories1.items): point_categories1.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) dataset1 = Dataset.from_iterable([ DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), Label(2, id=3, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 3, 4, label=0, id=4, z_order=1, attributes={ 'score': 1.0, }), Bbox(5, 6, 7, 8, id=5, group=5), Points([1, 2, 2, 0, 1, 1], label=0, id=5, z_order=4), Mask(label=3, id=5, z_order=2, image=np.ones((2, 3))), ]), DatasetItem(id=21, subset='train', annotations=[ Caption('test'), Label(2), Bbox(1, 2, 3, 4, label=2, id=42, group=42) ]), DatasetItem(id=2, subset='val', annotations=[ PolyLine([1, 2, 3, 4, 5, 6, 7, 8], id=11, z_order=1), Polygon([1, 2, 3, 4, 5, 6, 7, 8], id=12, z_order=4), ]), DatasetItem(id=42, subset='test', attributes={'a1': 5, 'a2': '42'}), DatasetItem(id=42), DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories1, AnnotationType.mask: mask_categories1, AnnotationType.points: point_categories1, }) label_categories2 = LabelCategories.from_iterable(['a', 'b', 'x', 'y']) mask_categories2 = MaskCategories.generate(len(label_categories2)) point_categories2 = PointsCategories() for index, _ in enumerate(label_categories2.items): point_categories2.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) dataset2 = Dataset.from_iterable([ DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), Label(2, id=3, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 3, 4, label=1, id=4, z_order=1, attributes={ 'score': 1.0, }), Bbox(5, 6, 7, 8, id=5, group=5), Points([1, 2, 2, 0, 1, 1], label=0, id=5, z_order=4), Mask(label=3, id=5, z_order=2, image=np.ones((2, 3))), ]), DatasetItem(id=21, subset='train', annotations=[ Caption('test'), Label(2), Bbox(1, 2, 3, 4, label=3, id=42, group=42) ]), DatasetItem(id=2, subset='val', annotations=[ PolyLine([1, 2, 3, 4, 5, 6, 7, 8], id=11, z_order=1), Polygon([1, 2, 3, 4, 5, 6, 7, 8], id=12, z_order=4), ]), DatasetItem(id=42, subset='test', attributes={'a1': 5, 'a2': '42'}), DatasetItem(id=42), DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories2, AnnotationType.mask: mask_categories2, AnnotationType.points: point_categories2, }) with TestDir() as test_dir: with DiffVisualizer(save_dir=test_dir, comparator=DistanceComparator(iou_threshold=0.8), ) as visualizer: visualizer.save(dataset1, dataset2) self.assertNotEqual(0, os.listdir(osp.join(test_dir)))
def test_dataset(self): label_categories = LabelCategories(attributes={'a', 'b', 'score'}) for i in range(5): label_categories.add('cat' + str(i), attributes={'x', 'y'}) mask_categories = MaskCategories( generate_colormap(len(label_categories.items))) points_categories = PointsCategories() for index, _ in enumerate(label_categories.items): points_categories.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) return Dataset.from_iterable( [ DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), Label(2, id=3, attributes={ 'x': 1, 'y': '2', }), Bbox(1, 2, 3, 4, label=4, id=4, z_order=1, attributes={ 'score': 1.0, }), Bbox(5, 6, 7, 8, id=5, group=5, attributes={ 'a': 1.5, 'b': 'text', }), Points([1, 2, 2, 0, 1, 1], label=0, id=5, z_order=4, attributes={ 'x': 1, 'y': '2', }), Mask(label=3, id=5, z_order=2, image=np.ones((2, 3)), attributes={ 'x': 1, 'y': '2', }), ]), DatasetItem(id=21, subset='train', annotations=[ Caption('test'), Label(2), Bbox(1, 2, 3, 4, label=5, id=42, group=42) ]), DatasetItem( id=2, subset='val', annotations=[ PolyLine([1, 2, 3, 4, 5, 6, 7, 8], id=11, z_order=1), Polygon([1, 2, 3, 4, 5, 6, 7, 8], id=12, z_order=4), ]), DatasetItem(id=1, subset='test', annotations=[ Cuboid3d([1.0, 2.0, 3.0], [2.0, 2.0, 4.0], [1.0, 3.0, 4.0], id=6, label=0, attributes={'occluded': True}, group=6) ]), DatasetItem( id=42, subset='test', attributes={ 'a1': 5, 'a2': '42' }), DatasetItem(id=42), DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories, AnnotationType.mask: mask_categories, AnnotationType.points: points_categories, })