diff --git a/README.md b/README.md index dd8b68c6b56..6a65a2ea06b 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ For more information about supported formats look at the | [LabelMe 3.0](http://labelme.csail.mit.edu/Release3.0) | X | X | | [ImageNet](http://www.image-net.org) | X | X | | [CamVid](http://mi.eng.cam.ac.uk/research/projects/VideoRec/CamVid/) | X | X | +| [VGGFace2](https://github.com/ox-vgg/vgg_face2) | X | X | ## Deep learning serverless functions for automatic labeling diff --git a/cvat/apps/dataset_manager/formats/README.md b/cvat/apps/dataset_manager/formats/README.md index 38ff0676217..8e61fdbbb2d 100644 --- a/cvat/apps/dataset_manager/formats/README.md +++ b/cvat/apps/dataset_manager/formats/README.md @@ -20,6 +20,7 @@ - [TF detection API](#tfrecord) - [ImageNet](#imagenet) - [CamVid](#camvid) + - [VGGFace2](#vggface2) ## How to add a new annotation format support @@ -874,3 +875,34 @@ has own color which corresponds to a label. Uploaded file: a zip archive of the structure above - supported annotations: Polygons + +### [VGGFace2](https://github.com/ox-vgg/vgg_face2) + +#### VGGFace2 Dumper + +Downloaded file: a zip archive of the following structure: + +```bash +taskname.zip/ +├── labels.txt # optional +├── / +| ├── label0/ +| | └── image1.jpg +| └── label1/ +| └── image2.jpg +└── bb_landmark/ + ├── loose_bb_.csv + └── loose_landmark_.csv +# labels.txt +# n000001 car +label0 +label1 +``` + +- supported annotations: Rectangles, Points (landmarks - groups of 5 points) + +#### VGGFace2 Loader + +Uploaded file: a zip archive of the structure above + +- supported annotations: Rectangles, Points (landmarks - groups of 5 points) diff --git a/cvat/apps/dataset_manager/formats/registry.py b/cvat/apps/dataset_manager/formats/registry.py index 46039f25fcd..5218ff28413 100644 --- a/cvat/apps/dataset_manager/formats/registry.py +++ b/cvat/apps/dataset_manager/formats/registry.py @@ -95,3 +95,4 @@ def make_exporter(name): import cvat.apps.dataset_manager.formats.yolo import cvat.apps.dataset_manager.formats.imagenet import cvat.apps.dataset_manager.formats.camvid +import cvat.apps.dataset_manager.formats.vggface2 diff --git a/cvat/apps/dataset_manager/formats/vggface2.py b/cvat/apps/dataset_manager/formats/vggface2.py new file mode 100644 index 00000000000..528f52c76d7 --- /dev/null +++ b/cvat/apps/dataset_manager/formats/vggface2.py @@ -0,0 +1,32 @@ +# Copyright (C) 2021 Intel Corporation +# +# SPDX-License-Identifier: MIT + +import zipfile +from tempfile import TemporaryDirectory + +from datumaro.components.dataset import Dataset + +from cvat.apps.dataset_manager.bindings import CvatTaskDataExtractor, \ + import_dm_annotations +from cvat.apps.dataset_manager.util import make_zip_archive + +from .registry import dm_env, exporter, importer + + +@exporter(name='VGGFace2', ext='ZIP', version='1.0') +def _export(dst_file, task_data, save_images=False): + dataset = Dataset.from_extractors(CvatTaskDataExtractor( + task_data, include_images=save_images), env=dm_env) + with TemporaryDirectory() as temp_dir: + dataset.export(temp_dir, 'vgg_face2', save_images=save_images) + + make_zip_archive(temp_dir, dst_file) + +@importer(name='VGGFace2', ext='ZIP', version='1.0') +def _import(src_file, task_data): + with TemporaryDirectory() as tmp_dir: + zipfile.ZipFile(src_file).extractall(tmp_dir) + + dataset = Dataset.import_from(tmp_dir, 'vgg_face2', env=dm_env) + import_dm_annotations(dataset, task_data) diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index 5103da65ba3..f9b39b57436 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -282,6 +282,7 @@ def test_export_formats_query(self): 'YOLO 1.1', 'ImageNet 1.0', 'CamVid 1.0', + 'VGGFace2 1.0', }) def test_import_formats_query(self): @@ -300,6 +301,7 @@ def test_import_formats_query(self): 'YOLO 1.1', 'ImageNet 1.0', 'CamVid 1.0', + 'VGGFace2 1.0', }) def test_exports(self): @@ -312,6 +314,9 @@ def check(file_path): self.skipTest("Format is disabled") format_name = f.DISPLAY_NAME + if format_name == "VGGFace2 1.0": + self.skipTest("Format does not support multiple shapes for one item") + for save_images in { True, False }: images = self._generate_task_images(3) task = self._generate_task(images) @@ -337,6 +342,7 @@ def test_empty_images_are_exported(self): ('YOLO 1.1', 'yolo'), ('ImageNet 1.0', 'imagenet_txt'), ('CamVid 1.0', 'camvid'), + ('VGGFace2 1.0', 'vgg_face2'), ]: with self.subTest(format=format_name): if not dm.formats.registry.EXPORT_FORMATS[format_name].ENABLED: diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index d9d2c182a8e..9d37e6a71c1 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -16,8 +16,6 @@ from glob import glob from io import BytesIO from unittest import mock -import open3d as o3d -import struct import av import numpy as np @@ -739,7 +737,7 @@ def _run_api_v1_users(self, user): return response - def _check_response(self, user, response, is_full): + def _check_response(self, user, response, is_full=True): self.assertEqual(response.status_code, status.HTTP_200_OK) for user_info in response.data['results']: db_user = getattr(self, user_info['username']) @@ -3770,6 +3768,17 @@ def _get_initial_annotation(annotation_format): "occluded": False, }] + points_wo_attrs = [{ + "frame": 1, + "label_id": task["labels"][1]["id"], + "group": 0, + "source": "manual", + "attributes": [], + "points": [20.0, 0.1, 10, 3.22, 4, 7, 10, 30, 1, 2], + "type": "points", + "occluded": False, + }] + tags_wo_attrs = [{ "frame": 2, "label_id": task["labels"][1]["id"], @@ -3855,6 +3864,11 @@ def _get_initial_annotation(annotation_format): annotations["shapes"] = rectangle_shapes_wo_attrs \ + polygon_shapes_wo_attrs + elif annotation_format == "VGGFace2 1.0": + annotations["tags"] = tags_wo_attrs + annotations["shapes"] = points_wo_attrs \ + + rectangle_shapes_wo_attrs + else: raise Exception("Unknown format {}".format(annotation_format))