Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add KITTI format #3757

Merged
merged 12 commits into from
Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions cvat/apps/dataset_manager/formats/kitti.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright (C) 2021 Intel Corporation
#
# SPDX-License-Identifier: MIT

import os.path as osp
from tempfile import TemporaryDirectory

from datumaro.components.dataset import Dataset
from datumaro.plugins.kitti_format.format import KittiPath, write_label_map
from pyunpack import Archive

from cvat.apps.dataset_manager.bindings import (GetCVATDataExtractor,
ProjectData, import_dm_annotations)
from cvat.apps.dataset_manager.util import make_zip_archive

from .registry import dm_env, exporter, importer
from .utils import make_colormap


@exporter(name='KITTI', ext='ZIP', version='1.0')
def _export(dst_file, instance_data, save_images=False):
dataset = Dataset.from_extractors(GetCVATDataExtractor(instance_data,
include_images=save_images), env=dm_env)

with TemporaryDirectory() as tmp_dir:
dataset.transform('polygons_to_masks')
dataset.transform('merge_instance_segments')
dataset.export(tmp_dir, format='kitti',
label_map={k: v[0] for k, v in make_colormap(instance_data).items()},
apply_colormap=True, save_images=save_images
)

make_zip_archive(tmp_dir, dst_file)

@importer(name='KITTI', ext='ZIP', version='1.0')
def _import(src_file, instance_data):
with TemporaryDirectory() as tmp_dir:
Archive(src_file.name).extractall(tmp_dir)

color_map = {k: v[0] for k, v in make_colormap(instance_data).items()}
color_map_path = osp.join(tmp_dir, KittiPath.LABELMAP_FILE)
if not osp.isfile(color_map_path):
write_label_map(color_map_path, color_map)

dataset = Dataset.import_from(tmp_dir, format='kitti', env=dm_env)
labels_meta = instance_data.meta['project']['labels'] \
if isinstance(instance_data, ProjectData) else instance_data.meta['task']['labels']
if 'background' not in [label['name'] for _, label in labels_meta]:
dataset.filter('/item/annotation[label != "background"]',
filter_annotations=True)
dataset.transform('masks_to_polygons')

import_dm_annotations(dataset, instance_data)
2 changes: 1 addition & 1 deletion cvat/apps/dataset_manager/formats/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@ def make_exporter(name):
import cvat.apps.dataset_manager.formats.icdar
import cvat.apps.dataset_manager.formats.velodynepoint
import cvat.apps.dataset_manager.formats.pointcloud

import cvat.apps.dataset_manager.formats.kitti
1 change: 0 additions & 1 deletion cvat/apps/dataset_manager/formats/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from datumaro.util.os_util import make_file_name


def get_color_from_index(index):
def get_bit(number, index):
return (number >> index) & 1
Expand Down
18 changes: 18 additions & 0 deletions cvat/apps/dataset_manager/tests/assets/annotations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1168,5 +1168,23 @@
}
],
"tracks": []
},
"KITTI 1.0": {
"version": 0,
"tags": [],
"shapes": [
{
"type": "polygon",
"occluded": false,
"z_order": 0,
"points": [10.0, 20.0, 10.0, 25.0, 20.0, 10.0, 20.0, 25.0, 10.0, 20.0],
"frame": 0,
"label_id": null,
"group": 0,
"source": "manual",
"attributes": []
}
],
"tracks": []
}
}
30 changes: 10 additions & 20 deletions cvat/apps/dataset_manager/tests/test_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ def test_export_formats_query(self):
'ICDAR Localization 1.0',
'ICDAR Segmentation 1.0',
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0'

'Sly Point Cloud Format 1.0',
'KITTI 1.0'
})

