diff --git a/CHANGELOG.md b/CHANGELOG.md index 5727c4fd..4e53cf5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428) - Fixed FBRS serverless function runtime error on images with alpha channel () - Attaching manifest with custom name () - Uploading non-zip annotaion files () +- Loss of rotation in CVAT format () - A permission problem with interactive model launches for workers in orgs () - Fix chart not being upgradable () - Broken helm chart - if using custom release name () diff --git a/cvat/apps/dataset_manager/formats/cvat.py b/cvat/apps/dataset_manager/formats/cvat.py index dc3e8f00..4064edba 100644 --- a/cvat/apps/dataset_manager/formats/cvat.py +++ b/cvat/apps/dataset_manager/formats/cvat.py @@ -254,6 +254,7 @@ class CvatExtractor(Extractor): shape['type'] = el.tag shape['occluded'] = (el.attrib.get('occluded') == '1') shape['z_order'] = int(el.attrib.get('z_order', 0)) + shape['rotation'] = float(el.attrib.get('rotation', 0)) if el.tag == 'box': shape['points'] = list(map(float, [ @@ -440,6 +441,8 @@ class CvatExtractor(Extractor): attributes['keyframe'] = ann['keyframe'] if 'track_id' in ann: attributes['track_id'] = ann['track_id'] + if 'rotation' in ann: + attributes['rotation'] = ann['rotation'] group = ann.get('group') diff --git a/tests/python/rest_api/test_projects.py b/tests/python/rest_api/test_projects.py index 9c182327..dd9462df 100644 --- a/tests/python/rest_api/test_projects.py +++ b/tests/python/rest_api/test_projects.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: MIT import io +import json import xml.etree.ElementTree as ET import zipfile from copy import deepcopy @@ -402,6 +403,14 @@ class TestImportExportDatasetProject: if response.status == HTTPStatus.CREATED: break + def _test_get_annotations_from_task(self, username, task_id): + with make_api_client(username) as api_client: + (_, response) = api_client.tasks_api.retrieve_annotations(task_id) + assert response.status == HTTPStatus.OK + + response_data = json.loads(response.data) + return response_data + def test_can_import_dataset_in_org(self, admin_user): project_id = 4 @@ -546,6 +555,33 @@ class TestImportExportDatasetProject: content = zip_file.read(anno_file_name) check_func(content, values_to_be_checked) + def test_can_import_export_annotations_with_rotation(self): + # https://github.com/opencv/cvat/issues/4378 + username = "admin1" + project_id = 4 + + response = self._test_export_project(username, project_id, "CVAT for images 1.1") + + tmp_file = io.BytesIO(response.data) + tmp_file.name = "dataset.zip" + + import_data = { + "dataset_file": tmp_file, + } + + self._test_import_project(username, project_id, "CVAT 1.1", import_data) + + response = get_method(username, f"/projects/{project_id}/tasks") + assert response.status_code == HTTPStatus.OK + tasks = response.json()["results"] + + response_data = self._test_get_annotations_from_task(username, tasks[0]["id"]) + task1_rotation = response_data["shapes"][0]["rotation"] + response_data = self._test_get_annotations_from_task(username, tasks[1]["id"]) + task2_rotation = response_data["shapes"][0]["rotation"] + + assert task1_rotation == task2_rotation + @pytest.mark.usefixtures("restore_db_per_function") class TestPatchProjectLabel: diff --git a/tests/python/shared/assets/annotations.json b/tests/python/shared/assets/annotations.json index 7cc496b2..16e5fbd7 100644 --- a/tests/python/shared/assets/annotations.json +++ b/tests/python/shared/assets/annotations.json @@ -376,12 +376,12 @@ "occluded": false, "outside": false, "points": [ - 106.36066411239153, - 85.1515964240134, - 240.08352490421748, - 241.26526181354166 + 106.361328125, + 85.150390625, + 240.083984375, + 241.263671875 ], - "rotation": 0.0, + "rotation": 45.9, "source": "manual", "type": "rectangle", "z_order": 0 @@ -1121,12 +1121,12 @@ "occluded": false, "outside": false, "points": [ - 106.36066411239153, - 85.1515964240134, - 240.08352490421748, - 241.26526181354166 + 106.361328125, + 85.150390625, + 240.083984375, + 241.263671875 ], - "rotation": 0.0, + "rotation": 45.9, "source": "manual", "type": "rectangle", "z_order": 0 diff --git a/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 b/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 index 99db774a..39a048d6 100644 Binary files a/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 and b/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 differ diff --git a/tests/python/shared/assets/cvat_db/data.json b/tests/python/shared/assets/cvat_db/data.json index f6efcec2..d7462eb3 100644 --- a/tests/python/shared/assets/cvat_db/data.json +++ b/tests/python/shared/assets/cvat_db/data.json @@ -36,7 +36,7 @@ "pk": 1, "fields": { "password": "pbkdf2_sha256$260000$DevmxlmLwciP1P6sZs2Qag$U9DFtjTWx96Sk95qY6UXVcvpdQEP2LcoFBftk5D2RKY=", - "last_login": "2022-12-01T12:52:15.631Z", + "last_login": "2022-12-05T07:46:24.795Z", "is_superuser": true, "username": "admin1", "first_name": "Admin", @@ -455,6 +455,14 @@ "user_permissions": [] } }, +{ + "model": "sessions.session", + "pk": "3p7i7jibc6g827i39r8e0ce5i9f1orzp", + "fields": { + "session_data": ".eJxVjDEOAiEQAP9CbQiwgGBp7xsIC6ycGkiOu8r4d0NyhbYzk3mzEPethn2UNSyZXZhkp1-GMT1LmyI_Yrt3nnrb1gX5TPhhB7_1XF7Xo_0b1Djq3AoglJTJACKS9zGB0eAdopNkz6TIWq2LLQ611gkEgjFJCTIChFPs8wX0UDee:1p26BE:nXJF4Fl6fGAvhi1ZZfLr4WJSgvc53poHLXXAM5V6NdU", + "expire_date": "2022-12-19T07:46:24.799Z" + } +}, { "model": "sessions.session", "pk": "5x9v6r58e4l9if78anupog0ittsq2w3j", @@ -625,12 +633,12 @@ }, { "model": "authtoken.token", - "pk": "4f057576712c65d30847e77456aea605a9df5965", + "pk": "2dcf8d2ff5032c3cf7d276549af3a50edb4f11c8", "fields": { "user": [ "admin1" ], - "created": "2022-09-28T12:20:48.631Z" + "created": "2022-12-05T07:46:24.792Z" } }, { @@ -2279,7 +2287,7 @@ "assignee": null, "bug_tracker": "", "created_date": "2022-06-08T08:32:45.521Z", - "updated_date": "2022-10-17T17:09:36.526Z", + "updated_date": "2022-12-05T07:47:01.518Z", "status": "annotation", "organization": 2, "source_storage": null, @@ -2587,7 +2595,7 @@ "assignee": null, "bug_tracker": "", "created_date": "2022-06-08T08:33:06.505Z", - "updated_date": "2022-10-17T17:09:36.570Z", + "updated_date": "2022-12-05T07:47:01.633Z", "overlap": 0, "segment_size": 5, "status": "annotation", @@ -3671,7 +3679,7 @@ "fields": { "segment": 17, "assignee": null, - "updated_date": "2022-10-17T17:09:36.571Z", + "updated_date": "2022-12-05T07:47:01.633Z", "status": "annotation", "stage": "annotation", "state": "in progress" @@ -4991,6 +4999,23 @@ "job": 19 } }, +{ + "model": "engine.jobcommit", + "pk": 81, + "fields": { + "scope": "create", + "owner": [ + "admin1" + ], + "timestamp": "2022-12-05T07:47:01.635Z", + "data": { + "stage": "annotation", + "state": "in progress", + "assignee": null + }, + "job": 17 + } +}, { "model": "engine.labeledimage", "pk": 1, @@ -5206,8 +5231,8 @@ "occluded": false, "outside": false, "z_order": 0, - "points": "[106.36066411239153, 85.1515964240134, 240.08352490421748, 241.26526181354166]", - "rotation": 0.0, + "points": "[106.361328125, 85.150390625, 240.083984375, 241.263671875]", + "rotation": 45.9, "parent": null } }, diff --git a/tests/python/shared/assets/jobs.json b/tests/python/shared/assets/jobs.json index 627bd290..bac17fdc 100644 --- a/tests/python/shared/assets/jobs.json +++ b/tests/python/shared/assets/jobs.json @@ -273,7 +273,7 @@ "status": "annotation", "stop_frame": 4, "task_id": 13, - "updated_date": "2022-10-17T17:09:36.571000Z", + "updated_date": "2022-12-05T07:47:01.633000Z", "url": "http://localhost:8080/api/jobs/17" }, { diff --git a/tests/python/shared/assets/projects.json b/tests/python/shared/assets/projects.json index 482b983a..2b40cfdd 100644 --- a/tests/python/shared/assets/projects.json +++ b/tests/python/shared/assets/projects.json @@ -406,7 +406,7 @@ "tasks": [ 13 ], - "updated_date": "2022-10-17T17:09:36.526000Z", + "updated_date": "2022-12-05T07:47:01.518000Z", "url": "http://localhost:8080/api/projects/4" }, { diff --git a/tests/python/shared/assets/tasks.json b/tests/python/shared/assets/tasks.json index d04e65d4..dbdc7e4e 100644 --- a/tests/python/shared/assets/tasks.json +++ b/tests/python/shared/assets/tasks.json @@ -379,7 +379,7 @@ "status": "annotation", "subset": "", "target_storage": null, - "updated_date": "2022-10-17T17:09:36.570000Z", + "updated_date": "2022-12-05T07:47:01.633000Z", "url": "http://localhost:8080/api/tasks/13" }, { diff --git a/tests/python/shared/assets/users.json b/tests/python/shared/assets/users.json index af5d8066..8f545153 100644 --- a/tests/python/shared/assets/users.json +++ b/tests/python/shared/assets/users.json @@ -310,7 +310,7 @@ "is_active": true, "is_staff": true, "is_superuser": true, - "last_login": "2022-12-01T12:52:15.631000Z", + "last_login": "2022-12-05T07:46:24.795659Z", "last_name": "First", "url": "http://localhost:8080/api/users/1", "username": "admin1"