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), ], categories=['label_%s' % i for i in range(4)]) expected = { 'images count': 3, 'annotations count': 10, 'unannotated images count': 1, 'unannotated images': ['3'], 'annotations by type': { 'label': { 'count': 2, }, 'polygon': { 'count': 0, }, 'polyline': { 'count': 0, }, 'bbox': { 'count': 4, }, 'mask': { 'count': 1, }, 'points': { 'count': 1, }, 'caption': { 'count': 2, }, }, '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, # unnotations with no label are skipped 'values count': 2, 'values present': ['1', '2'], 'distribution': { '1': [1, 1/2], '2': [1, 1/2], }, }, 'y': { 'count': 2, # unnotations 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 _load_items(self, path): items = {} images_dir = osp.join(self._dataset_dir, self._subset, LfwPath.IMAGES_DIR) with open(path, encoding='utf-8') as f: for line in f: pair = line.strip().split() if len(pair) == 3: image1 = self.get_image_name(pair[0], pair[1]) image2 = self.get_image_name(pair[0], pair[2]) if image1 not in items: items[image1] = DatasetItem( id=image1, subset=self._subset, image=osp.join(images_dir, image1 + LfwPath.IMAGE_EXT), attributes={ 'positive_pairs': [], 'negative_pairs': [] }) if image2 not in items: items[image2] = DatasetItem( id=image2, subset=self._subset, image=osp.join(images_dir, image2 + LfwPath.IMAGE_EXT), attributes={ 'positive_pairs': [], 'negative_pairs': [] }) attributes = items[image1].attributes attributes['positive_pairs'].append(image2) elif len(pair) == 4: image1 = self.get_image_name(pair[0], pair[1]) image2 = self.get_image_name(pair[2], pair[3]) if image1 not in items: items[image1] = DatasetItem( id=image1, subset=self._subset, image=osp.join(images_dir, image1 + LfwPath.IMAGE_EXT), attributes={ 'positive_pairs': [], 'negative_pairs': [] }) if image2 not in items: items[image2] = DatasetItem( id=image2, subset=self._subset, image=osp.join(images_dir, image2 + LfwPath.IMAGE_EXT), attributes={ 'positive_pairs': [], 'negative_pairs': [] }) attributes = items[image1].attributes attributes['negative_pairs'].append(image2) landmarks_file = osp.join(self._dataset_dir, self._subset, LfwPath.LANDMARKS_FILE) if osp.isfile(landmarks_file): with open(landmarks_file, encoding='utf-8') as f: for line in f: line = line.split('\t') item_id = line[0] if item_id.endswith(LfwPath.IMAGE_EXT): item_id = item_id[:-len(LfwPath.IMAGE_EXT)] if item_id not in items: items[item_id] = DatasetItem(id=item_id, subset=self._subset, image=osp.join( images_dir, line[0]), attributes={ 'positive_pairs': [], 'negative_pairs': [] }) annotations = items[item_id].annotations annotations.append(Points([float(p) for p in line[1:]])) return items
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_can_match_shapes(self): source0 = Dataset.from_iterable([ DatasetItem(1, annotations=[ # unique Bbox(1, 2, 3, 4, label=1), # common Mask(label=3, z_order=2, image=np.array([ [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 0], ])), Polygon([1, 0, 3, 2, 1, 2]), # an instance with keypoints Bbox(4, 5, 2, 4, label=2, z_order=1, group=1), Points([5, 6], label=0, group=1), Points([6, 8], label=1, group=1), PolyLine([1, 1, 2, 1, 3, 1]), ]), ], categories=['a', 'b', 'c']) source1 = Dataset.from_iterable([ DatasetItem(1, annotations=[ # common Mask(label=3, image=np.array([ [0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], ])), Polygon([0, 2, 2, 0, 2, 1]), # an instance with keypoints Bbox(4, 4, 2, 5, label=2, z_order=1, group=2), Points([5.5, 6.5], label=0, group=2), Points([6, 8], label=1, group=2), PolyLine([1, 1.5, 2, 1.5]), ]), ], categories=['a', 'b', 'c']) source2 = Dataset.from_iterable([ DatasetItem(1, annotations=[ # common Mask(label=3, z_order=3, image=np.array([ [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 0], ])), Polygon([3, 1, 2, 2, 0, 1]), # an instance with keypoints, one is missing Bbox(3, 6, 2, 3, label=2, z_order=4, group=3), Points([4.5, 5.5], label=0, group=3), PolyLine([1, 1.25, 3, 1, 4, 2]), ]), ], categories=['a', 'b', 'c']) expected = Dataset.from_iterable([ DatasetItem(1, annotations=[ # unique Bbox(1, 2, 3, 4, label=1), # common # nearest to mean bbox Mask(label=3, z_order=3, image=np.array([ [0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], ])), Polygon([1, 0, 3, 2, 1, 2]), # an instance with keypoints Bbox(4, 5, 2, 4, label=2, z_order=4, group=1), Points([5, 6], label=0, group=1), Points([6, 8], label=1, group=1), PolyLine([1, 1.25, 3, 1, 4, 2]), ]), ], categories=['a', 'b', 'c']) merger = IntersectMerge(conf={'quorum': 1, 'pairwise_dist': 0.1}) merged = merger([source0, source1, source2]) compare_datasets(self, expected, merged, ignored_attrs={'score'}) self.assertEqual( [ NoMatchingAnnError(item_id=('1', ''), sources={2}, ann=source0.get('1').annotations[5]), NoMatchingAnnError(item_id=('1', ''), sources={1, 2}, ann=source0.get('1').annotations[0]), ], sorted((e for e in merger.errors if isinstance(e, NoMatchingAnnError)), key=lambda e: len(e.sources)) )
def test_dataset(self): label_categories = LabelCategories() for i in range(5): label_categories.add('cat' + str(i)) 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), 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, 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=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, })
def __iter__(self): return iter([ DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=0, label=1, group=4, attributes={'occluded': True}), Polygon([5, 0, 9, 0, 5, 5], z_order=0, label=2, group=4, attributes={'occluded': False}), Points([1, 1, 3, 2, 2, 3], z_order=0, label=2, attributes={ 'occluded': False, 'a1': 'x', 'a2': 42 }), Label(1), Label(2, attributes={ 'a1': 'y', 'a2': 44 }), ]), DatasetItem(id=1, subset='s1', annotations=[ PolyLine([0, 0, 4, 0, 4, 4], z_order=0, label=3, group=4, attributes={'occluded': False}), Bbox(5, 0, 1, 9, z_order=0, label=3, group=4, attributes={'occluded': False}), ]), DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=1, label=3, group=4, attributes={'occluded': False}), ]), DatasetItem(id=3, subset='s3', image=Image(path='3.jpg', size=(2, 4))), ])
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)) else: raise NotImplementedError() return loaded
def test_can_compare_projects(self): # just a smoke test label_categories1 = LabelCategories.from_iterable(['x', 'a', 'b', 'y']) mask_categories1 = MaskCategories.make_default(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.make_default(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 DatasetDiffVisualizer( 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_can_save_and_load(self): source_dataset = Dataset.from_iterable( [ DatasetItem(id='1', subset='train', image=np.ones((8, 8, 3)), annotations=[ Bbox(0, 2, 4, 2, label=0), Points([ 3.2, 3.12, 4.11, 3.2, 2.11, 2.5, 3.5, 2.11, 3.8, 2.13 ], label=0), ]), DatasetItem(id='2', subset='train', image=np.ones((10, 10, 3)), annotations=[ Points([ 4.23, 4.32, 5.34, 4.45, 3.54, 3.56, 4.52, 3.51, 4.78, 3.34 ], label=1), ]), DatasetItem(id='3', subset='train', image=np.ones((8, 8, 3)), annotations=[Label(2)]), DatasetItem(id='4', subset='train', image=np.ones((10, 10, 3)), annotations=[ Bbox(0, 2, 4, 2, label=3), Points([ 3.2, 3.12, 4.11, 3.2, 2.11, 2.5, 3.5, 2.11, 3.8, 2.13 ], label=3), ]), DatasetItem(id='a/5', subset='train', image=np.ones((8, 8, 3)), annotations=[ Bbox(2, 2, 2, 2), ]), DatasetItem( id='label_0', subset='train', image=np.ones((8, 8, 3)), ), ], categories={ AnnotationType.label: LabelCategories.from_iterable([('label_%s' % i, 'class_%s' % i) for i in range(5)]), }) with TestDir() as test_dir: VggFace2Converter.convert(source_dataset, test_dir, save_images=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset)
def test_can_load_video(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id='frame_000010', subset='annotations', image=np.ones((20, 25, 3)), annotations=[ Bbox(3, 4, 7, 1, label=2, id=0, attributes={ 'occluded': True, 'outside': False, 'keyframe': True, 'track_id': 0 }), Points( [21.95, 8.00, 2.55, 15.09, 2.23, 3.16], label=0, id=1, attributes={ 'occluded': False, 'outside': False, 'keyframe': True, 'track_id': 1, 'hgl': 'hgkf', }), ], attributes={'frame': 10}), DatasetItem(id='frame_000013', subset='annotations', image=np.ones((20, 25, 3)), annotations=[ Bbox(7, 6, 7, 2, label=2, id=0, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 0 }), Points( [21.95, 8.00, 9.55, 15.09, 5.23, 1.16], label=0, id=1, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 1, 'hgl': 'jk', }), PolyLine( [ 7.85, 13.88, 3.50, 6.67, 15.90, 2.00, 13.31, 7.21 ], label=2, id=2, attributes={ 'occluded': False, 'outside': False, 'keyframe': True, 'track_id': 2, }), ], attributes={'frame': 13}), DatasetItem(id='frame_000016', subset='annotations', image=Image(path='frame_0000016.png', size=(20, 25)), annotations=[ Bbox(8, 7, 6, 10, label=2, id=0, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 0 }), PolyLine( [ 7.85, 13.88, 3.50, 6.67, 15.90, 2.00, 13.31, 7.21 ], label=2, id=2, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 2, }), ], attributes={'frame': 16}), ], categories={ AnnotationType.label: LabelCategories.from_iterable([['klhg', '', {'hgl'}], ['z U k'], ['II']]), }) parsed_dataset = CvatImporter()(DUMMY_VIDEO_DATASET_DIR).make_dataset() compare_datasets(self, expected_dataset, parsed_dataset)
def _load_items(self, path): def _split_item_path(path): label_name = path.split('/')[0] label = None if label_name != VggFace2Path.IMAGES_DIR_NO_LABEL: label = \ self._categories[AnnotationType.label].find(label_name)[0] item_id = path[len(label_name) + 1:] return item_id, label items = {} image_dir = osp.join(self._dataset_dir, self._subset) if osp.isdir(image_dir): images = { osp.splitext(osp.relpath(p, image_dir))[0]: p for p in find_images(image_dir, recursive=True) } else: images = {} with open(path, encoding='utf-8') as content: landmarks_table = list(csv.DictReader(content)) for row in landmarks_table: item_id = row['NAME_ID'] label = None if '/' in item_id: item_id, label = _split_item_path(item_id) if item_id not in items: items[item_id] = DatasetItem(id=item_id, subset=self._subset, image=images.get(row['NAME_ID'])) annotations = items[item_id].annotations if [a for a in annotations if a.type == AnnotationType.points]: raise Exception("Item %s: an image can have only one " "set of landmarks" % item_id) if len([p for p in row if row[p] == '']) == 0 and len(row) == 11: annotations.append(Points( [float(row[p]) for p in row if p != 'NAME_ID'], label=label)) elif label is not None: annotations.append(Label(label=label)) bboxes_path = osp.join(self._dataset_dir, VggFace2Path.ANNOTATION_DIR, VggFace2Path.BBOXES_FILE + self._subset + '.csv') if osp.isfile(bboxes_path): with open(bboxes_path, encoding='utf-8') as content: bboxes_table = list(csv.DictReader(content)) for row in bboxes_table: item_id = row['NAME_ID'] label = None if '/' in item_id: item_id, label = _split_item_path(item_id) if item_id not in items: items[item_id] = DatasetItem(id=item_id, subset=self._subset, image=images.get(row['NAME_ID'])) annotations = items[item_id].annotations if [a for a in annotations if a.type == AnnotationType.bbox]: raise Exception("Item %s: an image can have only one " "bbox" % item_id) if len([p for p in row if row[p] == '']) == 0 and len(row) == 5: annotations.append(Bbox(float(row['X']), float(row['Y']), float(row['W']), float(row['H']), label=label)) return items
def test_can_save_and_load_keypoints(self): source_dataset = Dataset.from_iterable( [ DatasetItem( id=1, subset='train', image=np.zeros((5, 5, 3)), annotations=[ # Full instance annotations: polygon + keypoints Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=3, group=1, id=1), Polygon([0, 0, 4, 0, 4, 4], label=3, group=1, id=1), # Full instance annotations: bbox + keypoints Points([1, 2, 3, 4, 2, 3], group=2, id=2), Bbox(1, 2, 2, 2, group=2, id=2), # Solitary keypoints Points([1, 2, 0, 2, 4, 1], label=5, id=3), # Some other solitary annotations (bug #1387) Polygon([0, 0, 4, 0, 4, 4], label=3, id=4), # Solitary keypoints with no label Points([0, 0, 1, 2, 3, 4], [0, 1, 2], id=5), ]), ], categories={ AnnotationType.label: LabelCategories.from_iterable(str(i) for i in range(10)), AnnotationType.points: PointsCategories.from_iterable( (i, None, [[0, 1], [1, 2]]) for i in range(10)), }) target_dataset = Dataset.from_iterable( [ DatasetItem(id=1, subset='train', image=np.zeros((5, 5, 3)), annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=3, group=1, id=1, attributes={'is_crowd': False}), Polygon([0, 0, 4, 0, 4, 4], label=3, group=1, id=1, attributes={'is_crowd': False}), Points([1, 2, 3, 4, 2, 3], group=2, id=2, attributes={'is_crowd': False}), Bbox(1, 2, 2, 2, group=2, id=2, attributes={'is_crowd': False}), Points([1, 2, 0, 2, 4, 1], label=5, group=3, id=3, attributes={'is_crowd': False}), Bbox(0, 1, 4, 1, label=5, group=3, id=3, attributes={'is_crowd': False}), Points([0, 0, 1, 2, 3, 4], [0, 1, 2], group=5, id=5, attributes={'is_crowd': False}), Bbox(1, 2, 2, 2, group=5, id=5, attributes={'is_crowd': False}), ], attributes={'id': 1}), ], categories={ AnnotationType.label: LabelCategories.from_iterable(str(i) for i in range(10)), AnnotationType.points: PointsCategories.from_iterable( (i, None, [[0, 1], [1, 2]]) for i in range(10)), }) with TestDir() as test_dir: self._test_save_and_load(source_dataset, CocoPersonKeypointsConverter.convert, test_dir, target_dataset=target_dataset)
def test_can_import_points(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id=1, subset='train', image=Image(path='1.jpg', size=(5, 5)), annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=1, group=1, id=1, attributes={'is_crowd': False}), Polygon([0, 0, 4, 0, 4, 4], label=1, group=1, id=1, attributes={'is_crowd': False}), Points([1, 2, 3, 4, 2, 3], group=2, id=2, attributes={'is_crowd': False}), Bbox(1, 2, 2, 2, group=2, id=2, attributes={'is_crowd': False}), Points([1, 2, 0, 2, 4, 1], label=0, group=3, id=3, attributes={'is_crowd': False}), Bbox(0, 1, 4, 1, label=0, group=3, id=3, attributes={'is_crowd': False}), Points([0, 0, 1, 2, 3, 4], [0, 1, 2], group=5, id=5, attributes={'is_crowd': False}), Bbox(1, 2, 2, 2, group=5, id=5, attributes={'is_crowd': False}), ], attributes={'id': 1}), ], categories={ AnnotationType.label: LabelCategories.from_iterable(['a', 'b']), AnnotationType.points: PointsCategories.from_iterable( (i, None, [[0, 1], [1, 2]]) for i in range(2)), }) dataset = Dataset.import_from( osp.join(DUMMY_DATASET_DIR, 'coco_person_keypoints'), 'coco') compare_datasets(self, expected_dataset, dataset)
def _load_annotations(self, ann, image_info=None): parsed_annotations = [] ann_id = ann.get('id') attributes = {} if 'attributes' in ann: try: attributes.update(ann['attributes']) except Exception as e: log.debug("item #%s: failed to read annotation attributes: %s", image_info['id'], e) if 'score' in ann: attributes['score'] = ann['score'] group = ann_id # make sure all tasks' annotations are merged if self._task in [CocoTask.instances, CocoTask.person_keypoints]: x, y, w, h = ann['bbox'] label_id = self._get_label_id(ann) is_crowd = bool(ann['iscrowd']) attributes['is_crowd'] = is_crowd if self._task is CocoTask.person_keypoints: keypoints = ann['keypoints'] points = [p for i, p in enumerate(keypoints) if i % 3 != 2] visibility = keypoints[2::3] parsed_annotations.append( Points(points, visibility, label=label_id, id=ann_id, attributes=attributes, group=group)) segmentation = ann.get('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 img_h = image_info['height'] img_w = image_info['width'] rles = mask_utils.frPyObjects(segmentation, img_h, img_w) rle = mask_utils.merge(rles) 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 = mask_utils.frPyObjects([segmentation], mask_h, mask_w)[0] 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 is not None: parsed_annotations.append( RleMask(rle=rle, label=label_id, id=ann_id, attributes=attributes, group=group)) else: 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 __iter__(self): return iter([ DatasetItem(id='frame_000010', subset='annotations', image=np.ones((20, 25, 3)), annotations=[ Bbox(3, 4, 7, 1, label=2, id=0, attributes={ 'occluded': True, 'outside': False, 'keyframe': True, 'track_id': 0 }), Points( [21.95, 8.00, 2.55, 15.09, 2.23, 3.16], label=0, id=1, attributes={ 'occluded': False, 'outside': False, 'keyframe': True, 'track_id': 1, 'hgl': 'hgkf', }), ], attributes={'frame': 10}), DatasetItem(id='frame_000013', subset='annotations', image=np.ones((20, 25, 3)), annotations=[ Bbox(7, 6, 7, 2, label=2, id=0, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 0 }), Points( [21.95, 8.00, 9.55, 15.09, 5.23, 1.16], label=0, id=1, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 1, 'hgl': 'jk', }), PolyLine( [ 7.85, 13.88, 3.50, 6.67, 15.90, 2.00, 13.31, 7.21 ], label=2, id=2, attributes={ 'occluded': False, 'outside': False, 'keyframe': True, 'track_id': 2, }), ], attributes={'frame': 13}), DatasetItem(id='frame_000016', subset='annotations', image=Image(path='frame_0000016.png', size=(20, 25)), annotations=[ Bbox(8, 7, 6, 10, label=2, id=0, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 0 }), PolyLine( [ 7.85, 13.88, 3.50, 6.67, 15.90, 2.00, 13.31, 7.21 ], label=2, id=2, attributes={ 'occluded': False, 'outside': True, 'keyframe': True, 'track_id': 2, }), ], attributes={'frame': 16}), ])
def test_can_save_and_load(self): src_label_cat = LabelCategories(attributes={'occluded', 'common'}) for i in range(10): src_label_cat.add(str(i)) src_label_cat.items[2].attributes.update(['a1', 'a2', 'empty']) source_dataset = Dataset.from_iterable( [ DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=1, group=4, attributes={ 'occluded': True, 'common': 't' }), Points( [1, 1, 3, 2, 2, 3], label=2, attributes={ 'a1': 'x', 'a2': 42, 'empty': '', 'unknown': 'bar' }), Label(1), Label(2, attributes={ 'a1': 'y', 'a2': 44 }), ]), DatasetItem( id=1, subset='s1', annotations=[ PolyLine([0, 0, 4, 0, 4, 4], label=3, id=4, group=4), Bbox(5, 0, 1, 9, label=3, id=4, group=4), ]), DatasetItem( id=2, subset='s2', image=np.ones((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=1, label=3, group=4, attributes={'occluded': False}), PolyLine([5, 0, 9, 0, 5, 5 ]), # will be skipped as no label ]), DatasetItem( id=3, subset='s3', image=Image(path='3.jpg', size=(2, 4))), ], categories={AnnotationType.label: src_label_cat}) target_label_cat = LabelCategories( attributes={'occluded'}) # unable to represent a common attribute for i in range(10): target_label_cat.add(str(i), attributes={'common'}) target_label_cat.items[2].attributes.update( ['a1', 'a2', 'empty', 'common']) target_dataset = Dataset.from_iterable( [ DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=1, group=4, attributes={ 'occluded': True, 'common': 't' }), Points( [1, 1, 3, 2, 2, 3], label=2, attributes={ 'occluded': False, 'empty': '', 'a1': 'x', 'a2': 42 }), Label(1), Label(2, attributes={ 'a1': 'y', 'a2': 44 }), ], attributes={'frame': 0}), DatasetItem(id=1, subset='s1', annotations=[ PolyLine([0, 0, 4, 0, 4, 4], label=3, group=4, attributes={'occluded': False}), Bbox(5, 0, 1, 9, label=3, group=4, attributes={'occluded': False}), ], attributes={'frame': 1}), DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=1, label=3, group=4, attributes={'occluded': False}), ], attributes={'frame': 0}), DatasetItem(id=3, subset='s3', image=Image(path='3.jpg', size=(2, 4)), attributes={'frame': 0}), ], categories={AnnotationType.label: target_label_cat}) with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(CvatConverter.convert, save_images=True), test_dir, target_dataset=target_dataset)
def _load_items(self, path): items = {} with open(path) as content: landmarks_table = list(csv.DictReader(content)) for row in landmarks_table: item_id = row['NAME_ID'] label = None if '/' in item_id: label_name = item_id.split('/')[0] if label_name != VggFace2Path.IMAGES_DIR_NO_LABEL: label = \ self._categories[AnnotationType.label].find(label_name)[0] item_id = item_id[len(label_name) + 1:] if item_id not in items: image_path = osp.join(self._dataset_dir, self._subset, row['NAME_ID'] + VggFace2Path.IMAGE_EXT) items[item_id] = DatasetItem(id=item_id, subset=self._subset, image=image_path) annotations = items[item_id].annotations if len([p for p in row if row[p] == '']) == 0 and len(row) == 11: annotations.append( Points([float(row[p]) for p in row if p != 'NAME_ID'], label=label, group=1)) elif label is not None: annotations.append(Label(label=label, group=1)) bboxes_path = osp.join( self._dataset_dir, VggFace2Path.ANNOTATION_DIR, VggFace2Path.BBOXES_FILE + self._subset + '.csv') if osp.isfile(bboxes_path): with open(bboxes_path) as content: bboxes_table = list(csv.DictReader(content)) for row in bboxes_table: item_id = row['NAME_ID'] label = None if '/' in item_id: label_name = item_id.split('/')[0] if label_name != VggFace2Path.IMAGES_DIR_NO_LABEL: label = \ self._categories[AnnotationType.label].find(label_name)[0] item_id = item_id[len(label_name) + 1:] if item_id not in items: image_path = osp.join( self._dataset_dir, self._subset, row['NAME_ID'] + VggFace2Path.IMAGE_EXT) items[item_id] = DatasetItem(id=item_id, subset=self._subset, image=image_path) annotations = items[item_id].annotations if len([p for p in row if row[p] == '']) == 0 and len(row) == 5: annotations.append( Bbox(float(row['X']), float(row['Y']), float(row['W']), float(row['H']), label=label, group=1)) return items