def test_import_formats_query(self):
Expand All @@ -323,6 +323,7 @@ def test_import_formats_query(self):
'ICDAR Segmentation 1.0',
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0',
'KITTI 1.0',
'Datumaro 1.0',
'Datumaro 3D 1.0'
})
Expand Down Expand Up @@ -371,6 +372,7 @@ def test_empty_images_are_exported(self):
('ICDAR Recognition 1.0', 'icdar_word_recognition'),
('ICDAR Localization 1.0', 'icdar_text_localization'),
('ICDAR Segmentation 1.0', 'icdar_text_segmentation'),
# ('KITTI 1.0', 'kitti') format does not support empty annotations
]:
with self.subTest(format=format_name):
if not dm.formats.registry.EXPORT_FORMATS[format_name].ENABLED:
Expand Down Expand Up @@ -784,25 +786,14 @@ def _generate_annotations(self, task, annotation_format):
"type": "rectangle",
"occluded": False,
}]
elif annotation_format == "VGGFace2 1.0":
shapes = [{
"frame": 1,
"label_id": task["labels"][1]["id"],
"group": None,
"source": "manual",
"attributes": [],
"points": [2.0, 2.1, 40, 50.7],
"type": "rectangle",
"occluded": False
}]
else:
rectangle_shape_wo_attrs = {
"frame": 1,
"label_id": task["labels"][1]["id"],
"group": 0,
"source": "manual",
"attributes": [],
"points": [2.0, 2.1, 40, 50.7],
"points": [2.0, 2.1, 40, 10.7],
"type": "rectangle",
"occluded": False,
}
Expand All @@ -822,7 +813,7 @@ def _generate_annotations(self, task, annotation_format):
"value": task["labels"][0]["attributes"][1]["default_value"]
}
],
"points": [1.0, 2.1, 10.6, 53.22],
"points": [1.0, 2.1, 10.6, 13.22],
"type": "rectangle",
"occluded": False,
}
Expand All @@ -837,7 +828,7 @@ def _generate_annotations(self, task, annotation_format):
{
"frame": 0,
"attributes": [],
"points": [1.0, 2.1, 10.6, 53.22, 100, 300.222],
"points": [1.0, 2.1, 10.6, 53.22, 30, 20.222],
"type": "polygon",
"occluded": False,
"outside": False
Expand Down Expand Up @@ -870,7 +861,7 @@ def _generate_annotations(self, task, annotation_format):
}

if annotation_format == "VGGFace2 1.0":
shapes = rectangle_shape_wo_attrs
shapes = [rectangle_shape_wo_attrs]
elif annotation_format == "CVAT 1.1":
shapes = [rectangle_shape_wo_attrs,
rectangle_shape_with_attrs]
Expand All @@ -880,8 +871,8 @@ def _generate_annotations(self, task, annotation_format):
else:
shapes = [rectangle_shape_wo_attrs,
rectangle_shape_with_attrs]
tags = tag_wo_attrs
tracks = track_wo_attrs
tags = [tag_wo_attrs]
tracks = [track_wo_attrs]

annotations = {
"version": 0,
Expand Down Expand Up @@ -917,7 +908,6 @@ def test_can_import_annotations_for_image_with_dots_in_filename(self):

images = self._generate_task_images(3, "img0.0.0")
task = self._generate_task(images, format_name)
self._generate_annotations(task, format_name)

with self.subTest(format=format_name):
if not f.ENABLED:
Expand Down
8 changes: 6 additions & 2 deletions cvat/apps/dataset_manager/tests/test_rest_api_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ def test_api_v1_dump_empty_frames(self):
with self.subTest(format=upload_format_name):
if upload_format_name in [
"MOTS PNG 1.0", # issue #2925 and changed points values
"KITTI 1.0", # format does not support empty annotation
]:
self.skipTest("Format is fail")
images = self._generate_task_images(3)
Expand Down Expand Up @@ -916,7 +917,8 @@ def test_api_v1_rewriting_annotations(self):
"MOT 1.1", "MOTS PNG 1.0", \
"PASCAL VOC 1.1", "Segmentation mask 1.1", \
"TFRecord 1.0", "YOLO 1.1", "ImageNet 1.0", \
"WiderFace 1.0", "VGGFace2 1.0", "Datumaro 1.0" \
"WiderFace 1.0", "VGGFace2 1.0", "KITTI 1.0", \
"Datumaro 1.0" \
]:
self._create_annotations(task, dump_format_name, "default")
else:
Expand Down Expand Up @@ -1007,6 +1009,7 @@ def test_api_v1_tasks_annotations_dump_and_upload_with_datumaro(self):
"ICDAR Segmentation 1.0", # changed points values
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0',
'KITTI 1.0', # changed points values
'Datumaro 3D 1.0'
]:
self.skipTest("Format is fail")
Expand All @@ -1028,7 +1031,8 @@ def test_api_v1_tasks_annotations_dump_and_upload_with_datumaro(self):
"MOT 1.1", "MOTS PNG 1.0", \
"PASCAL VOC 1.1", "Segmentation mask 1.1", \
"TFRecord 1.0", "YOLO 1.1", "ImageNet 1.0", \
"WiderFace 1.0", "VGGFace2 1.0", "Datumaro 1.0", \
"WiderFace 1.0", "VGGFace2 1.0", "KITTI 1.0", \
"Datumaro 1.0", \
]:
self._create_annotations(task, dump_format_name, "default")
else:
Expand Down
4 changes: 4 additions & 0 deletions cvat/apps/engine/tests/test_rest_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4811,6 +4811,10 @@ def _get_initial_annotation(annotation_format):
annotations["shapes"] = points_wo_attrs \
+ rectangle_shapes_wo_attrs

