From 3cdd4eb393577954391817642f8799a24a4d0f65 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 21 Aug 2024 12:13:32 +0400 Subject: [PATCH 1/8] when comparing datasets, ignoring point order in skeleton annotations and existence of absent points --- datumaro/components/operations.py | 13 ++- datumaro/util/test_utils.py | 41 ++++---- tests/test_diff.py | 152 +++++++++++++++++++++++++++++- 3 files changed, 188 insertions(+), 18 deletions(-) diff --git a/datumaro/components/operations.py b/datumaro/components/operations.py index c11a528b6d..e76cecabeb 100644 --- a/datumaro/components/operations.py +++ b/datumaro/components/operations.py @@ -37,6 +37,7 @@ Label, LabelCategories, MaskCategories, + Points, PointsCategories, ) from datumaro.components.cli_plugin import CliPlugin @@ -1856,7 +1857,7 @@ def _compare_categories(self, a, b): except AssertionError as e: errors.append({"type": "points", "message": str(e)}) - def _compare_annotations(self, a, b): + def _compare_annotations(self, a: Annotation, b: Annotation): ignored_fields = self.ignored_fields ignored_attrs = self.ignored_attrs @@ -1866,6 +1867,16 @@ def _compare_annotations(self, a, b): a_fields["attributes"] = filter_dict(a.attributes, ignored_attrs) b_fields["attributes"] = filter_dict(b.attributes, ignored_attrs) + if a.type == b.type == AnnotationType.skeleton and "elements" not in ignored_fields: + a_fields["elements"] = sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, a.elements), + key=lambda s: s.label, + ) + b_fields["elements"] = sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, b.elements), + key=lambda s: s.label, + ) + result = a.wrap(**a_fields) == b.wrap(**b_fields) return result diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index 5e45aa1e76..eb49db9938 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -16,7 +16,7 @@ from typing_extensions import Literal -from datumaro.components.annotation import AnnotationType +from datumaro.components.annotation import Annotation, AnnotationType, Points from datumaro.components.dataset import Dataset, IDataset from datumaro.components.media import Image, MultiframeImage, PointCloud from datumaro.util import filter_dict, find @@ -115,26 +115,35 @@ def compare_categories(test, expected, actual): IGNORE_ALL = "*" -def compare_annotations(expected, actual, ignored_attrs=None): - if not ignored_attrs: +def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs=None): + is_skeleton = expected.type == actual.type == AnnotationType.skeleton + if not ignored_attrs and not is_skeleton: return expected == actual - a_attr = expected.attributes - b_attr = actual.attributes - if ignored_attrs != IGNORE_ALL: - expected.attributes = filter_dict(a_attr, exclude_keys=ignored_attrs) - actual.attributes = filter_dict(b_attr, exclude_keys=ignored_attrs) + expected = expected.wrap( + attributes=filter_dict(expected.attributes, exclude_keys=ignored_attrs) + ) + actual = actual.wrap(attributes=filter_dict(actual.attributes, exclude_keys=ignored_attrs)) else: - expected.attributes = {} - actual.attributes = {} - - r = expected == actual - - expected.attributes = a_attr - actual.attributes = b_attr + expected = expected.wrap(attributes={}) + actual = actual.wrap(attributes={}) + + if is_skeleton: + expected = expected.wrap( + elements=sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, expected.elements), + key=lambda s: s.label, + ) + ) + actual = actual.wrap( + elements=sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, actual.elements), + key=lambda s: s.label, + ) + ) - return r + return expected == actual def compare_datasets( diff --git a/tests/test_diff.py b/tests/test_diff.py index e52a4a35e2..d2649c8d5f 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -2,7 +2,17 @@ import numpy as np -from datumaro.components.annotation import Bbox, Caption, Label, Mask, Points +from datumaro.components.annotation import ( + AnnotationType, + Bbox, + Caption, + Label, + LabelCategories, + Mask, + Points, + PointsCategories, + Skeleton, +) from datumaro.components.extractor import DEFAULT_SUBSET_NAME, DatasetItem from datumaro.components.media import Image from datumaro.components.operations import DistanceComparator, ExactComparator @@ -268,6 +278,146 @@ def test_annotation_comparison(self): self.assertEqual(2, len(unmatched), unmatched) self.assertEqual(0, len(errors), errors) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_skeleton_annotation_comparison(self): + categories = { + AnnotationType.label: LabelCategories.from_iterable( + [ + "skeleton", + ("point1", "skeleton"), + ("point2", "skeleton"), + ("point3", "skeleton"), + ] + ), + AnnotationType.points: PointsCategories.from_iterable( + [ + (0, ["point1", "point2", "point3"], set()), + ] + ), + } + a = Dataset.from_iterable( + [ + DatasetItem( + id=1, + annotations=[ + Skeleton( + [ + Points([0, 1], [2], label=1), + Points([1, 2], [1], label=2), + Points([2, 3], [0], label=3), + ], + label=0, + ) + ], + ), + DatasetItem( + id=2, + annotations=[ + Skeleton( + [ + Points([4, 5], [2], label=1), + Points([5, 6], [1], label=2), + Points([6, 7], [0], label=3), + ], + label=0, + ) + ], + ), + DatasetItem( + id=3, + annotations=[ + Skeleton( + [ + Points([7, 8], [2], label=1), + Points([8, 9], [1], label=2), + Points([9, 10], [0], label=3), + ], + label=0, + ) + ], + ), + ], + categories=categories, + ) + + b = Dataset.from_iterable( + [ + DatasetItem( + id=1, + annotations=[ + Skeleton( + [ + Points([1, 2], [1], label=2), + Points([0, 1], [2], label=1), + ], + label=0, + ) + ], + ), # matched, even though absent point is removed and order differs + DatasetItem( + id=2, + annotations=[ + Skeleton( + [ + Points([4, 5], [2], label=1), + Points([5, 6], [1], label=2), + Points([6, 8], [0], label=3), + ], + label=0, + ) + ], + ), # matched, even though absent point has different coordinates + DatasetItem( + id=3, + annotations=[ + Skeleton( + [ + Points([7, 8], [2], label=1), + Points([8, 10], [1], label=2), + Points([9, 10], [0], label=3), + ], + label=0, + ) + ], + ), # not matched, not-absent point has changed coordinates + ], + categories=categories, + ) + + comp = ExactComparator() + _, unmatched, _, _, _ = comp.compare_datasets(a, b) + + assert unmatched == [ + { + "item": ("3", "default"), + "source": "a", + "ann": repr( + Skeleton( + [ + Points([7, 8], [2], label=1), + Points([8, 9], [1], label=2), + Points([9, 10], [0], label=3), + ], + label=0, + ) + ), + }, + { + "item": ("3", "default"), + "source": "b", + "ann": repr( + Skeleton( + [ + Points([7, 8], [2], label=1), + Points([8, 10], [1], label=2), + Points([9, 10], [0], label=3), + ], + label=0, + ) + ), + }, + ] + @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_image_comparison(self): a = Dataset.from_iterable( From 89ee634d33578d49ef01e4448a0fad1f16a43b43 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 21 Aug 2024 13:14:55 +0400 Subject: [PATCH 2/8] do not create empty files on export --- datumaro/plugins/yolo_format/converter.py | 13 +++++++----- tests/unit/data_formats/test_yolo_format.py | 23 ++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/datumaro/plugins/yolo_format/converter.py b/datumaro/plugins/yolo_format/converter.py index 8b812948b9..5c5f6e7417 100644 --- a/datumaro/plugins/yolo_format/converter.py +++ b/datumaro/plugins/yolo_format/converter.py @@ -194,6 +194,10 @@ def _export_media(self, item: DatasetItem, subset_img_dir: str) -> str: except Exception as e: self._ctx.error_policy.report_item_error(e, item_id=(item.id, item.subset)) + def _save_annotation_file(self, annotation_path, yolo_annotation): + with open(annotation_path, "w", encoding="utf-8") as f: + f.write(yolo_annotation) + def _export_item_annotation(self, item: DatasetItem, subset_dir: str) -> None: try: height, width = item.media.size @@ -208,8 +212,7 @@ def _export_item_annotation(self, item: DatasetItem, subset_dir: str) -> None: annotation_path = osp.join(subset_dir, f"{item.id}{YoloPath.LABELS_EXT}") os.makedirs(osp.dirname(annotation_path), exist_ok=True) - with open(annotation_path, "w", encoding="utf-8") as f: - f.write(yolo_annotation) + self._save_annotation_file(annotation_path, yolo_annotation) except Exception as e: self._ctx.error_policy.report_item_error(e, item_id=(item.id, item.subset)) @@ -288,9 +291,9 @@ def __init__( super().__init__(extractor, save_dir, add_path_prefix=add_path_prefix, **kwargs) self._config_filename = config_file or YOLOv8Path.DEFAULT_CONFIG_FILE - def _export_item_annotation(self, item: DatasetItem, subset_dir: str) -> None: - if len(item.annotations) > 0: - super()._export_item_annotation(item, subset_dir) + def _save_annotation_file(self, annotation_path, yolo_annotation): + if yolo_annotation: + super()._save_annotation_file(annotation_path, yolo_annotation) @classmethod def build_cmdline_parser(cls, **kwargs): diff --git a/tests/unit/data_formats/test_yolo_format.py b/tests/unit/data_formats/test_yolo_format.py index 0eba149913..eb3ada266b 100644 --- a/tests/unit/data_formats/test_yolo_format.py +++ b/tests/unit/data_formats/test_yolo_format.py @@ -18,6 +18,7 @@ AnnotationType, Bbox, LabelCategories, + Mask, Points, PointsCategories, Polygon, @@ -466,14 +467,26 @@ def test_can_save_and_load_without_path_prefix(self, test_dir): self.compare_datasets(source_dataset, parsed_dataset) - @mark_requirement(Requirements.DATUM_609) - def test_can_save_and_load_without_annotations(self, test_dir): - source_dataset = self._generate_random_dataset([{"annotations": 0}]) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_without_creating_annotation_file_and_load(self, test_dir): + source_dataset = Dataset.from_iterable( + [ + DatasetItem( + id=1, + subset="train", + media=Image(data=np.ones((8, 8, 3))), + annotations=[ + # Mask annotation is not supported by yolo8 formats, so should be omitted + Mask(np.array([[0, 1, 1, 1, 0]]), label=0), + ], + ) + ], + categories=["label_" + str(i) for i in range(5)], + ) self.CONVERTER.convert(source_dataset, test_dir, save_media=True) assert os.listdir(osp.join(test_dir, "labels", "train")) == [] - parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) - self.compare_datasets(source_dataset, parsed_dataset) + Dataset.import_from(test_dir, self.IMPORTER.NAME) def _check_inplace_save_writes_only_updated_data(self, test_dir, expected): assert set(os.listdir(osp.join(test_dir, "images", "train"))) == { From f1a7cecd7b62299e7a9d1132c96da68c8cd97cb3 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 21 Aug 2024 13:41:50 +0400 Subject: [PATCH 3/8] fix tests --- datumaro/util/test_utils.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index eb49db9938..a9f3bf8a6a 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -10,6 +10,7 @@ import unittest import unittest.mock import warnings +from copy import copy from enum import Enum, auto from glob import glob from typing import Any, Callable, Collection, Optional, Union @@ -120,27 +121,24 @@ def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs= if not ignored_attrs and not is_skeleton: return expected == actual + expected = copy(expected) + actual = copy(actual) + if ignored_attrs != IGNORE_ALL: - expected = expected.wrap( - attributes=filter_dict(expected.attributes, exclude_keys=ignored_attrs) - ) - actual = actual.wrap(attributes=filter_dict(actual.attributes, exclude_keys=ignored_attrs)) + expected.attributes = filter_dict(expected.attributes, exclude_keys=ignored_attrs) + actual.attributes = filter_dict(actual.attributes, exclude_keys=ignored_attrs) else: - expected = expected.wrap(attributes={}) - actual = actual.wrap(attributes={}) + expected.attributes = {} + actual.attributes = {} if is_skeleton: - expected = expected.wrap( - elements=sorted( - filter(lambda p: p.visibility[0] != Points.Visibility.absent, expected.elements), - key=lambda s: s.label, - ) + expected.elements = sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, expected.elements), + key=lambda s: s.label, ) - actual = actual.wrap( - elements=sorted( - filter(lambda p: p.visibility[0] != Points.Visibility.absent, actual.elements), - key=lambda s: s.label, - ) + actual.elements = sorted( + filter(lambda p: p.visibility[0] != Points.Visibility.absent, actual.elements), + key=lambda s: s.label, ) return expected == actual From 97fa6452817ad4814b222d4bf0f1e0f67a8003f3 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 21 Aug 2024 13:55:24 +0400 Subject: [PATCH 4/8] fix tests again --- datumaro/util/test_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index a9f3bf8a6a..98083546e9 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -121,6 +121,8 @@ def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs= if not ignored_attrs and not is_skeleton: return expected == actual + ignored_attrs = ignored_attrs or {} + expected = copy(expected) actual = copy(actual) From 00a1bd844a3037c13012d940987ac3f4b5d38435 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 21 Aug 2024 14:08:57 +0400 Subject: [PATCH 5/8] if label points are missing, use -1 as a label for sorting purposes --- datumaro/components/operations.py | 4 ++-- datumaro/util/test_utils.py | 4 ++-- tests/test_diff.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/datumaro/components/operations.py b/datumaro/components/operations.py index e76cecabeb..230ea13286 100644 --- a/datumaro/components/operations.py +++ b/datumaro/components/operations.py @@ -1870,11 +1870,11 @@ def _compare_annotations(self, a: Annotation, b: Annotation): if a.type == b.type == AnnotationType.skeleton and "elements" not in ignored_fields: a_fields["elements"] = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, a.elements), - key=lambda s: s.label, + key=lambda s: s.label or -1, ) b_fields["elements"] = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, b.elements), - key=lambda s: s.label, + key=lambda s: s.label or -1, ) result = a.wrap(**a_fields) == b.wrap(**b_fields) diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index 98083546e9..72476ce2d0 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -136,11 +136,11 @@ def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs= if is_skeleton: expected.elements = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, expected.elements), - key=lambda s: s.label, + key=lambda s: s.label or -1, ) actual.elements = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, actual.elements), - key=lambda s: s.label, + key=lambda s: s.label or -1, ) return expected == actual diff --git a/tests/test_diff.py b/tests/test_diff.py index d2649c8d5f..5010e6dcde 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -302,7 +302,7 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([0, 1], [2], label=1), + Points([0, 1], [2]), Points([1, 2], [1], label=2), Points([2, 3], [0], label=3), ], @@ -348,7 +348,7 @@ def test_skeleton_annotation_comparison(self): Skeleton( [ Points([1, 2], [1], label=2), - Points([0, 1], [2], label=1), + Points([0, 1], [2]), ], label=0, ) From a698ef96351106132674a8b07f37bb972b5b082d Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 28 Aug 2024 14:34:37 +0400 Subject: [PATCH 6/8] fixes --- datumaro/components/operations.py | 4 +- datumaro/util/test_utils.py | 6 +-- tests/test_diff.py | 34 ++++++++-------- tests/unit/data_formats/test_yolo_format.py | 45 ++++++++++++++++++++- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/datumaro/components/operations.py b/datumaro/components/operations.py index 230ea13286..41d19ee7a0 100644 --- a/datumaro/components/operations.py +++ b/datumaro/components/operations.py @@ -1870,11 +1870,11 @@ def _compare_annotations(self, a: Annotation, b: Annotation): if a.type == b.type == AnnotationType.skeleton and "elements" not in ignored_fields: a_fields["elements"] = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, a.elements), - key=lambda s: s.label or -1, + key=lambda p: p.label if p.label is not None else -1, ) b_fields["elements"] = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, b.elements), - key=lambda s: s.label or -1, + key=lambda p: p.label if p.label is not None else -1, ) result = a.wrap(**a_fields) == b.wrap(**b_fields) diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index 72476ce2d0..77a0d524af 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -121,7 +121,7 @@ def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs= if not ignored_attrs and not is_skeleton: return expected == actual - ignored_attrs = ignored_attrs or {} + ignored_attrs = ignored_attrs or [] expected = copy(expected) actual = copy(actual) @@ -136,11 +136,11 @@ def compare_annotations(expected: Annotation, actual: Annotation, ignored_attrs= if is_skeleton: expected.elements = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, expected.elements), - key=lambda s: s.label or -1, + key=lambda p: p.label if p.label is not None else -1, ) actual.elements = sorted( filter(lambda p: p.visibility[0] != Points.Visibility.absent, actual.elements), - key=lambda s: s.label or -1, + key=lambda p: p.label if p.label is not None else -1, ) return expected == actual diff --git a/tests/test_diff.py b/tests/test_diff.py index 5010e6dcde..50e1d8a88e 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -302,9 +302,9 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([0, 1], [2]), - Points([1, 2], [1], label=2), - Points([2, 3], [0], label=3), + Points([0, 1], [Points.Visibility.visible]), + Points([1, 2], [Points.Visibility.hidden], label=2), + Points([2, 3], [Points.Visibility.absent], label=3), ], label=0, ) @@ -315,9 +315,9 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([4, 5], [2], label=1), - Points([5, 6], [1], label=2), - Points([6, 7], [0], label=3), + Points([4, 5], [Points.Visibility.visible], label=1), + Points([5, 6], [Points.Visibility.hidden], label=2), + Points([6, 7], [Points.Visibility.absent], label=3), ], label=0, ) @@ -328,9 +328,9 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([7, 8], [2], label=1), - Points([8, 9], [1], label=2), - Points([9, 10], [0], label=3), + Points([7, 8], [Points.Visibility.visible], label=1), + Points([8, 9], [Points.Visibility.hidden], label=2), + Points([9, 10], [Points.Visibility.absent], label=3), ], label=0, ) @@ -347,8 +347,8 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([1, 2], [1], label=2), - Points([0, 1], [2]), + Points([1, 2], [Points.Visibility.hidden], label=2), + Points([0, 1], [Points.Visibility.absent]), ], label=0, ) @@ -359,9 +359,9 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([4, 5], [2], label=1), - Points([5, 6], [1], label=2), - Points([6, 8], [0], label=3), + Points([4, 5], [Points.Visibility.visible], label=1), + Points([5, 6], [Points.Visibility.hidden], label=2), + Points([6, 8], [Points.Visibility.absent], label=3), ], label=0, ) @@ -372,9 +372,9 @@ def test_skeleton_annotation_comparison(self): annotations=[ Skeleton( [ - Points([7, 8], [2], label=1), - Points([8, 10], [1], label=2), - Points([9, 10], [0], label=3), + Points([7, 8], [Points.Visibility.visible], label=1), + Points([8, 10], [Points.Visibility.hidden], label=2), + Points([9, 10], [Points.Visibility.absent], label=3), ], label=0, ) diff --git a/tests/unit/data_formats/test_yolo_format.py b/tests/unit/data_formats/test_yolo_format.py index eb3ada266b..64872fe8e0 100644 --- a/tests/unit/data_formats/test_yolo_format.py +++ b/tests/unit/data_formats/test_yolo_format.py @@ -483,10 +483,20 @@ def test_can_save_without_creating_annotation_file_and_load(self, test_dir): ], categories=["label_" + str(i) for i in range(5)], ) + expected_dataset = Dataset.from_iterable( + [ + DatasetItem( + id=1, + subset="train", + media=Image(data=np.ones((8, 8, 3))), + ) + ], + categories=["label_" + str(i) for i in range(5)], + ) self.CONVERTER.convert(source_dataset, test_dir, save_media=True) - assert os.listdir(osp.join(test_dir, "labels", "train")) == [] - Dataset.import_from(test_dir, self.IMPORTER.NAME) + parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) + self.compare_datasets(expected_dataset, parsed_dataset) def _check_inplace_save_writes_only_updated_data(self, test_dir, expected): assert set(os.listdir(osp.join(test_dir, "images", "train"))) == { @@ -889,6 +899,37 @@ def test_saves_only_parentless_labels(self, test_dir): parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) self.compare_datasets(expected_dataset, parsed_dataset) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_without_creating_annotation_file_and_load(self, test_dir): + source_dataset = Dataset.from_iterable( + [ + DatasetItem( + id=1, + subset="train", + media=Image(data=np.ones((8, 8, 3))), + annotations=[ + # Mask annotation is not supported by yolo8 formats, so should be omitted + Mask(np.array([[0, 1, 1, 1, 0]]), label=0), + ], + ) + ], + categories=["label_" + str(i) for i in range(5)], + ) + expected_dataset = Dataset.from_iterable( + [ + DatasetItem( + id=1, + subset="train", + media=Image(data=np.ones((8, 8, 3))), + ) + ], + categories=[], + ) + self.CONVERTER.convert(source_dataset, test_dir, save_media=True) + assert os.listdir(osp.join(test_dir, "labels", "train")) == [] + parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) + self.compare_datasets(expected_dataset, parsed_dataset) + class YoloImporterTest(CompareDatasetMixin): IMPORTER = YoloImporter From 8df44c6e4131a57f9060da5cabce88dd3e7dc418 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 28 Aug 2024 14:45:39 +0400 Subject: [PATCH 7/8] fix --- tests/test_diff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_diff.py b/tests/test_diff.py index 50e1d8a88e..30a394a51e 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -348,7 +348,7 @@ def test_skeleton_annotation_comparison(self): Skeleton( [ Points([1, 2], [Points.Visibility.hidden], label=2), - Points([0, 1], [Points.Visibility.absent]), + Points([0, 1], [Points.Visibility.visible]), ], label=0, ) From da9629ff42cc42c860bef82b90e3df13696d1214 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrukhin Date: Wed, 28 Aug 2024 14:50:29 +0400 Subject: [PATCH 8/8] fixing code duplication --- tests/unit/data_formats/test_yolo_format.py | 36 ++------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/tests/unit/data_formats/test_yolo_format.py b/tests/unit/data_formats/test_yolo_format.py index 64872fe8e0..3cfb8d8344 100644 --- a/tests/unit/data_formats/test_yolo_format.py +++ b/tests/unit/data_formats/test_yolo_format.py @@ -469,6 +469,7 @@ def test_can_save_and_load_without_path_prefix(self, test_dir): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_without_creating_annotation_file_and_load(self, test_dir): + categories = self._generate_random_dataset([]).categories() source_dataset = Dataset.from_iterable( [ DatasetItem( @@ -481,7 +482,7 @@ def test_can_save_without_creating_annotation_file_and_load(self, test_dir): ], ) ], - categories=["label_" + str(i) for i in range(5)], + categories=categories, ) expected_dataset = Dataset.from_iterable( [ @@ -491,7 +492,7 @@ def test_can_save_without_creating_annotation_file_and_load(self, test_dir): media=Image(data=np.ones((8, 8, 3))), ) ], - categories=["label_" + str(i) for i in range(5)], + categories=categories, ) self.CONVERTER.convert(source_dataset, test_dir, save_media=True) assert os.listdir(osp.join(test_dir, "labels", "train")) == [] @@ -899,37 +900,6 @@ def test_saves_only_parentless_labels(self, test_dir): parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) self.compare_datasets(expected_dataset, parsed_dataset) - @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_without_creating_annotation_file_and_load(self, test_dir): - source_dataset = Dataset.from_iterable( - [ - DatasetItem( - id=1, - subset="train", - media=Image(data=np.ones((8, 8, 3))), - annotations=[ - # Mask annotation is not supported by yolo8 formats, so should be omitted - Mask(np.array([[0, 1, 1, 1, 0]]), label=0), - ], - ) - ], - categories=["label_" + str(i) for i in range(5)], - ) - expected_dataset = Dataset.from_iterable( - [ - DatasetItem( - id=1, - subset="train", - media=Image(data=np.ones((8, 8, 3))), - ) - ], - categories=[], - ) - self.CONVERTER.convert(source_dataset, test_dir, save_media=True) - assert os.listdir(osp.join(test_dir, "labels", "train")) == [] - parsed_dataset = Dataset.import_from(test_dir, self.IMPORTER.NAME) - self.compare_datasets(expected_dataset, parsed_dataset) - class YoloImporterTest(CompareDatasetMixin): IMPORTER = YoloImporter