diff --git a/CHANGELOG.md b/CHANGELOG.md index f5e168ec4f2a..5f415aa19180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed multiple tasks moving () - Fixed task creating CLI parameter () +- Fixed import for MOTS format () ### Security diff --git a/cvat/apps/dataset_manager/formats/mots.py b/cvat/apps/dataset_manager/formats/mots.py index fc2d69edea99..9ba5b2268bce 100644 --- a/cvat/apps/dataset_manager/formats/mots.py +++ b/cvat/apps/dataset_manager/formats/mots.py @@ -46,15 +46,27 @@ def _import(src_file, task_data): root_hint = find_dataset_root(dataset, task_data) + shift = 0 for item in dataset: frame_number = task_data.abs_frame_id( match_dm_item(item, task_data, root_hint=root_hint)) + track_ids = set() + for ann in item.annotations: if ann.type != AnnotationType.polygon: continue track_id = ann.attributes['track_id'] + group_id = track_id + + if track_id in track_ids: + # use negative id for tracks with the same id on the same frame + shift -= 1 + track_id = shift + else: + track_ids.add(track_id) + shape = task_data.TrackedShape( type='polygon', points=ann.points, @@ -65,6 +77,7 @@ def _import(src_file, task_data): frame=frame_number, attributes=[], source='manual', + group=group_id ) # build trajectories as lists of shapes in track dict diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index 8f7edd2f7450..69c7e34797ea 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -3,22 +3,27 @@ # # SPDX-License-Identifier: MIT - -from io import BytesIO +import numpy as np import os.path as osp import tempfile import zipfile +from io import BytesIO import datumaro +from datumaro.components.dataset import Dataset, DatasetItem +from datumaro.components.extractor import Mask +from django.contrib.auth.models import Group, User from PIL import Image -from django.contrib.auth.models import User, Group -from rest_framework.test import APITestCase, APIClient + from rest_framework import status +from rest_framework.test import APIClient, APITestCase import cvat.apps.dataset_manager as dm from cvat.apps.dataset_manager.annotation import AnnotationIR -from cvat.apps.dataset_manager.bindings import TaskData, find_dataset_root, CvatTaskDataExtractor +from cvat.apps.dataset_manager.bindings import (CvatTaskDataExtractor, + TaskData, find_dataset_root) from cvat.apps.dataset_manager.task import TaskAnnotation +from cvat.apps.dataset_manager.util import make_zip_archive from cvat.apps.engine.models import Task @@ -501,7 +506,6 @@ 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() @@ -598,9 +602,10 @@ 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"): + def _generate_task_images(self, count, name="image", **image_params): images = { - "client_files[%d]" % i: generate_image_file("image_%d.jpg" % i) + "client_files[%d]" % i: generate_image_file("%s_%d.jpg" % (name, i), + **image_params) for i in range(count) } images["image_quality"] = 75 @@ -916,3 +921,36 @@ def test_can_import_annotations_for_image_with_dots_in_filename(self): self.skipTest("Format is disabled") self._test_can_import_annotations(task, format_name) + + def test_can_import_mots_annotations_with_splited_masks(self): + #https://github.com/openvinotoolkit/cvat/issues/3360 + + format_name = 'MOTS PNG 1.0' + source_dataset = Dataset.from_iterable([ + DatasetItem(id='image_0', + annotations=[ + Mask(np.array([[1, 1, 1, 0, 1, 1, 1]] * 5), + label=0, attributes={'track_id': 0}) + ] + ) + ], categories=['label_0']) + + with tempfile.TemporaryDirectory() as temp_dir: + dataset_dir = osp.join(temp_dir, 'dataset') + source_dataset.export(dataset_dir, 'mots_png') + dataset_path = osp.join(temp_dir, 'annotations.zip') + make_zip_archive(dataset_dir, dataset_path) + + images = self._generate_task_images(1, size=(5, 7)) + task = { + 'name': 'test', + "overlap": 0, + "segment_size": 100, + "labels": [{'name': 'label_0'}] + } + task.update() + task = self._create_task(task, images) + + dm.task.import_task_annotations(task['id'], dataset_path, format_name) + self._test_can_import_annotations(task, format_name) +