elif annotation_format == "KITTI 1.0":
annotations["shapes"] = rectangle_shapes_wo_attrs \
+ polygon_shapes_wo_attrs

elif annotation_format == "Market-1501 1.0":
tags_with_attrs = [{
"frame": 1,
Expand Down
22 changes: 11 additions & 11 deletions site/content/en/docs/manual/advanced/formats/format-coco.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ weight: 5

# [MS COCO Object Detection](http://cocodataset.org/#format-data)

- [Format specification](https://github.com/openvinotoolkit/datumaro/blob/develop/docs/formats/coco_user_manual.md#format-specification)
- [Format specification](https://openvinotoolkit.github.io/datumaro/docs/formats/coco/)

## COCO export

Downloaded file: a zip archive with the structure described [here](https://github.com/openvinotoolkit/datumaro/blob/develop/docs/formats/coco_user_manual.md#load-coco-dataset)
Downloaded file: a zip archive with the structure described [here](https://openvinotoolkit.github.io/datumaro/docs/formats/coco/#import-coco-dataset)

- supported annotations: Polygons, Rectangles
- supported attributes:
Expand All @@ -21,13 +21,13 @@ Downloaded file: a zip archive with the structure described [here](https://githu
- `score` (number) - the annotation `score` field
- arbitrary attributes - will be stored in the `attributes` annotation section

Support for COCO tasks via Datumaro is described [here](https://github.com/openvinotoolkit/datumaro/blob/develop/docs/formats/coco_user_manual.md#export-to-coco)
Support for COCO tasks via Datumaro is described [here](https://openvinotoolkit.github.io/datumaro/docs/formats/coco/#export-to-other-formats)
For example, [support for COCO keypoints over Datumaro](https://github.com/openvinotoolkit/cvat/issues/2910#issuecomment-726077582):

1. Install [Datumaro](https://github.com/openvinotoolkit/datumaro)
`pip install datumaro`
1. Export the task in the `Datumaro` format, unzip
1. Export the Datumaro project in `coco` / `coco_person_keypoints` formats
2. Export the task in the `Datumaro` format, unzip
3. Export the Datumaro project in `coco` / `coco_person_keypoints` formats
`datum export -f coco -p path/to/project [-- --save-images]`

This way, one can export CVAT points as single keypoints or
Expand All @@ -36,29 +36,29 @@ keypoint lists (without the `visibility` COCO flag).
## COCO import

Uploaded file: a single unpacked `*.json` or a zip archive with the structure described
[here](https://github.com/openvinotoolkit/datumaro/blob/develop/docs/formats/coco_user_manual.md#load-coco-dataset)
[here](https://openvinotoolkit.github.io/datumaro/docs/formats/coco/#import-coco-dataset)
(without images).

- supported annotations: Polygons, Rectangles (if the `segmentation` field is empty)

## How to create a task from MS COCO dataset

1. Download the [MS COCO dataset](https://github.com/openvinotoolkit/datumaro/blob/develop/docs/formats/coco_user_manual.md#load-COCO-dataset).
1. Download the [MS COCO dataset](https://openvinotoolkit.github.io/datumaro/docs/formats/coco/#import-coco-dataset).

For example `val images` and `instances` annotations

1. Create a CVAT task with the following labels:
2. Create a CVAT task with the following labels:

```bash
person bicycle car motorcycle airplane bus train truck boat "traffic light" "fire hydrant" "stop sign" "parking meter" bench bird cat dog horse sheep cow elephant bear zebra giraffe backpack umbrella handbag tie suitcase frisbee skis snowboard "sports ball" kite "baseball bat" "baseball glove" skateboard surfboard "tennis racket" bottle "wine glass" cup fork knife spoon bowl banana apple sandwich orange broccoli carrot "hot dog" pizza donut cake chair couch "potted plant" bed "dining table" toilet tv laptop mouse remote keyboard "cell phone" microwave oven toaster sink refrigerator book clock vase scissors "teddy bear" "hair drier" toothbrush
```

1. Select `val2017.zip` as data
3. Select `val2017.zip` as data
(See [Creating an annotation task](/docs/manual/basics/creating_an_annotation_task/)
guide for details)

2. Unpack `annotations_trainval2017.zip`
4. Unpack `annotations_trainval2017.zip`

3. click `Upload annotation` button,
5. click `Upload annotation` button,
choose `COCO 1.1` and select `instances_val2017.json`
annotation file. It can take some time.
Loading