From 279f01b53bb50bd7ac64e32ed09705f96e224d34 Mon Sep 17 00:00:00 2001 From: Anastasia Yasakova Date: Thu, 24 Nov 2022 16:22:33 +0200 Subject: [PATCH] Fix: Can't dump annotations with objects type is track from several jobs (#5250) --- CHANGELOG.md | 1 + cvat/apps/dataset_manager/annotation.py | 20 +++---- .../tests/test_rest_api_formats.py | 54 ++++++++++--------- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 991929e3..83a88898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428) - Added "type" field for all the labels, allows to reduce number of controls on annotation view () - Occluded not applied on canvas instantly for a skeleton elements () - Oriented bounding boxes broken with COCO format ss() +- Can't dump annotations with objects type is track from several jobs () - Fixed upload resumption in production environments () - Fixed job exporting () diff --git a/cvat/apps/dataset_manager/annotation.py b/cvat/apps/dataset_manager/annotation.py index 38ff78b2..16e67691 100644 --- a/cvat/apps/dataset_manager/annotation.py +++ b/cvat/apps/dataset_manager/annotation.py @@ -105,7 +105,7 @@ class AnnotationIR: if scoped_shapes: if not scoped_shapes[0]['keyframe']: segment_shapes.insert(0, scoped_shapes[0]) - if not scoped_shapes[-1]['keyframe'] and \ + if scoped_shapes[-1]['keyframe'] and \ scoped_shapes[-1]['outside']: segment_shapes.append(scoped_shapes[-1]) elif stop + 1 < len(interpolated_shapes) and \ @@ -737,11 +737,18 @@ class TrackManager(ObjectManager): return shapes shapes = [] - curr_frame = track["shapes"][0]["frame"] prev_shape = {} - for shape in track["shapes"]: + for shape in sorted(track["shapes"], key=lambda shape: shape["frame"]): + curr_frame = shape["frame"] + if end_frame <= curr_frame: + if not prev_shape: + shape["keyframe"] = True + shapes.append(shape) + prev_shape = shape + break + if prev_shape: - assert shape["frame"] > curr_frame + assert shape["frame"] > prev_shape["frame"] for attr in prev_shape["attributes"]: if attr["spec_id"] not in map(lambda el: el["spec_id"], shape["attributes"]): shape["attributes"].append(deepcopy(attr)) @@ -750,13 +757,8 @@ class TrackManager(ObjectManager): shape["keyframe"] = True shapes.append(shape) - curr_frame = shape["frame"] prev_shape = shape - # keep at least 1 shape - if end_frame <= curr_frame: - break - if not prev_shape["outside"]: shape = deepcopy(prev_shape) shape["frame"] = end_frame diff --git a/cvat/apps/dataset_manager/tests/test_rest_api_formats.py b/cvat/apps/dataset_manager/tests/test_rest_api_formats.py index 07d5bc37..cbefa3e3 100644 --- a/cvat/apps/dataset_manager/tests/test_rest_api_formats.py +++ b/cvat/apps/dataset_manager/tests/test_rest_api_formats.py @@ -785,39 +785,41 @@ class TaskDumpUploadTest(_DbTestBase): with open(file_zip_name, 'rb') as binary_file: self._upload_file(url, binary_file, self.admin) - def test_api_v2_dump_annotations_with_objects_type_is_shape_from_several_jobs(self): + def test_api_v2_dump_annotations_from_several_jobs(self): test_name = self._testMethodName - dump_format_name = "CVAT for images 1.1" + dump_formats = ["CVAT for images 1.1", "CVAT for video 1.1"] test_cases = ['all', 'first'] - images = self._generate_task_images(10) - task = self._create_task(tasks["change overlap and segment size"], images) - task_id = task["id"] + for dump_format_name in dump_formats: - for test_case in test_cases: - with TestDir() as test_dir: - jobs = self._get_jobs(task_id) - if test_case == "all": - for job in jobs: - self._create_annotations_in_job(task, job["id"], dump_format_name, "default") - else: - self._create_annotations_in_job(task, jobs[0]["id"], dump_format_name, "default") + images = self._generate_task_images(10) + task = self._create_task(tasks["change overlap and segment size"], images) + task_id = task["id"] - url = self._generate_url_dump_tasks_annotations(task_id) + for test_case in test_cases: + with TestDir() as test_dir: + jobs = self._get_jobs(task_id) + if test_case == "all": + for job in jobs: + self._create_annotations_in_job(task, job["id"], dump_format_name, "default") + else: + self._create_annotations_in_job(task, jobs[0]["id"], dump_format_name, "default") - file_zip_name = osp.join(test_dir, f'{test_name}.zip') - data = { - "format": dump_format_name, - "action": "download", - } - self._download_file(url, data, self.admin, file_zip_name) - self.assertEqual(osp.exists(file_zip_name), True) + url = self._generate_url_dump_tasks_annotations(task_id) - # remove annotations - self._remove_annotations(url, self.admin) - url = self._generate_url_upload_tasks_annotations(task_id, "CVAT 1.1") - with open(file_zip_name, 'rb') as binary_file: - self._upload_file(url, binary_file, self.admin) + file_zip_name = osp.join(test_dir, f'{test_name}.zip') + data = { + "format": dump_format_name, + "action": "download", + } + self._download_file(url, data, self.admin, file_zip_name) + self.assertEqual(osp.exists(file_zip_name), True) + + # remove annotations + self._remove_annotations(url, self.admin) + url = self._generate_url_upload_tasks_annotations(task_id, "CVAT 1.1") + with open(file_zip_name, 'rb') as binary_file: + self._upload_file(url, binary_file, self.admin) def test_api_v2_export_dataset(self): test_name = self._testMethodName