diff --git a/CHANGELOG.md b/CHANGELOG.md index 175ea3083670..e351167ea542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Pre-built [cvat_server](https://hub.docker.com/r/openvino/cvat_server) and [cvat_ui](https://hub.docker.com/r/openvino/cvat_ui) images were published on DockerHub () - Project task subsets () +- [WiderFace](http://shuoyang1213.me/WIDERFACE/) format support () +- [VGGFace2](https://github.com/ox-vgg/vgg_face2) format support () ### Changed diff --git a/README.md b/README.md index 6a65a2ea06b9..ca8b1739d6b5 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 | +| [WIDER Face](http://shuoyang1213.me/WIDERFACE/) | 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 8e61fdbbb2dd..a89cf6e1fb5f 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) + - [WIDER Face](#widerface) - [VGGFace2](#vggface2) ## How to add a new annotation format support @@ -876,6 +877,36 @@ Uploaded file: a zip archive of the structure above - supported annotations: Polygons +### [WIDER Face](http://shuoyang1213.me/WIDERFACE/) + +#### WIDER Face Dumper + +Downloaded file: a zip archive of the following structure: + +```bash +taskname.zip/ +├── labels.txt # optional +├── wider_face_split/ +│ └── wider_face__bbx_gt.txt +└── WIDER_/ + └── images/ + ├── 0--label0/ + │ └── 0_label0_image1.jpg + └── 1--label1/ + └── 1_label1_image2.jpg +``` + +- supported annotations: Rectangles (with attributes), Labels +- supported attributes: `blur`, `expression`, `illumination`, + `occluded` (both the annotation property & an attribute), `pose`, `invalid` + +#### WIDER Face Loader + +Uploaded file: a zip archive of the structure above + +- supported annotations: Rectangles (with attributes), Labels +- supported attributes: `blur`, `expression`, `illumination`, `occluded`, `pose`, `invalid` + ### [VGGFace2](https://github.com/ox-vgg/vgg_face2) #### VGGFace2 Dumper diff --git a/cvat/apps/dataset_manager/formats/registry.py b/cvat/apps/dataset_manager/formats/registry.py index 5218ff284131..c14a732d3c5c 100644 --- a/cvat/apps/dataset_manager/formats/registry.py +++ b/cvat/apps/dataset_manager/formats/registry.py @@ -95,4 +95,5 @@ 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.widerface import cvat.apps.dataset_manager.formats.vggface2 diff --git a/cvat/apps/dataset_manager/formats/widerface.py b/cvat/apps/dataset_manager/formats/widerface.py new file mode 100644 index 000000000000..7f120ffe2154 --- /dev/null +++ b/cvat/apps/dataset_manager/formats/widerface.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='WiderFace', 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, 'wider_face', save_images=save_images) + + make_zip_archive(temp_dir, dst_file) + +@importer(name='WiderFace', 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, 'wider_face', 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 f9b39b57436b..75ff51d01b41 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', + 'WiderFace 1.0', 'VGGFace2 1.0', }) @@ -301,6 +302,7 @@ def test_import_formats_query(self): 'YOLO 1.1', 'ImageNet 1.0', 'CamVid 1.0', + 'WiderFace 1.0', 'VGGFace2 1.0', }) @@ -342,6 +344,7 @@ def test_empty_images_are_exported(self): ('YOLO 1.1', 'yolo'), ('ImageNet 1.0', 'imagenet_txt'), ('CamVid 1.0', 'camvid'), + ('WiderFace 1.0', 'wider_face'), ('VGGFace2 1.0', 'vgg_face2'), ]: with self.subTest(format=format_name): diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index 9d37e6a71c10..780b6c7086dd 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -2595,6 +2595,32 @@ def _create_task(self, owner, assignee): ] }, {"name": "person"}, + { + "name": "widerface", + "attributes": [ + { + "name": "blur", + "mutable": False, + "input_type": "select", + "default_value": "0", + "values": ["0", "1", "2"] + }, + { + "name": "expression", + "mutable": False, + "input_type": "select", + "default_value": "0", + "values": ["0", "1"] + }, + { + "name": "illumination", + "mutable": False, + "input_type": "select", + "default_value": "0", + "values": ["0", "1"] + }, + ] + }, ] } @@ -3716,6 +3742,30 @@ def _get_initial_annotation(annotation_format): "occluded": False, }] + rectangle_shapes_with_wider_attrs = [{ + "frame": 0, + "label_id": task["labels"][2]["id"], + "group": 0, + "source": "manual", + "attributes": [ + { + "spec_id": task["labels"][2]["attributes"][0]["id"], + "value": task["labels"][2]["attributes"][0]["default_value"] + }, + { + "spec_id": task["labels"][2]["attributes"][1]["id"], + "value": task["labels"][2]["attributes"][1]["values"][1] + }, + { + "spec_id": task["labels"][2]["attributes"][2]["id"], + "value": task["labels"][2]["attributes"][2]["default_value"] + } + ], + "points": [1.0, 2.1, 10.6, 53.22], + "type": "rectangle", + "occluded": False, + }] + rectangle_shapes_wo_attrs = [{ "frame": 1, "label_id": task["labels"][1]["id"], @@ -3864,6 +3914,10 @@ def _get_initial_annotation(annotation_format): annotations["shapes"] = rectangle_shapes_wo_attrs \ + polygon_shapes_wo_attrs + elif annotation_format == "WiderFace 1.0": + annotations["tags"] = tags_wo_attrs + annotations["shapes"] = rectangle_shapes_with_wider_attrs + elif annotation_format == "VGGFace2 1.0": annotations["tags"] = tags_wo_attrs annotations["shapes"] = points_wo_attrs \