Skip to content
This repository was archived by the owner on Nov 14, 2023. It is now read-only.

Commit 2b1a6c9

Browse files
yasakova-anastasiamikhail-treskin
authored andcommitted
Fix loss of rotation in CVAT format (cvat-ai#5407)
Fix cvat-ai#4378
1 parent 4c5372c commit 2b1a6c9

File tree

10 files changed

+87
-22
lines changed

10 files changed

+87
-22
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428)
9090
- Fixed FBRS serverless function runtime error on images with alpha channel (<https://github.com/opencv/cvat/pull/5384>)
9191
- Attaching manifest with custom name (<https://github.com/opencv/cvat/pull/5377>)
9292
- Uploading non-zip annotaion files (<https://github.com/opencv/cvat/pull/5386>)
93+
- Loss of rotation in CVAT format (<https://github.com/opencv/cvat/pull/5407>)
9394
- A permission problem with interactive model launches for workers in orgs (<https://github.com/opencv/cvat/issues/4996>)
9495
- Fix chart not being upgradable (<https://github.com/opencv/cvat/pull/5371>)
9596
- Broken helm chart - if using custom release name (<https://github.com/opencv/cvat/pull/5403>)

cvat/apps/dataset_manager/formats/cvat.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ def _parse(cls, path):
254254
shape['type'] = el.tag
255255
shape['occluded'] = (el.attrib.get('occluded') == '1')
256256
shape['z_order'] = int(el.attrib.get('z_order', 0))
257+
shape['rotation'] = float(el.attrib.get('rotation', 0))
257258

258259
if el.tag == 'box':
259260
shape['points'] = list(map(float, [
@@ -440,6 +441,8 @@ def _parse_shape_ann(cls, ann, categories):
440441
attributes['keyframe'] = ann['keyframe']
441442
if 'track_id' in ann:
442443
attributes['track_id'] = ann['track_id']
444+
if 'rotation' in ann:
445+
attributes['rotation'] = ann['rotation']
443446

444447
group = ann.get('group')
445448

tests/python/rest_api/test_projects.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# SPDX-License-Identifier: MIT
55

66
import io
7+
import json
78
import xml.etree.ElementTree as ET
89
import zipfile
910
from copy import deepcopy
@@ -402,6 +403,14 @@ def _test_import_project(self, username, project_id, format_name, data):
402403
if response.status == HTTPStatus.CREATED:
403404
break
404405

406+
def _test_get_annotations_from_task(self, username, task_id):
407+
with make_api_client(username) as api_client:
408+
(_, response) = api_client.tasks_api.retrieve_annotations(task_id)
409+
assert response.status == HTTPStatus.OK
410+
411+
response_data = json.loads(response.data)
412+
return response_data
413+
405414
def test_can_import_dataset_in_org(self, admin_user):
406415
project_id = 4
407416

@@ -546,6 +555,33 @@ def test_exported_project_dataset_structure(
546555
content = zip_file.read(anno_file_name)
547556
check_func(content, values_to_be_checked)
548557

558+
def test_can_import_export_annotations_with_rotation(self):
559+
# https://github.com/opencv/cvat/issues/4378
560+
username = "admin1"
561+
project_id = 4
562+
563+
response = self._test_export_project(username, project_id, "CVAT for images 1.1")
564+
565+
tmp_file = io.BytesIO(response.data)
566+
tmp_file.name = "dataset.zip"
567+
568+
import_data = {
569+
"dataset_file": tmp_file,
570+
}
571+
572+
self._test_import_project(username, project_id, "CVAT 1.1", import_data)
573+
574+
response = get_method(username, f"/projects/{project_id}/tasks")
575+
assert response.status_code == HTTPStatus.OK
576+
tasks = response.json()["results"]
577+
578+
response_data = self._test_get_annotations_from_task(username, tasks[0]["id"])
579+
task1_rotation = response_data["shapes"][0]["rotation"]
580+
response_data = self._test_get_annotations_from_task(username, tasks[1]["id"])
581+
task2_rotation = response_data["shapes"][0]["rotation"]
582+
583+
assert task1_rotation == task2_rotation
584+
549585

550586
@pytest.mark.usefixtures("restore_db_per_function")
551587
class TestPatchProjectLabel:

tests/python/shared/assets/annotations.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,12 @@
376376
"occluded": false,
377377
"outside": false,
378378
"points": [
379-
106.36066411239153,
380-
85.1515964240134,
381-
240.08352490421748,
382-
241.26526181354166
379+
106.361328125,
380+
85.150390625,
381+
240.083984375,
382+
241.263671875
383383
],
384-
"rotation": 0.0,
384+
"rotation": 45.9,
385385
"source": "manual",
386386
"type": "rectangle",
387387
"z_order": 0
@@ -1121,12 +1121,12 @@
11211121
"occluded": false,
11221122
"outside": false,
11231123
"points": [
1124-
106.36066411239153,
1125-
85.1515964240134,
1126-
240.08352490421748,
1127-
241.26526181354166
1124+
106.361328125,
1125+
85.150390625,
1126+
240.083984375,
1127+
241.263671875
11281128
],
1129-
"rotation": 0.0,
1129+
"rotation": 45.9,
11301130
"source": "manual",
11311131
"type": "rectangle",
11321132
"z_order": 0
Binary file not shown.

tests/python/shared/assets/cvat_db/data.json

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"pk": 1,
3737
"fields": {
3838
"password": "pbkdf2_sha256$260000$DevmxlmLwciP1P6sZs2Qag$U9DFtjTWx96Sk95qY6UXVcvpdQEP2LcoFBftk5D2RKY=",
39-
"last_login": "2022-12-01T12:52:15.631Z",
39+
"last_login": "2022-12-05T07:46:24.795Z",
4040
"is_superuser": true,
4141
"username": "admin1",
4242
"first_name": "Admin",
@@ -455,6 +455,14 @@
455455
"user_permissions": []
456456
}
457457
},
458+
{
459+
"model": "sessions.session",
460+
"pk": "3p7i7jibc6g827i39r8e0ce5i9f1orzp",
461+
"fields": {
462+
"session_data": ".eJxVjDEOAiEQAP9CbQiwgGBp7xsIC6ycGkiOu8r4d0NyhbYzk3mzEPethn2UNSyZXZhkp1-GMT1LmyI_Yrt3nnrb1gX5TPhhB7_1XF7Xo_0b1Djq3AoglJTJACKS9zGB0eAdopNkz6TIWq2LLQ611gkEgjFJCTIChFPs8wX0UDee:1p26BE:nXJF4Fl6fGAvhi1ZZfLr4WJSgvc53poHLXXAM5V6NdU",
463+
"expire_date": "2022-12-19T07:46:24.799Z"
464+
}
465+
},
458466
{
459467
"model": "sessions.session",
460468
"pk": "5x9v6r58e4l9if78anupog0ittsq2w3j",
@@ -625,12 +633,12 @@
625633
},
626634
{
627635
"model": "authtoken.token",
628-
"pk": "4f057576712c65d30847e77456aea605a9df5965",
636+
"pk": "2dcf8d2ff5032c3cf7d276549af3a50edb4f11c8",
629637
"fields": {
630638
"user": [
631639
"admin1"
632640
],
633-
"created": "2022-09-28T12:20:48.631Z"
641+
"created": "2022-12-05T07:46:24.792Z"
634642
}
635643
},
636644
{
@@ -2279,7 +2287,7 @@
22792287
"assignee": null,
22802288
"bug_tracker": "",
22812289
"created_date": "2022-06-08T08:32:45.521Z",
2282-
"updated_date": "2022-10-17T17:09:36.526Z",
2290+
"updated_date": "2022-12-05T07:47:01.518Z",
22832291
"status": "annotation",
22842292
"organization": 2,
22852293
"source_storage": null,
@@ -2587,7 +2595,7 @@
25872595
"assignee": null,
25882596
"bug_tracker": "",
25892597
"created_date": "2022-06-08T08:33:06.505Z",
2590-
"updated_date": "2022-10-17T17:09:36.570Z",
2598+
"updated_date": "2022-12-05T07:47:01.633Z",
25912599
"overlap": 0,
25922600
"segment_size": 5,
25932601
"status": "annotation",
@@ -3671,7 +3679,7 @@
36713679
"fields": {
36723680
"segment": 17,
36733681
"assignee": null,
3674-
"updated_date": "2022-10-17T17:09:36.571Z",
3682+
"updated_date": "2022-12-05T07:47:01.633Z",
36753683
"status": "annotation",
36763684
"stage": "annotation",
36773685
"state": "in progress"
@@ -4991,6 +4999,23 @@
49914999
"job": 19
49925000
}
49935001
},
5002+
{
5003+
"model": "engine.jobcommit",
5004+
"pk": 81,
5005+
"fields": {
5006+
"scope": "create",
5007+
"owner": [
5008+
"admin1"
5009+
],
5010+
"timestamp": "2022-12-05T07:47:01.635Z",
5011+
"data": {
5012+
"stage": "annotation",
5013+
"state": "in progress",
5014+
"assignee": null
5015+
},
5016+
"job": 17
5017+
}
5018+
},
49945019
{
49955020
"model": "engine.labeledimage",
49965021
"pk": 1,
@@ -5206,8 +5231,8 @@
52065231
"occluded": false,
52075232
"outside": false,
52085233
"z_order": 0,
5209-
"points": "[106.36066411239153, 85.1515964240134, 240.08352490421748, 241.26526181354166]",
5210-
"rotation": 0.0,
5234+
"points": "[106.361328125, 85.150390625, 240.083984375, 241.263671875]",
5235+
"rotation": 45.9,
52115236
"parent": null
52125237
}
52135238
},

tests/python/shared/assets/jobs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@
273273
"status": "annotation",
274274
"stop_frame": 4,
275275
"task_id": 13,
276-
"updated_date": "2022-10-17T17:09:36.571000Z",
276+
"updated_date": "2022-12-05T07:47:01.633000Z",
277277
"url": "http://localhost:8080/api/jobs/17"
278278
},
279279
{

tests/python/shared/assets/projects.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@
406406
"tasks": [
407407
13
408408
],
409-
"updated_date": "2022-10-17T17:09:36.526000Z",
409+
"updated_date": "2022-12-05T07:47:01.518000Z",
410410
"url": "http://localhost:8080/api/projects/4"
411411
},
412412
{

tests/python/shared/assets/tasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@
379379
"status": "annotation",
380380
"subset": "",
381381
"target_storage": null,
382-
"updated_date": "2022-10-17T17:09:36.570000Z",
382+
"updated_date": "2022-12-05T07:47:01.633000Z",
383383
"url": "http://localhost:8080/api/tasks/13"
384384
},
385385
{

tests/python/shared/assets/users.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@
310310
"is_active": true,
311311
"is_staff": true,
312312
"is_superuser": true,
313-
"last_login": "2022-12-01T12:52:15.631000Z",
313+
"last_login": "2022-12-05T07:46:24.795659Z",
314314
"last_name": "First",
315315
"url": "http://localhost:8080/api/users/1",
316316
"username": "admin1"

0 commit comments

Comments
 (0)