Skip to content

Commit

Permalink
Merge branch 'develop' into sk/add-cityscapes
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikita Manovich authored Nov 9, 2021
2 parents d6d2d28 + cc1b819 commit 319e442
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
and Azure Blob Container (<https://github.com/openvinotoolkit/cvat/pull/3778>)
- The feature to remove annotations in a specified range of frames (<https://github.com/openvinotoolkit/cvat/pull/3617>)
- Add Cityscapes format (<https://github.com/openvinotoolkit/cvat/pull/3758>)
- Add Open Images V6 format (<https://github.com/openvinotoolkit/cvat/pull/3679>)

### Changed

Expand Down Expand Up @@ -47,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Migration of `dataset_repo` application (<https://github.com/openvinotoolkit/cvat/pull/3827>)
- Helm settings for external psql database were unused by backend (<https://github.com/openvinotoolkit/cvat/pull/3779>)
- Updated WSL setup for development (<https://github.com/openvinotoolkit/cvat/pull/3828>)
- Helm chart config (<https://github.com/openvinotoolkit/cvat/pull/3784>)

### Security

Expand Down
83 changes: 83 additions & 0 deletions cvat/apps/dataset_manager/formats/openimages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright (C) 2021 Intel Corporation
#
# SPDX-License-Identifier: MIT

import glob
import os.path as osp
from tempfile import TemporaryDirectory

from datumaro.components.dataset import Dataset, DatasetItem
from datumaro.plugins.open_images_format import OpenImagesPath
from datumaro.util.image import DEFAULT_IMAGE_META_FILE_NAME
from pyunpack import Archive

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

from .registry import dm_env, exporter, importer


def find_item_ids(path):
image_desc_patterns = (
OpenImagesPath.FULL_IMAGE_DESCRIPTION_FILE_NAME,
*OpenImagesPath.SUBSET_IMAGE_DESCRIPTION_FILE_PATTERNS
)

image_desc_patterns = (
osp.join(path, OpenImagesPath.ANNOTATIONS_DIR, pattern)
for pattern in image_desc_patterns
)

for pattern in image_desc_patterns:
for path in glob.glob(pattern):
with open(path, 'r') as desc:
next(desc)
for row in desc:
yield row.split(',')[0]

@exporter(name='Open Images V6', ext='ZIP', version='1.0')
def _export(dst_file, task_data, save_images=False):
dataset = Dataset.from_extractors(GetCVATDataExtractor(
task_data, include_images=save_images), env=dm_env)
dataset.transform('polygons_to_masks')
dataset.transform('merge_instance_segments')

with TemporaryDirectory() as temp_dir:
dataset.export(temp_dir, 'open_images', save_images=save_images)

make_zip_archive(temp_dir, dst_file)

@importer(name='Open Images V6', ext='ZIP', version='1.0')
def _import(src_file, task_data):
with TemporaryDirectory() as tmp_dir:
Archive(src_file.name).extractall(tmp_dir)

image_meta_path = osp.join(tmp_dir, OpenImagesPath.ANNOTATIONS_DIR,
DEFAULT_IMAGE_META_FILE_NAME)
image_meta = None

if not osp.isfile(image_meta_path):
image_meta = {}
item_ids = list(find_item_ids(tmp_dir))

root_hint = find_dataset_root(
[DatasetItem(id=item_id) for item_id in item_ids], task_data)

for item_id in item_ids:
frame_info = None
try:
frame_id = match_dm_item(DatasetItem(id=item_id),
task_data, root_hint)
frame_info = task_data.frame_info[frame_id]
except Exception: # nosec
pass
if frame_info is not None:
image_meta[item_id] = (frame_info['height'], frame_info['width'])

dataset = Dataset.import_from(tmp_dir, 'open_images',
image_meta=image_meta, env=dm_env)
dataset.transform('masks_to_polygons')
import_dm_annotations(dataset, task_data)


1 change: 1 addition & 0 deletions cvat/apps/dataset_manager/formats/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,5 @@ def make_exporter(name):
import cvat.apps.dataset_manager.formats.velodynepoint
import cvat.apps.dataset_manager.formats.pointcloud
import cvat.apps.dataset_manager.formats.cityscapes
import cvat.apps.dataset_manager.formats.openimages

29 changes: 29 additions & 0 deletions cvat/apps/dataset_manager/tests/assets/annotations.json
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,35 @@
}
]
},
"Open Images V6 1.0": {
"version": 0,
"tags": [],
"shapes": [
{
"type": "rectangle",
"occluded": false,
"z_order": 0,
"points": [1.0, 2.0, 3.0, 4.0],
"frame": 0,
"label_id": null,
"group": 0,
"source": "manual",
"attributes": []
},
{
"type": "polygon",
"occluded": false,
"z_order": 0,
"points": [1.0, 1.0, 1.0, 20.0, 20.0, 1.0, 20.0, 1.0, 1.0, 1.0],
"frame": 0,
"label_id": null,
"group": 0,
"source": "manual",
"attributes": []
}
],
"tracks": []
},
"PASCAL VOC 1.1": {
"version": 0,
"tags": [
Expand Down
4 changes: 3 additions & 1 deletion cvat/apps/dataset_manager/tests/test_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ def test_export_formats_query(self):
'ICDAR Segmentation 1.0',
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0',
'Cityscapes 1.0'
'Cityscapes 1.0',
'Open Images V6 1.0'
})

def test_import_formats_query(self):
Expand Down Expand Up @@ -324,6 +325,7 @@ def test_import_formats_query(self):
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0',
'Cityscapes 1.0',
'Open Images V6 1.0',
'Datumaro 1.0',
'Datumaro 3D 1.0'
})
Expand Down
14 changes: 8 additions & 6 deletions cvat/apps/dataset_manager/tests/test_rest_api_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,11 +916,11 @@ def test_api_v1_rewriting_annotations(self):
task = self._create_task(tasks["main"], images)
task_id = task["id"]
if dump_format_name in [
"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", "Cityscapes 1.0", \
"Datumaro 1.0" \
"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", "Cityscapes 1.0",
"Datumaro 1.0", "Open Images V6 1.0"
]:
self._create_annotations(task, dump_format_name, "default")
else:
Expand Down Expand Up @@ -1009,6 +1009,7 @@ def test_api_v1_tasks_annotations_dump_and_upload_with_datumaro(self):
"MOTS PNG 1.0", # changed points values
"Segmentation mask 1.1", # changed points values
"ICDAR Segmentation 1.0", # changed points values
"Open Images V6 1.0", # changed points values
'Kitti Raw Format 1.0',
'Sly Point Cloud Format 1.0',
'Cityscapes 1.0', # changed points value
Expand All @@ -1032,7 +1033,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", "Open Images V6 1.0", \
"Datumaro 1.0", \
]:
self._create_annotations(task, dump_format_name, "default")
else:
Expand Down
5 changes: 4 additions & 1 deletion cvat/apps/engine/tests/test_rest_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4810,10 +4810,13 @@ def _get_initial_annotation(annotation_format):
annotations["tags"] = tags_wo_attrs
annotations["shapes"] = points_wo_attrs \
+ rectangle_shapes_wo_attrs

elif annotation_format == "Cityscapes 1.0":
annotations["shapes"] = points_wo_attrs \
+ rectangle_shapes_wo_attrs
elif annotation_format == "Open Images V6 1.0":
annotations["tags"] = tags_wo_attrs
annotations["shapes"] = rectangle_shapes_wo_attrs \
+ polygon_shapes_wo_attrs

elif annotation_format == "Market-1501 1.0":
tags_with_attrs = [{
Expand Down
6 changes: 5 additions & 1 deletion helm-chart/templates/cvat_backend/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,14 @@ spec:
{{- with .Values.cvat.backend.additionalVolumeMounts }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.cvat.frontend.affinity }}
{{- with .Values.cvat.backend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.backend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if .Values.cvat.backend.defaultStorage.enabled }}
- name: cvat-backend-data
Expand Down
6 changes: 5 additions & 1 deletion helm-chart/templates/cvat_frontend/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ spec:
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.frontend.affinity }}
{{- with .Values.cvat.frontend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.frontend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
Expand Down
2 changes: 2 additions & 0 deletions helm-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cvat:
# test.io/test: test
resources: {}
affinity: {}
tolerations: []
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
Expand Down Expand Up @@ -65,6 +66,7 @@ cvat:
# test.io/test: test
resources: {}
affinity: {}
tolerations: []
# nodeAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# nodeSelectorTerms:
Expand Down
108 changes: 108 additions & 0 deletions site/content/en/docs/manual/advanced/formats/format-openimages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
linkTitle: 'Open Images V6'
weight: 15
---

# [Open Images](https://storage.googleapis.com/openimages/web/index.html)

- [Format specification](https://storage.googleapis.com/openimages/web/download.html)

- Supported annotations:

- Rectangles (detection task)
- Tags (classification task)
- Polygons (segmentation task)

- Supported attributes:

- Labels

- `score` (should be defined for labels as `text` or `number`).
The confidence level from 0 to 1.

- Bounding boxes

- `score` (should be defined for labels as `text` or `number`).
The confidence level from 0 to 1.
- `occluded` (both UI option and a separate attribute).
Whether the object is occluded by another object.
- `truncated` (should be defined for labels as `checkbox` -es).
Whether the object extends beyond the boundary of the image.
- `is_group_of` (should be defined for labels as `checkbox` -es).
Whether the object represents a group of objects of the same class.
- `is_depiction` (should be defined for labels as `checkbox` -es).
Whether the object is a depiction (such as a drawing)
rather than a real object.
- `is_inside` (should be defined for labels as `checkbox` -es).
Whether the object is seen from the inside.

- Masks
- `box_id` (should be defined for labels as `text`).
An identifier for the bounding box associated with the mask.
- `predicted_iou` (should be defined for labels as `text` or `number`).
Predicted IoU value with respect to the ground truth.

## Open Images export

Downloaded file: a zip archive of the following structure:

```
└─ taskname.zip/
├── annotations/
│ ├── bbox_labels_600_hierarchy.json
│ ├── class-descriptions.csv
| ├── images.meta # additional file with information about image sizes
│ ├── <subset_name>-image_ids_and_rotation.csv
│ ├── <subset_name>-annotations-bbox.csv
│ ├── <subset_name>-annotations-human-imagelabels.csv
│ └── <subset_name>-annotations-object-segmentation.csv
├── images/
│ ├── subset1/
│ │ ├── <image_name101.jpg>
│ │ ├── <image_name102.jpg>
│ │ └── ...
│ ├── subset2/
│ │ ├── <image_name201.jpg>
│ │ ├── <image_name202.jpg>
│ │ └── ...
| ├── ...
└── masks/
├── subset1/
│ ├── <mask_name101.png>
│ ├── <mask_name102.png>
│ └── ...
├── subset2/
│ ├── <mask_name201.png>
│ ├── <mask_name202.png>
│ └── ...
├── ...
```

## Open Images import

Uploaded file: a zip archive of the following structure:

```
└─ upload.zip/
├── annotations/
│ ├── bbox_labels_600_hierarchy.json
│ ├── class-descriptions.csv
| ├── images.meta # optional, file with information about image sizes
│ ├── <subset_name>-image_ids_and_rotation.csv
│ ├── <subset_name>-annotations-bbox.csv
│ ├── <subset_name>-annotations-human-imagelabels.csv
│ └── <subset_name>-annotations-object-segmentation.csv
└── masks/
├── subset1/
│ ├── <mask_name101.png>
│ ├── <mask_name102.png>
│ └── ...
├── subset2/
│ ├── <mask_name201.png>
│ ├── <mask_name202.png>
│ └── ...
├── ...
```

Image ids in the `<subset_name>-image_ids_and_rotation.csv` should match with
image names in the task.

0 comments on commit 319e442

Please sign in to comment.