From fc636d2512b47e5439e467cf943ca27c215bc515 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Thu, 15 Apr 2021 10:28:14 +0300 Subject: [PATCH 1/9] fix match dm item for no image frame --- cvat/apps/dataset_manager/bindings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index a8d2fcb98da3..a48cb28cdb04 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -611,7 +611,7 @@ def match_dm_item(item, task_data, root_hint=None): if frame_number is None and item.has_image: frame_number = task_data.match_frame(item.id + item.image.ext, root_hint) if frame_number is None: - frame_number = task_data.match_frame(item.id, root_hint) + 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: From 6366b992488022c578a78839a63dd9a8f671cef0 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Thu, 15 Apr 2021 10:41:13 +0300 Subject: [PATCH 2/9] test --- .../dataset_manager/tests/test_formats.py | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index f4589feedc05..588f2ce63545 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -217,9 +217,9 @@ def _generate_annotations(self, task): } return self._generate_custom_annotations(annotations, task) - def _generate_task_images(self, count): # pylint: disable=no-self-use + def _generate_task_images(self, count, name="image"): # pylint: disable=no-self-use images = { - "client_files[%d]" % i: generate_image_file("image_%d.jpg" % i) + "client_files[%d]" % i: generate_image_file(name + "_%d.jpg" % i) for i in range(count) } images["image_quality"] = 75 @@ -264,6 +264,21 @@ def _test_export(check, task, format_name, **export_args): check(file_path) + def _test_can_import_annotations(self, task, format_name): + with tempfile.TemporaryDirectory() as temp_dir: + file_path = osp.join(temp_dir, format_name) + + dm.task.export_task(task["id"], file_path, format_name) + expected_ann = TaskAnnotation(task["id"]) + expected_ann.init_from_db() + + dm.task.import_task_annotations(task["id"], + file_path, format_name) + actual_ann = TaskAnnotation(task["id"]) + actual_ann.init_from_db() + + self.assertEqual(len(expected_ann.data), len(actual_ann.data)) + def test_export_formats_query(self): formats = dm.views.get_export_formats() @@ -496,6 +511,21 @@ def test_frames_outside_are_not_generated(self): self.assertTrue(frame.frame in range(6, 10)) self.assertEqual(i + 1, 4) + def test_can_import_annotations_for_image_with_dots_in_filename(self): + export_formats = [f.DISPLAY_NAME for f in dm.views.get_export_formats()] + formats = [f.DISPLAY_NAME for f in dm.views.get_import_formats() if + f.DISPLAY_NAME in export_formats] + for format_name in formats: + if format_name == "VGGFace2 1.0": + self.skipTest("Format is disabled") + + images = self._generate_task_images(2, "img0.0.0.") + task = self._generate_task(images) + self._generate_annotations(task) + + with self.subTest(format=format_name): + self._test_can_import_annotations(task, format_name) + class FrameMatchingTest(_DbTestBase): def _generate_task_images(self, paths): # pylint: disable=no-self-use f = BytesIO() From d7be0429fd3ff4e9928f6221e1a1905c56afbe7f Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Thu, 15 Apr 2021 13:31:38 +0300 Subject: [PATCH 3/9] fix import dm annotations --- cvat/apps/dataset_manager/bindings.py | 5 +++-- cvat/apps/dataset_manager/formats/mots.py | 4 ++-- cvat/apps/dataset_manager/formats/yolo.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index a48cb28cdb04..a03adb2110db 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -14,6 +14,7 @@ from cvat.apps.engine.models import AttributeType, ShapeType from datumaro.util import cast from datumaro.util.image import ByteImage, Image +from datumaro.components.extractor import DatasetItem from .annotation import AnnotationManager, TrackManager @@ -611,7 +612,7 @@ def match_dm_item(item, task_data, root_hint=None): if frame_number is None and item.has_image: frame_number = task_data.match_frame(item.id + item.image.ext, root_hint) if frame_number is None: - frame_number = task_data.match_frame(item.id + '.', root_hint) + 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: @@ -651,7 +652,7 @@ def import_dm_annotations(dm_dataset, task_data): for item in dm_dataset: frame_number = task_data.abs_frame_id( - match_dm_item(item, task_data, root_hint=root_hint)) + match_dm_item(DatasetItem(id=item.id + '.'), task_data, root_hint=root_hint)) # do not store one-item groups group_map = {0: 0} diff --git a/cvat/apps/dataset_manager/formats/mots.py b/cvat/apps/dataset_manager/formats/mots.py index 22b9dd08c7ea..a4a14e44527e 100644 --- a/cvat/apps/dataset_manager/formats/mots.py +++ b/cvat/apps/dataset_manager/formats/mots.py @@ -5,7 +5,7 @@ from tempfile import TemporaryDirectory from datumaro.components.dataset import Dataset -from datumaro.components.extractor import AnnotationType, Transform +from datumaro.components.extractor import AnnotationType, Transform, DatasetItem from pyunpack import Archive from cvat.apps.dataset_manager.bindings import (CvatTaskDataExtractor, @@ -48,7 +48,7 @@ def _import(src_file, task_data): for item in dataset: frame_number = task_data.abs_frame_id( - match_dm_item(item, task_data, root_hint=root_hint)) + match_dm_item(DatasetItem(id=item.id + '.'), task_data, root_hint=root_hint)) for ann in item.annotations: if ann.type != AnnotationType.polygon: diff --git a/cvat/apps/dataset_manager/formats/yolo.py b/cvat/apps/dataset_manager/formats/yolo.py index 0df6f5fe27a1..c0994774393d 100644 --- a/cvat/apps/dataset_manager/formats/yolo.py +++ b/cvat/apps/dataset_manager/formats/yolo.py @@ -40,7 +40,7 @@ def _import(src_file, task_data): for frame in frames: frame_info = None try: - frame_id = match_dm_item(DatasetItem(id=frame), task_data, + frame_id = match_dm_item(DatasetItem(id=frame + '.'), task_data, root_hint=root_hint) frame_info = task_data.frame_info[frame_id] except Exception: # nosec From cbcb62048a16ef076d61ceb01148915c84affdb8 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Fri, 16 Apr 2021 10:24:16 +0300 Subject: [PATCH 4/9] fix incorrect solution --- cvat/apps/dataset_manager/bindings.py | 10 +++++----- cvat/apps/dataset_manager/formats/cvat.py | 2 +- cvat/apps/dataset_manager/formats/mots.py | 4 ++-- cvat/apps/dataset_manager/formats/yolo.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index a03adb2110db..b800e18ca3cf 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -14,7 +14,6 @@ from cvat.apps.engine.models import AttributeType, ShapeType from datumaro.util import cast from datumaro.util.image import ByteImage, Image -from datumaro.components.extractor import DatasetItem from .annotation import AnnotationManager, TrackManager @@ -436,8 +435,9 @@ def db_task(self): def _get_filename(path): return osp.splitext(path)[0] - def match_frame(self, path, root_hint=None): - path = self._get_filename(path) + def match_frame(self, path, root_hint=None, path_has_ext=True): + if path_has_ext: + path = self._get_filename(path) match = self._frame_mapping.get(path) if not match and root_hint and not path.startswith(root_hint): path = osp.join(root_hint, path) @@ -612,7 +612,7 @@ def match_dm_item(item, task_data, root_hint=None): if frame_number is None and item.has_image: frame_number = task_data.match_frame(item.id + item.image.ext, root_hint) if frame_number is None: - frame_number = task_data.match_frame(item.id, root_hint) + frame_number = task_data.match_frame(item.id, root_hint, path_has_ext=False) if frame_number is None: frame_number = cast(item.attributes.get('frame', item.id), int) if frame_number is None and is_video: @@ -652,7 +652,7 @@ def import_dm_annotations(dm_dataset, task_data): for item in dm_dataset: frame_number = task_data.abs_frame_id( - match_dm_item(DatasetItem(id=item.id + '.'), task_data, root_hint=root_hint)) + match_dm_item(item, task_data, root_hint=root_hint)) # do not store one-item groups group_map = {0: 0} diff --git a/cvat/apps/dataset_manager/formats/cvat.py b/cvat/apps/dataset_manager/formats/cvat.py index 02025afc750a..aa1a0a5af4cd 100644 --- a/cvat/apps/dataset_manager/formats/cvat.py +++ b/cvat/apps/dataset_manager/formats/cvat.py @@ -441,7 +441,7 @@ def load(file_object, annotations): elif el.tag == 'image': image_is_opened = True frame_id = annotations.abs_frame_id(match_dm_item( - DatasetItem(id=el.attrib['name'], + DatasetItem(id=osp.splitext(el.attrib['name'])[0], attributes={'frame': el.attrib['id']} ), task_data=annotations diff --git a/cvat/apps/dataset_manager/formats/mots.py b/cvat/apps/dataset_manager/formats/mots.py index a4a14e44527e..22b9dd08c7ea 100644 --- a/cvat/apps/dataset_manager/formats/mots.py +++ b/cvat/apps/dataset_manager/formats/mots.py @@ -5,7 +5,7 @@ from tempfile import TemporaryDirectory from datumaro.components.dataset import Dataset -from datumaro.components.extractor import AnnotationType, Transform, DatasetItem +from datumaro.components.extractor import AnnotationType, Transform from pyunpack import Archive from cvat.apps.dataset_manager.bindings import (CvatTaskDataExtractor, @@ -48,7 +48,7 @@ def _import(src_file, task_data): for item in dataset: frame_number = task_data.abs_frame_id( - match_dm_item(DatasetItem(id=item.id + '.'), task_data, root_hint=root_hint)) + match_dm_item(item, task_data, root_hint=root_hint)) for ann in item.annotations: if ann.type != AnnotationType.polygon: diff --git a/cvat/apps/dataset_manager/formats/yolo.py b/cvat/apps/dataset_manager/formats/yolo.py index c0994774393d..0df6f5fe27a1 100644 --- a/cvat/apps/dataset_manager/formats/yolo.py +++ b/cvat/apps/dataset_manager/formats/yolo.py @@ -40,7 +40,7 @@ def _import(src_file, task_data): for frame in frames: frame_info = None try: - frame_id = match_dm_item(DatasetItem(id=frame + '.'), task_data, + frame_id = match_dm_item(DatasetItem(id=frame), task_data, root_hint=root_hint) frame_info = task_data.frame_info[frame_id] except Exception: # nosec From 43fe33ff9ff1bf130a8c2cf5d0e8855ce0dfecfa Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Fri, 16 Apr 2021 15:12:06 +0300 Subject: [PATCH 5/9] remove incorrect tests --- .../dataset_manager/tests/test_formats.py | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index 588f2ce63545..44c0cda7822d 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -264,21 +264,6 @@ def _test_export(check, task, format_name, **export_args): check(file_path) - def _test_can_import_annotations(self, task, format_name): - with tempfile.TemporaryDirectory() as temp_dir: - file_path = osp.join(temp_dir, format_name) - - dm.task.export_task(task["id"], file_path, format_name) - expected_ann = TaskAnnotation(task["id"]) - expected_ann.init_from_db() - - dm.task.import_task_annotations(task["id"], - file_path, format_name) - actual_ann = TaskAnnotation(task["id"]) - actual_ann.init_from_db() - - self.assertEqual(len(expected_ann.data), len(actual_ann.data)) - def test_export_formats_query(self): formats = dm.views.get_export_formats() @@ -511,21 +496,6 @@ def test_frames_outside_are_not_generated(self): self.assertTrue(frame.frame in range(6, 10)) self.assertEqual(i + 1, 4) - def test_can_import_annotations_for_image_with_dots_in_filename(self): - export_formats = [f.DISPLAY_NAME for f in dm.views.get_export_formats()] - formats = [f.DISPLAY_NAME for f in dm.views.get_import_formats() if - f.DISPLAY_NAME in export_formats] - for format_name in formats: - if format_name == "VGGFace2 1.0": - self.skipTest("Format is disabled") - - images = self._generate_task_images(2, "img0.0.0.") - task = self._generate_task(images) - self._generate_annotations(task) - - with self.subTest(format=format_name): - self._test_can_import_annotations(task, format_name) - class FrameMatchingTest(_DbTestBase): def _generate_task_images(self, paths): # pylint: disable=no-self-use f = BytesIO() From aad580b9e080e630c9d1d3b4fe1ec7015e251e67 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Fri, 16 Apr 2021 15:16:23 +0300 Subject: [PATCH 6/9] add image path in load annotations for cvat format --- cvat/apps/dataset_manager/formats/cvat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cvat/apps/dataset_manager/formats/cvat.py b/cvat/apps/dataset_manager/formats/cvat.py index aa1a0a5af4cd..786a5025e7c0 100644 --- a/cvat/apps/dataset_manager/formats/cvat.py +++ b/cvat/apps/dataset_manager/formats/cvat.py @@ -442,7 +442,8 @@ def load(file_object, annotations): image_is_opened = True frame_id = annotations.abs_frame_id(match_dm_item( DatasetItem(id=osp.splitext(el.attrib['name'])[0], - attributes={'frame': el.attrib['id']} + attributes={'frame': el.attrib['id']}, + image=el.attrib['name'] ), task_data=annotations )) From 5d5a33068e1408d98aad32ad1f5f85b833c73a99 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Fri, 16 Apr 2021 15:18:59 +0300 Subject: [PATCH 7/9] add image with dots in filename for test rest api --- cvat/apps/engine/tests/test_rest_api.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index 01b85641ecbc..2469f7f980e0 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -2967,11 +2967,11 @@ def _create_task(self, owner, assignee, annotation_format=""): "client_files[1]": generate_image_file("test_2.jpg")[1], "client_files[2]": generate_image_file("test_3.jpg")[1], "client_files[4]": generate_image_file("test_4.jpg")[1], - "client_files[5]": generate_image_file("test_5.jpg")[1], - "client_files[6]": generate_image_file("test_6.jpg")[1], - "client_files[7]": generate_image_file("test_7.jpg")[1], - "client_files[8]": generate_image_file("test_8.jpg")[1], - "client_files[9]": generate_image_file("test_9.jpg")[1], + "client_files[5]": generate_image_file("test_5.0.jpg")[1], + "client_files[6]": generate_image_file("test_6.0.jpg")[1], + "client_files[7]": generate_image_file("test_7.0.jpg")[1], + "client_files[8]": generate_image_file("test_8.0.jpg")[1], + "client_files[9]": generate_image_file("test_9.0.jpg")[1], "image_quality": 75, "frame_filter": "step=3", } From 54b7cc37e840db06f34e33ac3e74549da4755ed9 Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Mon, 19 Apr 2021 12:53:57 +0300 Subject: [PATCH 8/9] delete filenames with dots in test rest api --- cvat/apps/engine/tests/test_rest_api.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index 2469f7f980e0..01b85641ecbc 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -2967,11 +2967,11 @@ def _create_task(self, owner, assignee, annotation_format=""): "client_files[1]": generate_image_file("test_2.jpg")[1], "client_files[2]": generate_image_file("test_3.jpg")[1], "client_files[4]": generate_image_file("test_4.jpg")[1], - "client_files[5]": generate_image_file("test_5.0.jpg")[1], - "client_files[6]": generate_image_file("test_6.0.jpg")[1], - "client_files[7]": generate_image_file("test_7.0.jpg")[1], - "client_files[8]": generate_image_file("test_8.0.jpg")[1], - "client_files[9]": generate_image_file("test_9.0.jpg")[1], + "client_files[5]": generate_image_file("test_5.jpg")[1], + "client_files[6]": generate_image_file("test_6.jpg")[1], + "client_files[7]": generate_image_file("test_7.jpg")[1], + "client_files[8]": generate_image_file("test_8.jpg")[1], + "client_files[9]": generate_image_file("test_9.jpg")[1], "image_quality": 75, "frame_filter": "step=3", } From be35a52ecbadc3b68c3b2f1b459aac343bbaeeca Mon Sep 17 00:00:00 2001 From: "kirill.sizov" Date: Mon, 19 Apr 2021 12:54:40 +0300 Subject: [PATCH 9/9] add test --- .../dataset_manager/tests/test_formats.py | 329 +++++++++++++++++- 1 file changed, 327 insertions(+), 2 deletions(-) diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index 44c0cda7822d..2a7c40cdad6e 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -217,9 +217,9 @@ def _generate_annotations(self, task): } return self._generate_custom_annotations(annotations, task) - def _generate_task_images(self, count, name="image"): # pylint: disable=no-self-use + def _generate_task_images(self, count): # pylint: disable=no-self-use images = { - "client_files[%d]" % i: generate_image_file(name + "_%d.jpg" % i) + "client_files[%d]" % i: generate_image_file("image_%d.jpg" % i) for i in range(count) } images["image_quality"] = 75 @@ -496,6 +496,7 @@ def test_frames_outside_are_not_generated(self): self.assertTrue(frame.frame in range(6, 10)) self.assertEqual(i + 1, 4) + class FrameMatchingTest(_DbTestBase): def _generate_task_images(self, paths): # pylint: disable=no-self-use f = BytesIO() @@ -586,3 +587,327 @@ def test_dataset_root(self): root = find_dataset_root(dataset, task_data) self.assertEqual(expected, root) + +class TaskAnnotationsImportTest(_DbTestBase): + def _generate_custom_annotations(self, annotations, task): + self._put_api_v1_task_id_annotations(task["id"], annotations) + return annotations + + def _generate_task_images(self, count, name="image"): + images = { + "client_files[%d]" % i: generate_image_file("image_%d.jpg" % i) + for i in range(count) + } + images["image_quality"] = 75 + return images + + def _generate_task(self, images, annotation_format, **overrides): + labels = [] + if annotation_format in ["ICDAR Recognition 1.0", + "ICDAR Localization 1.0"]: + labels = [{ + "name": "icdar", + "attributes": [{ + "name": "text", + "mutable": False, + "input_type": "text", + "values": ["word1", "word2"] + }] + }] + elif annotation_format == "ICDAR Segmentation 1.0": + labels = [{ + "name": "icdar", + "attributes": [ + { + "name": "text", + "mutable": False, + "input_type": "text", + "values": ["word_1", "word_2", "word_3"] + }, + { + "name": "index", + "mutable": False, + "input_type": "number", + "values": ["0", "1", "2"] + }, + { + "name": "color", + "mutable": False, + "input_type": "text", + "values": ["100 110 240", "10 15 20", "120 128 64"] + }, + { + "name": "center", + "mutable": False, + "input_type": "text", + "values": ["1 2", "2 4", "10 45"] + }, + ] + }] + elif annotation_format == "Market-1501 1.0": + labels = [{ + "name": "market-1501", + "attributes": [ + { + "name": "query", + "mutable": False, + "input_type": "select", + "values": ["True", "False"] + }, + { + "name": "camera_id", + "mutable": False, + "input_type": "number", + "values": ["0", "1", "2", "3"] + }, + { + "name": "person_id", + "mutable": False, + "input_type": "number", + "values": ["1", "2", "3"] + }, + ] + }] + else: + labels = [ + { + "name": "car", + "attributes": [ + { + "name": "model", + "mutable": False, + "input_type": "select", + "default_value": "mazda", + "values": ["bmw", "mazda", "renault"] + }, + { + "name": "parked", + "mutable": True, + "input_type": "checkbox", + "default_value": False + } + ] + }, + {"name": "person"} + ] + + task = { + "name": "my task #1", + "overlap": 0, + "segment_size": 100, + "labels": labels + } + task.update(overrides) + return self._create_task(task, images) + + def _generate_annotations(self, task, annotation_format): + shapes = [] + tracks = [] + tags = [] + + if annotation_format in ["ICDAR Recognition 1.0", + "ICDAR Localization 1.0"]: + shapes = [{ + "frame": 0, + "label_id": task["labels"][0]["id"], + "group": 0, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][0]["attributes"][0]["id"], + "value": task["labels"][0]["attributes"][0]["values"][0] + }, + ], + "points": [1.0, 2.1, 10.6, 53.22], + "type": "rectangle", + "occluded": False, + }] + elif annotation_format == "Market-1501 1.0": + tags = [{ + "frame": 1, + "label_id": task["labels"][0]["id"], + "group": 0, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][0]["attributes"][0]["id"], + "value": task["labels"][0]["attributes"][0]["values"][1] + }, + { + "spec_id": task["labels"][0]["attributes"][1]["id"], + "value": task["labels"][0]["attributes"][1]["values"][2] + }, + { + "spec_id": task["labels"][0]["attributes"][2]["id"], + "value": task["labels"][0]["attributes"][2]["values"][0] + } + ], + }] + elif annotation_format == "ICDAR Segmentation 1.0": + shapes = [{ + "frame": 0, + "label_id": task["labels"][0]["id"], + "group": 0, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][0]["attributes"][0]["id"], + "value": task["labels"][0]["attributes"][0]["values"][0] + }, + { + "spec_id": task["labels"][0]["attributes"][1]["id"], + "value": task["labels"][0]["attributes"][1]["values"][0] + }, + { + "spec_id": task["labels"][0]["attributes"][2]["id"], + "value": task["labels"][0]["attributes"][2]["values"][1] + }, + { + "spec_id": task["labels"][0]["attributes"][3]["id"], + "value": task["labels"][0]["attributes"][3]["values"][2] + } + ], + "points": [1.0, 2.1, 10.6, 53.22], + "type": "rectangle", + "occluded": False, + }] + elif annotation_format == "VGGFace2 1.0": + shapes = [{ + "frame": 1, + "label_id": task["labels"][1]["id"], + "group": None, + "source": "manual", + "attributes": [], + "points": [2.0, 2.1, 40, 50.7], + "type": "rectangle", + "occluded": False + }] + else: + rectangle_shape_wo_attrs = { + "frame": 1, + "label_id": task["labels"][1]["id"], + "group": 0, + "source": "manual", + "attributes": [], + "points": [2.0, 2.1, 40, 50.7], + "type": "rectangle", + "occluded": False, + } + + rectangle_shape_with_attrs = { + "frame": 0, + "label_id": task["labels"][0]["id"], + "group": 0, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][0]["attributes"][0]["id"], + "value": task["labels"][0]["attributes"][0]["values"][0] + }, + { + "spec_id": task["labels"][0]["attributes"][1]["id"], + "value": task["labels"][0]["attributes"][1]["default_value"] + } + ], + "points": [1.0, 2.1, 10.6, 53.22], + "type": "rectangle", + "occluded": False, + } + + track_wo_attrs = { + "frame": 0, + "label_id": task["labels"][1]["id"], + "group": 0, + "source": "manual", + "attributes": [], + "shapes": [ + { + "frame": 0, + "attributes": [], + "points": [1.0, 2.1, 100, 300.222], + "type": "polygon", + "occluded": False, + "outside": False + } + ] + } + + tag_wo_attrs = { + "frame": 0, + "label_id": task["labels"][0]["id"], + "group": None, + "attributes": [] + } + + tag_with_attrs = { + "frame": 1, + "label_id": task["labels"][0]["id"], + "group": 3, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][0]["attributes"][0]["id"], + "value": task["labels"][0]["attributes"][0]["values"][1] + }, + { + "spec_id": task["labels"][0]["attributes"][1]["id"], + "value": task["labels"][0]["attributes"][1]["default_value"] + } + ], + } + + if annotation_format == "VGGFace2 1.0": + shapes = rectangle_shape_wo_attrs + elif annotation_format == "CVAT 1.1": + shapes = [rectangle_shape_wo_attrs, + rectangle_shape_with_attrs] + tags = [tag_with_attrs, tag_wo_attrs] + elif annotation_format == "MOTS PNG 1.0": + tracks = [track_wo_attrs] + else: + shapes = [rectangle_shape_wo_attrs, + rectangle_shape_with_attrs] + tags = tag_wo_attrs + tracks = track_wo_attrs + + annotations = { + "version": 0, + "tags": tags, + "shapes": shapes, + "tracks": tracks + } + + return self._generate_custom_annotations(annotations, task) + + def _test_can_import_annotations(self, task, import_format): + with tempfile.TemporaryDirectory() as temp_dir: + file_path = osp.join(temp_dir, import_format) + + export_format = import_format + if import_format == "CVAT 1.1": + export_format = "CVAT for images 1.1" + + dm.task.export_task(task["id"], file_path, export_format) + expected_ann = TaskAnnotation(task["id"]) + expected_ann.init_from_db() + + dm.task.import_task_annotations(task["id"], + file_path, import_format) + actual_ann = TaskAnnotation(task["id"]) + actual_ann.init_from_db() + + self.assertEqual(len(expected_ann.data), len(actual_ann.data)) + + def test_can_import_annotations_for_image_with_dots_in_filename(self): + for f in dm.views.get_import_formats(): + format_name = f.DISPLAY_NAME + + images = self._generate_task_images(3, "img0.0.0") + task = self._generate_task(images, format_name) + self._generate_annotations(task, format_name) + + with self.subTest(format=format_name): + if not f.ENABLED: + self.skipTest("Format is disabled") + + self._test_can_import_annotations(task, format_name) \ No newline at end of file