diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f8232d04..467916fa81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- +- Subformat importers for VOC and COCO () ### Changed - diff --git a/datumaro/components/dataset.py b/datumaro/components/dataset.py index 3cc16eb0e5..e8e1b1d813 100644 --- a/datumaro/components/dataset.py +++ b/datumaro/components/dataset.py @@ -97,22 +97,22 @@ def put(self, item): return self._data.put(item) def get(self, id, subset=None): - assert subset or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (subset or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self._data.get(id, subset) def remove(self, id, subset=None): - assert subset or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (subset or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self._data.remove(id, subset) def get_subset(self, name): - assert name or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (name or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self def subsets(self): - return { self.name or DEFAULT_SUBSET_NAME: self } + return { self.name or DEFAULT_SUBSET_NAME : self } def categories(self): return self.parent.categories() @@ -187,22 +187,24 @@ def put(self, item): return self.parent.put(item, subset=self.name) def get(self, id, subset=None): - assert subset or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (subset or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self.parent.get(id, subset=self.name) def remove(self, id, subset=None): - assert subset or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (subset or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self.parent.remove(id, subset=self.name) def get_subset(self, name): - assert name or DEFAULT_SUBSET_NAME == \ - self.name or DEFAULT_SUBSET_NAME + assert (name or DEFAULT_SUBSET_NAME) == \ + (self.name or DEFAULT_SUBSET_NAME) return self def subsets(self): - return { self.name or DEFAULT_SUBSET_NAME: self } + if (self.name or DEFAULT_SUBSET_NAME) == DEFAULT_SUBSET_NAME: + return self.parent.subsets() + return { self.name: self } def categories(self): return self.parent.categories() diff --git a/datumaro/components/extractor.py b/datumaro/components/extractor.py index e8cc4f89c9..708a6f544e 100644 --- a/datumaro/components/extractor.py +++ b/datumaro/components/extractor.py @@ -5,7 +5,7 @@ from enum import Enum from glob import iglob -from typing import Iterable, List, Dict, Optional +from typing import Callable, Iterable, List, Dict, Optional import numpy as np import os import os.path as osp @@ -672,13 +672,39 @@ def __call__(self, path, **extra_params): return project @classmethod - def _find_sources_recursive(cls, path, ext, extractor_name, - filename='*', dirname='', file_filter=None, max_depth=3): + def _find_sources_recursive(cls, path: str, ext: Optional[str], + extractor_name: str, filename: str = '*', dirname: str = '', + file_filter: Optional[Callable[[str], bool]] = None, + max_depth: int = 3): + """ + Finds sources in the specified location, using the matching pattern + to filter file names and directories. + Supposed to be used, and to be the only call in subclasses. + + Paramters: + - path - a directory or file path, where sources need to be found. + - ext - file extension to match. To match directories, + set this parameter to None or ''. Comparison is case-independent, + a starting dot is not required. + - extractor_name - the name of the associated Extractor type + - filename - a glob pattern for file names + - dirname - a glob pattern for filename prefixes + - file_filter - a callable (abspath: str) -> bool, to filter paths found + - max_depth - the maximum depth for recursive search. + + Returns: a list of source configurations + (i.e. Extractor type names and c-tor parameters) + """ + + if ext: + if not ext.startswith('.'): + ext = '.' + ext + ext = ext.lower() - if (path.endswith(ext) and osp.isfile(path)) or \ - (not ext and osp.isdir(path) and dirname and \ - os.sep + osp.normpath(dirname) + os.sep in \ - osp.abspath(path) + os.sep): + if (ext and path.lower().endswith(ext) and osp.isfile(path)) or \ + (not ext and dirname and osp.isdir(path) and \ + os.sep + osp.normpath(dirname.lower()) + os.sep in \ + osp.abspath(path.lower()) + os.sep): sources = [{'url': path, 'format': extractor_name}] else: sources = [] diff --git a/datumaro/plugins/coco_format/importer.py b/datumaro/plugins/coco_format/importer.py index 8d41376ea8..f2c68a1f74 100644 --- a/datumaro/plugins/coco_format/importer.py +++ b/datumaro/plugins/coco_format/importer.py @@ -3,19 +3,19 @@ # # SPDX-License-Identifier: MIT -from collections import defaultdict from glob import glob import logging as log import os.path as osp from datumaro.components.extractor import Importer +from datumaro.util import parse_str_enum_value from datumaro.util.log_utils import logging_disabled from .format import CocoTask class CocoImporter(Importer): - _COCO_EXTRACTORS = { + _TASKS = { CocoTask.instances: 'coco_instances', CocoTask.person_keypoints: 'coco_person_keypoints', CocoTask.captions: 'coco_captions', @@ -65,34 +65,60 @@ def __call__(self, path, **extra_params): source_name = osp.splitext(osp.basename(ann_file))[0] project.add_source(source_name, { 'url': ann_file, - 'format': self._COCO_EXTRACTORS[ann_type], + 'format': self._TASKS[ann_type], 'options': dict(extra_params), }) return project - @staticmethod - def find_sources(path): + @classmethod + def find_sources(cls, path): if path.endswith('.json') and osp.isfile(path): subset_paths = [path] else: subset_paths = glob(osp.join(path, '**', '*_*.json'), recursive=True) - subsets = defaultdict(dict) + subsets = {} for subset_path in subset_paths: name_parts = osp.splitext(osp.basename(subset_path))[0] \ .rsplit('_', maxsplit=1) - ann_type = name_parts[0] - try: - ann_type = CocoTask[ann_type] - except KeyError: - log.warning("Skipping '%s': unknown subset " - "type '%s', the only known are: %s" % \ - (subset_path, ann_type, - ', '.join(e.name for e in CocoTask))) + ann_type = parse_str_enum_value(name_parts[0], CocoTask, + default=None) + if ann_type not in cls._TASKS: continue + subset_name = name_parts[1] - subsets[subset_name][ann_type] = subset_path - return dict(subsets) + subsets.setdefault(subset_name, {})[ann_type] = subset_path + + return subsets + + +class CocoImageInfoImporter(CocoImporter): + _TASK = CocoTask.image_info + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoCaptionsImporter(CocoImporter): + _TASK = CocoTask.captions + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoInstancesImporter(CocoImporter): + _TASK = CocoTask.instances + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoPersonKeypointsImporter(CocoImporter): + _TASK = CocoTask.person_keypoints + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoLabelsImporter(CocoImporter): + _TASK = CocoTask.labels + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoPanopticImporter(CocoImporter): + _TASK = CocoTask.panoptic + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } + +class CocoStuffImporter(CocoImporter): + _TASK = CocoTask.stuff + _TASKS = { _TASK: CocoImporter._TASKS[_TASK] } diff --git a/datumaro/plugins/lfw_format.py b/datumaro/plugins/lfw_format.py index c4806647cb..004c4e9315 100644 --- a/datumaro/plugins/lfw_format.py +++ b/datumaro/plugins/lfw_format.py @@ -164,7 +164,8 @@ def get_image_name(person, image_id): class LfwImporter(Importer): @classmethod def find_sources(cls, path): - return cls._find_sources_recursive(path, LfwPath.PAIRS_FILE, 'lfw') + base, ext = osp.splitext(LfwPath.PAIRS_FILE) + return cls._find_sources_recursive(path, ext, 'lfw', filename=base) class LfwConverter(Converter): DEFAULT_IMAGE_EXT = LfwPath.IMAGE_EXT diff --git a/datumaro/plugins/voc_format/importer.py b/datumaro/plugins/voc_format/importer.py index 7da323249b..0268458d40 100644 --- a/datumaro/plugins/voc_format/importer.py +++ b/datumaro/plugins/voc_format/importer.py @@ -3,75 +3,93 @@ # # SPDX-License-Identifier: MIT -from glob import glob import os.path as osp from datumaro.components.extractor import Importer from .format import VocTask, VocPath -def find_path(root_path, path, depth=4): - level, is_found = 0, False - full_path = None - while level < depth and not is_found: - full_path = osp.join(root_path, path) - paths = glob(full_path) - if paths: - full_path = paths[0] # ignore all after the first one - is_found = osp.isdir(full_path) - else: - full_path = None - - level += 1 - root_path = osp.join(root_path, '*') - - return full_path class VocImporter(Importer): - _TASKS = [ - (VocTask.classification, 'voc_classification', 'Main'), - (VocTask.detection, 'voc_detection', 'Main'), - (VocTask.segmentation, 'voc_segmentation', 'Segmentation'), - (VocTask.person_layout, 'voc_layout', 'Layout'), - (VocTask.action_classification, 'voc_action', 'Action'), - ] + _TASKS = { + VocTask.classification: ('voc_classification', 'Main'), + VocTask.detection: ('voc_detection', 'Main'), + VocTask.segmentation: ('voc_segmentation', 'Segmentation'), + VocTask.person_layout: ('voc_layout', 'Layout'), + VocTask.action_classification: ('voc_action', 'Action'), + } def __call__(self, path, **extra_params): from datumaro.components.project import Project # cyclic import project = Project() - subset_paths = self.find_sources(path) - if len(subset_paths) == 0: + subsets = self.find_sources(path) + if len(subsets) == 0: raise Exception("Failed to find 'voc' dataset at '%s'" % path) - for task, extractor_type, subset_path in subset_paths: + for config in subsets: + subset_path = config['url'] + extractor_type = config['format'] + + task = extractor_type.split('_')[1] + + opts = dict(config.get('options') or {}) + opts.update(extra_params) + project.add_source('%s-%s' % - (task.name, osp.splitext(osp.basename(subset_path))[0]), + (task, osp.splitext(osp.basename(subset_path))[0]), { 'url': subset_path, 'format': extractor_type, - 'options': dict(extra_params), + 'options': opts, }) return project @classmethod def find_sources(cls, path): - # find root path for the dataset - root_path = path - for task, extractor_type, task_dir in cls._TASKS: - task_path = find_path(root_path, osp.join(VocPath.SUBSETS_DIR, task_dir)) - if task_path: - root_path = osp.dirname(osp.dirname(task_path)) - break - - subset_paths = [] - for task, extractor_type, task_dir in cls._TASKS: - task_path = osp.join(root_path, VocPath.SUBSETS_DIR, task_dir) - - if not osp.isdir(task_path): + subsets = [] + + # find root path for the dataset and use it for all tasks + root_path = None + for extractor_type, task_dir in cls._TASKS.values(): + if osp.isfile(path) and \ + not osp.basename(osp.dirname(path)) == task_dir: + continue + + task_subsets = cls._find_sources_recursive(root_path or path, + 'txt', extractor_type, + dirname=osp.join(VocPath.SUBSETS_DIR, task_dir), + file_filter=lambda p: '_' not in osp.basename(p), + max_depth=0 if root_path else 3) + + if not task_subsets: continue - task_subsets = [p for p in glob(osp.join(task_path, '*.txt')) - if '_' not in osp.basename(p)] - subset_paths += [(task, extractor_type, p) for p in task_subsets] - return subset_paths + + subsets.extend(task_subsets) + + if not root_path: + root_path = osp.dirname(osp.dirname( + osp.dirname(task_subsets[0]['url']))) + + return subsets + +class VocClassificationImporter(VocImporter): + _TASK = VocTask.classification + _TASKS = { _TASK: VocImporter._TASKS[_TASK] } + +class VocDetectionImporter(VocImporter): + _TASK = VocTask.detection + _TASKS = { _TASK: VocImporter._TASKS[_TASK] } + +class VocSegmentationImporter(VocImporter): + _TASK = VocTask.segmentation + _TASKS = { _TASK: VocImporter._TASKS[_TASK] } + +class VocLayoutImporter(VocImporter): + _TASK = VocTask.person_layout + _TASKS = { _TASK: VocImporter._TASKS[_TASK] } + +class VocActionImporter(VocImporter): + _TASK = VocTask.action_classification + _TASKS = { _TASK: VocImporter._TASKS[_TASK] } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/captions_train.json b/tests/assets/coco_dataset/coco/annotations/captions_train.json new file mode 100644 index 0000000000..a568285a55 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/captions_train.json @@ -0,0 +1,40 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":0, + "caption":"hello" + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/captions_val.json b/tests/assets/coco_dataset/coco/annotations/captions_val.json new file mode 100644 index 0000000000..68ad11857e --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/captions_val.json @@ -0,0 +1,46 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":0, + "caption":"world" + }, + { + "id":2, + "image_id":40, + "category_id":0, + "caption":"text" + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/image_info_train.json b/tests/assets/coco_dataset/coco/annotations/image_info_train.json new file mode 100644 index 0000000000..7753ea13e0 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/image_info_train.json @@ -0,0 +1,35 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/image_info_val.json b/tests/assets/coco_dataset/coco/annotations/image_info_val.json new file mode 100644 index 0000000000..f854a6f760 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/image_info_val.json @@ -0,0 +1,35 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/instances_train.json b/tests/assets/coco_dataset/coco/annotations/instances_train.json new file mode 100644 index 0000000000..f2fe3e9ee1 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/instances_train.json @@ -0,0 +1,64 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + }, + { + "id":3, + "name":"c", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2, + "segmentation":[ + + ], + "area":3.0, + "bbox":[ + 2.0, + 2.0, + 3.0, + 1.0 + ], + "iscrowd":0 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/instances_val.json b/tests/assets/coco_dataset/coco/annotations/instances_val.json new file mode 100644 index 0000000000..3b9bd790e7 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/instances_val.json @@ -0,0 +1,101 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + }, + { + "id":3, + "name":"c", + "supercategory":"" + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":1, + "segmentation":[ + [ + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 2.0 + ] + ], + "area":2.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 2.0 + ], + "iscrowd":0, + "attributes":{ + "x":1, + "y":"hello" + } + }, + { + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] + }, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/labels_train.json b/tests/assets/coco_dataset/coco/annotations/labels_train.json new file mode 100644 index 0000000000..fc9ce7e6a8 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/labels_train.json @@ -0,0 +1,48 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/labels_val.json b/tests/assets/coco_dataset/coco/annotations/labels_val.json new file mode 100644 index 0000000000..01f1200838 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/labels_val.json @@ -0,0 +1,53 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":1 + }, + { + "id":2, + "image_id":40, + "category_id":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/panoptic_train.json b/tests/assets/coco_dataset/coco/annotations/panoptic_train.json new file mode 100644 index 0000000000..4225c3453a --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/panoptic_train.json @@ -0,0 +1,63 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "isthing":0 + }, + { + "id":2, + "name":"b", + "supercategory":"", + "isthing":0 + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "image_id":5, + "file_name":"a.png", + "segments_info":[ + { + "id":7, + "category_id":1, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 4.0, + 4.0 + ], + "iscrowd":0 + } + ] + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/panoptic_train/a.png b/tests/assets/coco_dataset/coco/annotations/panoptic_train/a.png new file mode 100644 index 0000000000..4de88c0991 Binary files /dev/null and b/tests/assets/coco_dataset/coco/annotations/panoptic_train/a.png differ diff --git a/tests/assets/coco_dataset/coco/annotations/panoptic_val.json b/tests/assets/coco_dataset/coco/annotations/panoptic_val.json new file mode 100644 index 0000000000..5d44f745a8 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/panoptic_val.json @@ -0,0 +1,75 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "isthing":0 + }, + { + "id":2, + "name":"b", + "supercategory":"", + "isthing":0 + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "image_id":40, + "file_name":"b.png", + "segments_info":[ + { + "id":7, + "category_id":1, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":0 + }, + { + "id":20, + "category_id":2, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 + } + ] + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/panoptic_val/b.png b/tests/assets/coco_dataset/coco/annotations/panoptic_val/b.png new file mode 100644 index 0000000000..05b45f1c9d Binary files /dev/null and b/tests/assets/coco_dataset/coco/annotations/panoptic_val/b.png differ diff --git a/tests/assets/coco_dataset/coco/annotations/person_keypoints_train.json b/tests/assets/coco_dataset/coco/annotations/person_keypoints_train.json new file mode 100644 index 0000000000..7a040f99ff --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/person_keypoints_train.json @@ -0,0 +1,97 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + }, + { + "id":2, + "name":"b", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2, + "segmentation":[ + + ], + "area":3.0, + "bbox":[ + 2.0, + 2.0, + 3.0, + 1.0 + ], + "iscrowd":0, + "keypoints":[ + 0, + 0, + 0, + 0, + 2, + 1, + 4, + 1, + 2 + ], + "num_keypoints":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/person_keypoints_val.json b/tests/assets/coco_dataset/coco/annotations/person_keypoints_val.json new file mode 100644 index 0000000000..5a79259a48 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/person_keypoints_val.json @@ -0,0 +1,146 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + }, + { + "id":2, + "name":"b", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":1, + "segmentation":[ + [ + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 2.0 + ] + ], + "area":2.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 2.0 + ], + "iscrowd":0, + "attributes":{ + "x":1, + "y":"hello" + }, + "keypoints":[ + 1, + 2, + 2, + 3, + 4, + 2, + 2, + 3, + 2 + ], + "num_keypoints":3 + }, + { + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] + }, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1, + "keypoints":[ + 2, + 4, + 2, + 4, + 4, + 2, + 4, + 2, + 2 + ], + "num_keypoints":3 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/stuff_train.json b/tests/assets/coco_dataset/coco/annotations/stuff_train.json new file mode 100644 index 0000000000..33c10c8fe8 --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/stuff_train.json @@ -0,0 +1,69 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":7, + "image_id":5, + "category_id":1, + "segmentation":{ + "counts":[ + 10, + 10, + 5, + 10, + 15 + ], + "size":[ + 5, + 10 + ] + }, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 4.0, + 4.0 + ], + "iscrowd":1 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco/annotations/stuff_val.json b/tests/assets/coco_dataset/coco/annotations/stuff_val.json new file mode 100644 index 0000000000..10f309063e --- /dev/null +++ b/tests/assets/coco_dataset/coco/annotations/stuff_val.json @@ -0,0 +1,67 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] + }, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_panoptic/images/val/000000000001.jpg b/tests/assets/coco_dataset/coco/images/train/a.jpg similarity index 89% rename from tests/assets/coco_dataset/coco_panoptic/images/val/000000000001.jpg rename to tests/assets/coco_dataset/coco/images/train/a.jpg index a082a80324..222682d80b 100644 Binary files a/tests/assets/coco_dataset/coco_panoptic/images/val/000000000001.jpg and b/tests/assets/coco_dataset/coco/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_instances/images/val/000000000001.jpg b/tests/assets/coco_dataset/coco/images/val/b.jpg similarity index 100% rename from tests/assets/coco_dataset/coco_instances/images/val/000000000001.jpg rename to tests/assets/coco_dataset/coco/images/val/b.jpg diff --git a/tests/assets/coco_dataset/coco_captions/annotations/captions_train.json b/tests/assets/coco_dataset/coco_captions/annotations/captions_train.json index e360262e0c..a568285a55 100644 --- a/tests/assets/coco_dataset/coco_captions/annotations/captions_train.json +++ b/tests/assets/coco_dataset/coco_captions/annotations/captions_train.json @@ -1,54 +1,40 @@ { - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [], - "images": [{ - "id": 1, - "width": 0, - "height": 0, - "file_name": "1.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }, { - "id": 2, - "width": 0, - "height": 0, - "file_name": "2.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }], - "annotations": [{ - "id": 1, - "image_id": 1, - "category_id": 0, - "caption": "hello", - "attributes": {} - }, { - "id": 2, - "image_id": 1, - "category_id": 0, - "caption": "world", - "attributes": {} - }, { - "id": 3, - "image_id": 2, - "category_id": 0, - "caption": "test", - "attributes": {} - }] -} \ No newline at end of file + "categories":[ + + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":0, + "caption":"hello" + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_captions/annotations/captions_val.json b/tests/assets/coco_dataset/coco_captions/annotations/captions_val.json index 47d071a57d..68ad11857e 100644 --- a/tests/assets/coco_dataset/coco_captions/annotations/captions_val.json +++ b/tests/assets/coco_dataset/coco_captions/annotations/captions_val.json @@ -1,33 +1,46 @@ { - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [], - "images": [{ - "id": 1, - "width": 0, - "height": 0, - "file_name": "3.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }], - "annotations": [{ - "id": 1, - "image_id": 1, - "category_id": 0, - "caption": "word", - "attributes": {} - }] -} \ No newline at end of file + "categories":[ + + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":0, + "caption":"world" + }, + { + "id":2, + "image_id":40, + "category_id":0, + "caption":"text" + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_captions/images/train/a.jpg b/tests/assets/coco_dataset/coco_captions/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_captions/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_stuff/images/val/000000000001.jpg b/tests/assets/coco_dataset/coco_captions/images/val/b.jpg similarity index 100% rename from tests/assets/coco_dataset/coco_stuff/images/val/000000000001.jpg rename to tests/assets/coco_dataset/coco_captions/images/val/b.jpg diff --git a/tests/assets/coco_dataset/coco_image_info/annotations/image_info_default.json b/tests/assets/coco_dataset/coco_image_info/annotations/image_info_default.json deleted file mode 100644 index f2fc85a73f..0000000000 --- a/tests/assets/coco_dataset/coco_image_info/annotations/image_info_default.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" - }, - "categories": [], - "images": [{ - "id": 1, - "width": 15, - "height": 10, - "file_name": "1.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }], - "annotations": [] -} \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_image_info/annotations/image_info_train.json b/tests/assets/coco_dataset/coco_image_info/annotations/image_info_train.json new file mode 100644 index 0000000000..7753ea13e0 --- /dev/null +++ b/tests/assets/coco_dataset/coco_image_info/annotations/image_info_train.json @@ -0,0 +1,35 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_image_info/annotations/image_info_val.json b/tests/assets/coco_dataset/coco_image_info/annotations/image_info_val.json new file mode 100644 index 0000000000..f854a6f760 --- /dev/null +++ b/tests/assets/coco_dataset/coco_image_info/annotations/image_info_val.json @@ -0,0 +1,35 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_image_info/images/train/a.jpg b/tests/assets/coco_dataset/coco_image_info/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_image_info/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_image_info/images/val/b.jpg b/tests/assets/coco_dataset/coco_image_info/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_image_info/images/val/b.jpg differ diff --git a/tests/assets/coco_dataset/coco_instances/annotations/instances_train.json b/tests/assets/coco_dataset/coco_instances/annotations/instances_train.json new file mode 100644 index 0000000000..f2fe3e9ee1 --- /dev/null +++ b/tests/assets/coco_dataset/coco_instances/annotations/instances_train.json @@ -0,0 +1,64 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + }, + { + "id":3, + "name":"c", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2, + "segmentation":[ + + ], + "area":3.0, + "bbox":[ + 2.0, + 2.0, + 3.0, + 1.0 + ], + "iscrowd":0 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_instances/annotations/instances_val.json b/tests/assets/coco_dataset/coco_instances/annotations/instances_val.json index 74de288d8e..3b9bd790e7 100644 --- a/tests/assets/coco_dataset/coco_instances/annotations/instances_val.json +++ b/tests/assets/coco_dataset/coco_instances/annotations/instances_val.json @@ -1,62 +1,101 @@ { - "licenses": [ + "licenses":[ { - "name": "", - "id": 0, - "url": "" + "name":"", + "id":0, + "url":"" } ], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [ + "categories":[ { - "id": 1, - "name": "TEST", - "supercategory": "" + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + }, + { + "id":3, + "name":"c", + "supercategory":"" } ], - "images": [ + "images":[ { - "id": 1, - "width": 5, - "height": 10, - "file_name": "000000000001.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 } ], - "annotations": [ + "annotations":[ { - "id": 1, - "image_id": 1, - "category_id": 1, - "segmentation": [[0, 0, 1, 0, 1, 2, 0, 2]], - "area": 2, - "bbox": [0, 0, 1, 2], - "iscrowd": 0, - "attributes": { - "x": 1, "y": "hello" + "id":1, + "image_id":40, + "category_id":1, + "segmentation":[ + [ + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 2.0 + ] + ], + "area":2.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 2.0 + ], + "iscrowd":0, + "attributes":{ + "x":1, + "y":"hello" } }, { - "id": 2, - "image_id": 1, - "category_id": 1, - "segmentation": { - "counts": [0, 10, 5, 5, 5, 5, 0, 10, 10, 0], - "size": [10, 5] + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] }, - "area": 30, - "bbox": [0, 0, 10, 4], - "iscrowd": 1 + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 } ] - } + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_instances/images/train/a.jpg b/tests/assets/coco_dataset/coco_instances/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_instances/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_instances/images/val/b.jpg b/tests/assets/coco_dataset/coco_instances/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_instances/images/val/b.jpg differ diff --git a/tests/assets/coco_dataset/coco_labels/annotations/labels_train.json b/tests/assets/coco_dataset/coco_labels/annotations/labels_train.json index 1f790645c3..fc9ce7e6a8 100644 --- a/tests/assets/coco_dataset/coco_labels/annotations/labels_train.json +++ b/tests/assets/coco_dataset/coco_labels/annotations/labels_train.json @@ -1,44 +1,48 @@ { - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [{ - "id": 1, - "name": "a", - "supercategory": "" - }, { - "id": 2, - "name": "b", - "supercategory": "" - }], - "images": [{ - "id": 1, - "width": 0, - "height": 0, - "file_name": "1.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }], - "annotations": [{ - "id": 1, - "image_id": 1, - "category_id": 2 - }, { - "id": 2, - "image_id": 1, - "category_id": 1, - "attributes": {} - }] -} \ No newline at end of file + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_labels/annotations/labels_val.json b/tests/assets/coco_dataset/coco_labels/annotations/labels_val.json new file mode 100644 index 0000000000..01f1200838 --- /dev/null +++ b/tests/assets/coco_dataset/coco_labels/annotations/labels_val.json @@ -0,0 +1,53 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":1 + }, + { + "id":2, + "image_id":40, + "category_id":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_labels/images/train/a.jpg b/tests/assets/coco_dataset/coco_labels/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_labels/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_labels/images/val/b.jpg b/tests/assets/coco_dataset/coco_labels/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_labels/images/val/b.jpg differ diff --git a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train.json b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train.json new file mode 100644 index 0000000000..4225c3453a --- /dev/null +++ b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train.json @@ -0,0 +1,63 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "isthing":0 + }, + { + "id":2, + "name":"b", + "supercategory":"", + "isthing":0 + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "image_id":5, + "file_name":"a.png", + "segments_info":[ + { + "id":7, + "category_id":1, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 4.0, + 4.0 + ], + "iscrowd":0 + } + ] + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train/a.png b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train/a.png new file mode 100644 index 0000000000..4de88c0991 Binary files /dev/null and b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_train/a.png differ diff --git a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val.json b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val.json index c945de7ca5..5d44f745a8 100644 --- a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val.json +++ b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val.json @@ -1,75 +1,75 @@ { - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" - }, - "categories": [ - { - "id": 1, - "name": "a", - "supercategory": "", - "isthing": 1 + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - { - "id": 2, - "name": "b", - "supercategory": "", - "isthing": 1 - }, - { - "id": 3, - "name": "c", - "supercategory": "", - "isthing": 1 - }, - { - "id": 4, - "name": "d", - "supercategory": "", - "isthing": 1 - } - ], - "images": [ - { - "id": 40, - "width": 5, - "height": 1, - "file_name": "000000000001.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - } - ], - "annotations": [ - { - "image_id": 40, - "file_name": "000000000001.png", - "segments_info": [ - { - "id": 7, - "category_id": 4, - "area": 2.0, - "bbox": [2.0, 0.0, 1.0, 0.0], - "iscrowd": 0 - }, - { - "id": 20, - "category_id": 2, - "area": 2.0, - "bbox": [1.0, 0.0, 3.0, 0.0], - "iscrowd": 1 - } - ] - } - ] -} \ No newline at end of file + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "isthing":0 + }, + { + "id":2, + "name":"b", + "supercategory":"", + "isthing":0 + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "image_id":40, + "file_name":"b.png", + "segments_info":[ + { + "id":7, + "category_id":1, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":0 + }, + { + "id":20, + "category_id":2, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 + } + ] + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/000000000001.png b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/000000000001.png deleted file mode 100644 index e471bfed41..0000000000 Binary files a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/000000000001.png and /dev/null differ diff --git a/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/b.png b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/b.png new file mode 100644 index 0000000000..05b45f1c9d Binary files /dev/null and b/tests/assets/coco_dataset/coco_panoptic/annotations/panoptic_val/b.png differ diff --git a/tests/assets/coco_dataset/coco_panoptic/images/train/a.jpg b/tests/assets/coco_dataset/coco_panoptic/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_panoptic/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_panoptic/images/val/b.jpg b/tests/assets/coco_dataset/coco_panoptic/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_panoptic/images/val/b.jpg differ diff --git a/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_train.json b/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_train.json index e5c2238d17..7a040f99ff 100644 --- a/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_train.json +++ b/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_train.json @@ -1,87 +1,97 @@ { - "licenses": [{ - "name": "", - "id": 0, - "url": "" - }], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [{ - "id": 1, - "name": "a", - "supercategory": "", - "keypoints": [], - "skeleton": [ - [0, 1], - [1, 2] + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] ] - }, { - "id": 2, - "name": "b", - "supercategory": "", - "keypoints": [], - "skeleton": [ - [0, 1], - [1, 2] + }, + { + "id":2, + "name":"b", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] ] - }], - "images": [{ - "id": 1, - "width": 5, - "height": 5, - "file_name": "1.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 - }], - "annotations": [{ - "id": 3, - "image_id": 1, - "category_id": 1, - "segmentation": [], - "area": 4.0, - "bbox": [0.0, 1.0, 4.0, 1.0], - "iscrowd": 0, - "keypoints": [1, 2, 2, 0, 2, 2, 4, 1, 2], - "num_keypoints": 3 - }, { - "id": 5, - "image_id": 1, - "category_id": 0, - "segmentation": [], - "area": 4.0, - "bbox": [1.0, 2.0, 2.0, 2.0], - "iscrowd": 0, - "keypoints": [0, 0, 0, 1, 2, 1, 3, 4, 2], - "num_keypoints": 2 - }, { - "id": 1, - "image_id": 1, - "category_id": 2, - "segmentation": [ - [0.0, 0.0, 4.0, 0.0, 4.0, 4.0] + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":5, + "category_id":2, + "segmentation":[ + + ], + "area":3.0, + "bbox":[ + 2.0, + 2.0, + 3.0, + 1.0 + ], + "iscrowd":0, + "keypoints":[ + 0, + 0, + 0, + 0, + 2, + 1, + 4, + 1, + 2 ], - "area": 6.0, - "bbox": [0.0, 0.0, 4.0, 4.0], - "iscrowd": 0, - "keypoints": [0, 0, 0, 0, 2, 1, 4, 1, 2], - "num_keypoints": 2 - }, { - "id": 2, - "image_id": 1, - "category_id": 0, - "segmentation": [], - "area": 4.0, - "bbox": [1.0, 2.0, 2.0, 2.0], - "iscrowd": 0, - "keypoints": [1, 2, 2, 3, 4, 2, 2, 3, 2], - "num_keypoints": 3 - }] -} \ No newline at end of file + "num_keypoints":2 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_val.json b/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_val.json new file mode 100644 index 0000000000..5a79259a48 --- /dev/null +++ b/tests/assets/coco_dataset/coco_person_keypoints/annotations/person_keypoints_val.json @@ -0,0 +1,146 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + }, + { + "id":2, + "name":"b", + "supercategory":"", + "keypoints":[ + + ], + "skeleton":[ + [ + 0, + 1 + ], + [ + 1, + 2 + ] + ] + } + ], + "images":[ + { + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":1, + "image_id":40, + "category_id":1, + "segmentation":[ + [ + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 2.0, + 0.0, + 2.0 + ] + ], + "area":2.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 2.0 + ], + "iscrowd":0, + "attributes":{ + "x":1, + "y":"hello" + }, + "keypoints":[ + 1, + 2, + 2, + 3, + 4, + 2, + 2, + 3, + 2 + ], + "num_keypoints":3 + }, + { + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] + }, + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1, + "keypoints":[ + 2, + 4, + 2, + 4, + 4, + 2, + 4, + 2, + 2 + ], + "num_keypoints":3 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_person_keypoints/images/train/a.jpg b/tests/assets/coco_dataset/coco_person_keypoints/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_person_keypoints/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_person_keypoints/images/val/b.jpg b/tests/assets/coco_dataset/coco_person_keypoints/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_person_keypoints/images/val/b.jpg differ diff --git a/tests/assets/coco_dataset/coco_stuff/annotations/stuff_train.json b/tests/assets/coco_dataset/coco_stuff/annotations/stuff_train.json new file mode 100644 index 0000000000..33c10c8fe8 --- /dev/null +++ b/tests/assets/coco_dataset/coco_stuff/annotations/stuff_train.json @@ -0,0 +1,69 @@ +{ + "licenses":[ + { + "name":"", + "id":0, + "url":"" + } + ], + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" + }, + "categories":[ + { + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" + } + ], + "images":[ + { + "id":5, + "width":10, + "height":5, + "file_name":"a.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 + } + ], + "annotations":[ + { + "id":7, + "image_id":5, + "category_id":1, + "segmentation":{ + "counts":[ + 10, + 10, + 5, + 10, + 15 + ], + "size":[ + 5, + 10 + ] + }, + "area":20.0, + "bbox":[ + 2.0, + 0.0, + 4.0, + 4.0 + ], + "iscrowd":1 + } + ] + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_stuff/annotations/stuff_val.json b/tests/assets/coco_dataset/coco_stuff/annotations/stuff_val.json index 51a654f9d1..10f309063e 100644 --- a/tests/assets/coco_dataset/coco_stuff/annotations/stuff_val.json +++ b/tests/assets/coco_dataset/coco_stuff/annotations/stuff_val.json @@ -1,50 +1,67 @@ { - "licenses": [ + "licenses":[ { - "name": "", - "id": 0, - "url": "" + "name":"", + "id":0, + "url":"" } ], - "info": { - "contributor": "", - "date_created": "", - "description": "", - "url": "", - "version": "", - "year": "" + "info":{ + "contributor":"", + "date_created":"", + "description":"", + "url":"", + "version":"", + "year":"" }, - "categories": [ + "categories":[ { - "id": 1, - "name": "TEST", - "supercategory": "" + "id":1, + "name":"a", + "supercategory":"" + }, + { + "id":2, + "name":"b", + "supercategory":"" } ], - "images": [ + "images":[ { - "id": 1, - "width": 5, - "height": 10, - "file_name": "000000000001.jpg", - "license": 0, - "flickr_url": "", - "coco_url": "", - "date_captured": 0 + "id":40, + "width":5, + "height":10, + "file_name":"b.jpg", + "license":0, + "flickr_url":"", + "coco_url":"", + "date_captured":0 } ], - "annotations": [ + "annotations":[ { - "id": 2, - "image_id": 1, - "category_id": 1, - "segmentation": { - "counts": [0, 10, 5, 5, 5, 5, 0, 10, 10, 0], - "size": [10, 5] + "id":2, + "image_id":40, + "category_id":2, + "segmentation":{ + "counts":[ + 0, + 20, + 30 + ], + "size":[ + 10, + 5 + ] }, - "area": 30, - "bbox": [0, 0, 10, 4], - "iscrowd": 0 + "area":20.0, + "bbox":[ + 0.0, + 0.0, + 1.0, + 9.0 + ], + "iscrowd":1 } ] - } + } \ No newline at end of file diff --git a/tests/assets/coco_dataset/coco_stuff/images/train/a.jpg b/tests/assets/coco_dataset/coco_stuff/images/train/a.jpg new file mode 100644 index 0000000000..222682d80b Binary files /dev/null and b/tests/assets/coco_dataset/coco_stuff/images/train/a.jpg differ diff --git a/tests/assets/coco_dataset/coco_stuff/images/val/b.jpg b/tests/assets/coco_dataset/coco_stuff/images/val/b.jpg new file mode 100644 index 0000000000..8bce84d3bf Binary files /dev/null and b/tests/assets/coco_dataset/coco_stuff/images/val/b.jpg differ diff --git a/tests/assets/voc_dataset/voc_dataset1/Annotations/2007_000001.xml b/tests/assets/voc_dataset/voc_dataset1/Annotations/2007_000001.xml index 4f1e25a211..04995b5736 100644 --- a/tests/assets/voc_dataset/voc_dataset1/Annotations/2007_000001.xml +++ b/tests/assets/voc_dataset/voc_dataset1/Annotations/2007_000001.xml @@ -3,8 +3,8 @@ VOC2007 2007_000001.jpg - 10 - 20 + 20 + 10 3 1 diff --git a/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000001.jpg b/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000001.jpg index 6c07340b73..cd08aa3038 100644 Binary files a/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000001.jpg and b/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000001.jpg differ diff --git a/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000002.jpg b/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000002.jpg index 3c81296b31..cd08aa3038 100644 Binary files a/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000002.jpg and b/tests/assets/voc_dataset/voc_dataset1/JPEGImages/2007_000002.jpg differ diff --git a/tests/assets/voc_dataset/voc_dataset1/SegmentationClass/2007_000001.png b/tests/assets/voc_dataset/voc_dataset1/SegmentationClass/2007_000001.png index 0b92051452..65f71759e6 100644 Binary files a/tests/assets/voc_dataset/voc_dataset1/SegmentationClass/2007_000001.png and b/tests/assets/voc_dataset/voc_dataset1/SegmentationClass/2007_000001.png differ diff --git a/tests/assets/voc_dataset/voc_dataset1/SegmentationObject/2007_000001.png b/tests/assets/voc_dataset/voc_dataset1/SegmentationObject/2007_000001.png index ebbeee61dd..67b82d980a 100644 Binary files a/tests/assets/voc_dataset/voc_dataset1/SegmentationObject/2007_000001.png and b/tests/assets/voc_dataset/voc_dataset1/SegmentationObject/2007_000001.png differ diff --git a/tests/cli/test_voc_format.py b/tests/cli/test_voc_format.py index a707a46513..5fe6a0d4ac 100644 --- a/tests/cli/test_voc_format.py +++ b/tests/cli/test_voc_format.py @@ -1,7 +1,7 @@ import os.path as osp -import numpy as np from collections import OrderedDict +import numpy as np from unittest import TestCase import datumaro.plugins.voc_format.format as VOC @@ -12,25 +12,30 @@ from ..requirements import Requirements, mark_requirement DUMMY_DATASETS_DIR = osp.join(__file__[:__file__.rfind(osp.join('tests', ''))], - 'tests', 'assets', 'voc_dataset') + 'tests', 'assets', 'voc_dataset') def run(test, *args, expected_code=0): test.assertEqual(expected_code, main(args), str(args)) class VocIntegrationScenarios(TestCase): - def _test_can_save_and_load(self, project_path, source_path, source_dataset, - dataset_format, result_path=None, label_map=None): + def _test_can_save_and_load(self, project_path, source_path, expected_dataset, + dataset_format, result_path='', label_map=None): run(self, 'create', '-o', project_path) - run(self, 'add', 'path', '-p', project_path, '-f', dataset_format, source_path) + run(self, 'add', 'path', '-p', project_path, '-f', dataset_format, + source_path) - result_dir = osp.join(project_path, 'voc_dataset') + result_dir = osp.join(project_path, 'result') + extra_args = ['--', '--save-images'] + if label_map: + extra_args += ['--label-map', label_map] run(self, 'export', '-f', dataset_format, '-p', project_path, - '-o', result_dir, '--', '--label-map', label_map) + '-o', result_dir, *extra_args) - result_path = osp.join(result_dir, result_path) if result_path else result_dir - target_dataset = Dataset.import_from(result_path, dataset_format) - compare_datasets(self, source_dataset, target_dataset) + result_path = osp.join(result_dir, result_path) + parsed_dataset = Dataset.import_from(result_path, dataset_format) + compare_datasets(self, expected_dataset, parsed_dataset, + require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_preparing_dataset_for_train_model(self): @@ -85,12 +90,12 @@ def test_preparing_dataset_for_train_model(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_convert_to_voc_format(self): - label_map = OrderedDict(('label_' + str(i), [None, [], []]) for i in range(10)) + label_map = OrderedDict(('label_%s' % i, [None, [], []]) for i in range(10)) label_map['background'] = [None, [], []] label_map.move_to_end('background', last=False) source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', subset='train', + DatasetItem(id='1', subset='train', image=np.ones((10, 15, 3)), annotations=[ Bbox(0.0, 2.0, 4.0, 2.0, attributes={ @@ -121,18 +126,19 @@ def test_convert_to_voc_format(self): voc_export = osp.join(test_dir, 'voc_export') run(self, 'export', '-p', test_dir, '-f', 'voc', - '-o', voc_export) + '-o', voc_export, '--', '--save-images') parsed_dataset = Dataset.import_from(voc_export, format='voc') - compare_datasets(self, source_dataset, parsed_dataset) + compare_datasets(self, source_dataset, parsed_dataset, + require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_voc_dataset(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[Label(i) for i in range(22) if i % 2 == 1] + [ - Bbox(4.0, 5.0, 2.0, 2.0, label=15, + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=1, group=1, attributes={ 'difficult': False, 'truncated': False, @@ -142,26 +148,21 @@ def test_can_save_and_load_voc_dataset(self): for a in VOC.VocAction } }, - id=1, group=1 ), - Bbox(1.0, 2.0, 2.0, 2.0, label=8, + Bbox(1.0, 2.0, 2.0, 2.0, label=8, id=2, group=2, attributes={ 'difficult': False, 'truncated': True, 'occluded': False, 'pose': 'Unspecified' - }, - id=2, group=2 - ), - Bbox(5.5, 6.0, 2.0, 2.0, label=22, - id=0, group=1 + } ), - Mask(image=np.ones([5, 10]), label=2, group=1) - ] - ), + Bbox(5.5, 6.0, 2.0, 2.0, label=22, id=0, group=1), + Mask(image=np.ones([10, 20]), label=2, group=1), + ]), + DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3)) - ) + image=np.ones((10, 20, 3))) ], categories=VOC.make_voc_categories()) voc_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -173,9 +174,9 @@ def test_can_save_and_load_voc_dataset(self): def test_can_save_and_load_voc_layout_dataset(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[ - Bbox(4.0, 5.0, 2.0, 2.0, label=15, + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=1, group=1, attributes={ 'difficult': False, 'truncated': False, @@ -184,31 +185,70 @@ def test_can_save_and_load_voc_layout_dataset(self): a.name : a.value % 2 == 1 for a in VOC.VocAction } - }, - id=1, group=1 - ), - Bbox(5.5, 6.0, 2.0, 2.0, label=22, - id=0, group=1 + } ), - ] - ), + Bbox(5.5, 6.0, 2.0, 2.0, label=22, id=0, group=1), + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), ], categories=VOC.make_voc_categories()) - voc_layout_path = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1', - 'ImageSets', 'Layout', 'train.txt') + dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') + rpath = osp.join('ImageSets', 'Layout', 'train.txt') + matrix = [ + ('voc_layout', '', ''), + ('voc_layout', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + source = source_dataset.get_subset(subset) + else: + source = source_dataset + + with TestDir() as test_dir: + self._test_can_save_and_load(test_dir, + osp.join(dataset_dir, path), source, + format, result_path=path, label_map='voc') - with TestDir() as test_dir: - result_voc_path = osp.join('ImageSets', 'Layout', 'train.txt') - self._test_can_save_and_load(test_dir, voc_layout_path, source_dataset, - 'voc_layout', result_path=result_voc_path, label_map='voc') + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_classification_dataset(self): + source_dataset = Dataset.from_iterable([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[Label(i) for i in range(22) if i % 2 == 1]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) + + dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') + rpath = osp.join('ImageSets', 'Main', 'train.txt') + matrix = [ + ('voc_classification', '', ''), + ('voc_classification', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + source = source_dataset.get_subset(subset) + else: + source = source_dataset + + with TestDir() as test_dir: + self._test_can_save_and_load(test_dir, + osp.join(dataset_dir, path), source, + format, result_path=path, label_map='voc') @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_voc_detect_dataset(self): + def test_can_save_and_load_voc_detection_dataset(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[ - Bbox(4.0, 5.0, 2.0, 2.0, label=15, + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, attributes={ 'difficult': False, 'truncated': False, @@ -217,56 +257,79 @@ def test_can_save_and_load_voc_detect_dataset(self): a.name : a.value % 2 == 1 for a in VOC.VocAction } - }, - id=2, group=2 + } ), - Bbox(1.0, 2.0, 2.0, 2.0, label=8, + Bbox(1.0, 2.0, 2.0, 2.0, label=8, id=1, group=1, attributes={ 'difficult': False, 'truncated': True, 'occluded': False, 'pose': 'Unspecified' - }, - id=1, group=1 + } ) - ] - ), - ], categories=VOC.make_voc_categories()) + ]), - voc_detection_path = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1', - 'ImageSets', 'Main', 'train.txt') + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) - with TestDir() as test_dir: - result_voc_path = osp.join('ImageSets', 'Main', 'train.txt') - self._test_can_save_and_load(test_dir, voc_detection_path, source_dataset, - 'voc_detection', result_path=result_voc_path, label_map='voc') + dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') + rpath = osp.join('ImageSets', 'Main', 'train.txt') + matrix = [ + ('voc_detection', '', ''), + ('voc_detection', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + source = source_dataset.get_subset(subset) + else: + source = source_dataset + + with TestDir() as test_dir: + self._test_can_save_and_load(test_dir, + osp.join(dataset_dir, path), source, + format, result_path=path, label_map='voc') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_voc_segmentation_dataset(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[ - Mask(image=np.ones([5, 10]), label=2, group=1) - ] - ) - ], categories=VOC.make_voc_categories()) + Mask(image=np.ones([10, 20]), label=2, group=1) + ]), - voc_segm_path = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1', - 'ImageSets', 'Segmentation', 'train.txt') + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) - with TestDir() as test_dir: - result_voc_path = osp.join('ImageSets', 'Segmentation', 'train.txt') - self._test_can_save_and_load(test_dir, voc_segm_path, source_dataset, - 'voc_segmentation', result_path=result_voc_path, label_map='voc') + dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') + rpath = osp.join('ImageSets', 'Segmentation', 'train.txt') + matrix = [ + ('voc_segmentation', '', ''), + ('voc_segmentation', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + source = source_dataset.get_subset(subset) + else: + source = source_dataset + + with TestDir() as test_dir: + self._test_can_save_and_load(test_dir, + osp.join(dataset_dir, path), source, + format, result_path=path, label_map='voc') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_voc_action_dataset(self): - source_dataset = Dataset.from_iterable([ + expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[ - Bbox(4.0, 5.0, 2.0, 2.0, label=15, + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=1, group=1, attributes={ 'difficult': False, 'truncated': False, @@ -275,17 +338,29 @@ def test_can_save_and_load_voc_action_dataset(self): a.name : a.value % 2 == 1 for a in VOC.VocAction } - }, - id=1, group=1 + } ) - ] - ) - ], categories=VOC.make_voc_categories()) + ]), - voc_act_path = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1', - 'ImageSets', 'Action', 'train.txt') + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) - with TestDir() as test_dir: - result_voc_path = osp.join('ImageSets', 'Action', 'train.txt') - self._test_can_save_and_load(test_dir, voc_act_path, source_dataset, - 'voc_action', result_path=result_voc_path, label_map='voc') + dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') + rpath = osp.join('ImageSets', 'Action', 'train.txt') + matrix = [ + ('voc_action', '', ''), + ('voc_action', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with TestDir() as test_dir: + self._test_can_save_and_load(test_dir, + osp.join(dataset_dir, path), expected, + format, result_path=path, label_map='voc') diff --git a/tests/cli/test_yolo_format.py b/tests/cli/test_yolo_format.py index 2ff047a010..e5c23371c0 100644 --- a/tests/cli/test_yolo_format.py +++ b/tests/cli/test_yolo_format.py @@ -68,10 +68,11 @@ def test_can_export_mot_as_yolo(self): def test_can_convert_voc_to_yolo(self): target_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), annotations=[ - Bbox(8.0, 2.5, 4.0, 1.0, label=15), - Bbox(2.0, 1.0, 4.0, 1.0, label=8), - Bbox(11.0, 3.0, 4.0, 1.0, label=22) + Bbox(1.0, 2.0, 2.0, 2.0, label=8), + Bbox(4.0, 5.0, 2.0, 2.0, label=15), + Bbox(5.5, 6, 2, 2, label=22), ] ) ], categories=[label.name for label in @@ -86,7 +87,8 @@ def test_can_convert_voc_to_yolo(self): '-f', 'yolo', '-o', yolo_dir, '--', '--save-images') parsed_dataset = Dataset.import_from(yolo_dir, format='yolo') - compare_datasets(self, target_dataset, parsed_dataset) + compare_datasets(self, target_dataset, parsed_dataset, + require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_ignore_non_supported_subsets(self): diff --git a/tests/test_coco_format.py b/tests/test_coco_format.py index c1b033d4f4..309f4efad9 100644 --- a/tests/test_coco_format.py +++ b/tests/test_coco_format.py @@ -1,10 +1,11 @@ from functools import partial -import numpy as np +from itertools import product import os import os.path as osp - from unittest import TestCase +import numpy as np + from datumaro.components.dataset import Dataset from datumaro.components.extractor import (DatasetItem, AnnotationType, Label, Mask, Points, Polygon, Bbox, Caption, @@ -20,7 +21,10 @@ CocoPanopticConverter, CocoStuffConverter, ) -from datumaro.plugins.coco_format.importer import CocoImporter +from datumaro.plugins.coco_format.importer import (CocoCaptionsImporter, + CocoImageInfoImporter, CocoImporter, CocoInstancesImporter, + CocoLabelsImporter, CocoPanopticImporter, CocoPersonKeypointsImporter, + CocoStuffImporter) from datumaro.util.image import Image from datumaro.util.test_utils import (TestDir, compare_datasets, test_save_and_load) @@ -33,168 +37,307 @@ class CocoImporterTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_instances(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000000001', image=np.ones((10, 5, 3)), - subset='val', attributes={'id': 1}, + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, + annotations=[ + Bbox(2, 2, 3, 1, label=1, + group=1, id=1, attributes={'is_crowd': False}) + ] + ), + + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}, annotations=[ Polygon([0, 0, 1, 0, 1, 2, 0, 2], label=0, id=1, group=1, attributes={'is_crowd': False, 'x': 1, 'y': 'hello'}), - Mask(np.array( - [[1, 0, 0, 1, 0]] * 5 + - [[1, 1, 1, 1, 0]] * 5 - ), label=0, + Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=1, id=2, group=2, attributes={'is_crowd': True}), ] ), - ], categories=['TEST',]) - - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_instances'), 'coco') - - compare_datasets(self, expected_dataset, dataset) + ], categories=['a', 'b', 'c']) + + formats = ['coco', 'coco_instances'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_instances')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_instances', + 'annotations', 'instances_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_instances', + 'annotations', 'instances_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_captions(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, annotations=[ Caption('hello', id=1, group=1), - Caption('world', id=2, group=2), - ], attributes={'id': 1}), - DatasetItem(id=2, subset='train', - annotations=[ - Caption('test', id=3, group=3), - ], attributes={'id': 2}), + ]), - DatasetItem(id=3, subset='val', + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}, annotations=[ - Caption('word', id=1, group=1), - ], attributes={'id': 1}), - ]) - - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_captions'), 'coco') + Caption('world', id=1, group=1), + Caption('text', id=2, group=2), + ]), + ]) - compare_datasets(self, expected_dataset, dataset) + formats = ['coco', 'coco_captions'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_captions')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_captions', + 'annotations', 'captions_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_captions', + 'annotations', 'captions_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_labels(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, annotations=[ Label(1, id=1, group=1), - Label(0, id=2, group=2), - ], attributes={'id': 1}), - ], categories=['a', 'b']) + ]), - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_labels'), 'coco') + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}, + annotations=[ + Label(0, id=1, group=1), + Label(1, id=2, group=2), + ]), + ], categories=['a', 'b']) - compare_datasets(self, expected_dataset, dataset) + formats = ['coco', 'coco_labels'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_labels')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_labels', + 'annotations', 'labels_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_labels', + 'annotations', 'labels_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_import_points(self): + def test_can_import_keypoints(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', - image=Image(path='1.jpg', size=(5, 5)), + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, annotations=[ - Points([0, 0, 0, 2, 4, 1], [0, 1, 2], - label=1, group=1, id=1, - attributes={'is_crowd': False}), - Polygon([0, 0, 4, 0, 4, 4], - label=1, group=1, id=1, - attributes={'is_crowd': False}), - - Points([1, 2, 3, 4, 2, 3], - group=2, id=2, - attributes={'is_crowd': False}), - Bbox(1, 2, 2, 2, - group=2, id=2, - attributes={'is_crowd': False}), - - Points([1, 2, 0, 2, 4, 1], - label=0, group=3, id=3, - attributes={'is_crowd': False}), - Bbox(0, 1, 4, 1, - label=0, group=3, id=3, - attributes={'is_crowd': False}), - - Points([0, 0, 1, 2, 3, 4], [0, 1, 2], - group=5, id=5, - attributes={'is_crowd': False}), - Bbox(1, 2, 2, 2, - group=5, id=5, - attributes={'is_crowd': False}), - ], attributes={'id': 1}), - ], categories={ - AnnotationType.label: LabelCategories.from_iterable(['a', 'b']), - AnnotationType.points: PointsCategories.from_iterable( - (i, None, [[0, 1], [1, 2]]) for i in range(2) - ), - }) + Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=1, + id=1, group=1, attributes={'is_crowd': False}), + Bbox(2, 2, 3, 1, label=1, + id=1, group=1, attributes={'is_crowd': False}), + ]), - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_person_keypoints'), 'coco') + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}, + annotations=[ + Points([1, 2, 3, 4, 2, 3], label=0, + id=1, group=1, attributes={'is_crowd': False, + 'x': 1, 'y': 'hello'}), + Polygon([0, 0, 1, 0, 1, 2, 0, 2], label=0, + id=1, group=1, attributes={'is_crowd': False, + 'x': 1, 'y': 'hello'}), - compare_datasets(self, expected_dataset, dataset) + Points([2, 4, 4, 4, 4, 2], label=1, + id=2, group=2, attributes={'is_crowd': True}), + Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=1, + id=2, group=2, attributes={'is_crowd': True}), + ]), + ], categories={ + AnnotationType.label: LabelCategories.from_iterable(['a', 'b']), + AnnotationType.points: PointsCategories.from_iterable( + (i, None, [[0, 1], [1, 2]]) for i in range(2) + ), + }) + + formats = ['coco', 'coco_person_keypoints'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_person_keypoints')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_person_keypoints', + 'annotations', 'person_keypoints_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_person_keypoints', + 'annotations', 'person_keypoints_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_image_info(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=Image(path='1.jpg', size=(10, 15)), - attributes={'id': 1}), + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}), + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}) ]) - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_image_info'), 'coco') - - compare_datasets(self, expected_dataset, dataset) + formats = ['coco', 'coco_image_info'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_image_info')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_image_info', + 'annotations', 'image_info_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_image_info', + 'annotations', 'image_info_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_panoptic(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000000001', - image=np.ones((1, 5, 3)), - subset='val', + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, + annotations=[ + Mask(np.array( + [[0, 0, 1, 1, 0, 1, 1, 0, 0, 0]] * 5 + ), label=0, + id=7, group=7, attributes={'is_crowd': False}), + ]), + + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), attributes={'id': 40}, annotations=[ - Mask(image=np.array([[0, 0, 1, 1, 0]]), label=3, + Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=0, id=7, group=7, attributes={'is_crowd': False}), - Mask(image=np.array([[0, 1, 0, 0, 1]]), label=1, + Mask(np.array( [[0, 0, 1, 1, 0]] * 10 ), label=1, id=20, group=20, attributes={'is_crowd': True}), - ] - ), - ], categories=['a', 'b', 'c', 'd']) - - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_panoptic'), 'coco') + ]), + ], categories=['a', 'b']) - compare_datasets(self, expected_dataset, dataset, require_images=True) + formats = ['coco', 'coco_panoptic'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_panoptic')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_panoptic', + 'annotations', 'panoptic_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_panoptic', + 'annotations', 'panoptic_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_stuff(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000000001', image=np.ones((10, 5, 3)), - subset='val', attributes={'id': 1}, + DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + attributes={'id': 5}, annotations=[ Mask(np.array( - [[1, 0, 0, 1, 0]] * 5 + - [[1, 1, 1, 1, 0]] * 5 + [[0, 0, 1, 1, 0, 1, 1, 0, 0, 0]] * 5 ), label=0, - id=2, group=2, attributes={'is_crowd': False}), - ] - ), - ], categories=['TEST',]) + id=7, group=7, attributes={'is_crowd': False}), + ]), - dataset = Dataset.import_from( - osp.join(DUMMY_DATASET_DIR, 'coco_stuff'), 'coco') + DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + attributes={'id': 40}, + annotations=[ + Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=1, + id=2, group=2, attributes={'is_crowd': False}), + ]), + ], categories=['a', 'b']) - compare_datasets(self, expected_dataset, dataset) + formats = ['coco', 'coco_stuff'] + paths = [ + ('', osp.join(DUMMY_DATASET_DIR, 'coco_stuff')), + ('train', osp.join(DUMMY_DATASET_DIR, 'coco_stuff', + 'annotations', 'stuff_train.json')), + ('val', osp.join(DUMMY_DATASET_DIR, 'coco_stuff', + 'annotations', 'stuff_val.json')), + ] + for format, (subset, path) in product(formats, paths): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + with self.subTest(path=path, format=format, subset=subset): + dataset = Dataset.import_from(path, format) + compare_datasets(self, expected, dataset, require_images=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect(self): - self.assertTrue(CocoImporter.detect( - osp.join(DUMMY_DATASET_DIR, 'coco_instances'))) + dataset_dir = osp.join(DUMMY_DATASET_DIR, 'coco') + matrix = [ + # Whole dataset + (dataset_dir, CocoImporter), + + # Subformats + (dataset_dir, CocoLabelsImporter), + (dataset_dir, CocoInstancesImporter), + (dataset_dir, CocoPanopticImporter), + (dataset_dir, CocoStuffImporter), + (dataset_dir, CocoCaptionsImporter), + (dataset_dir, CocoImageInfoImporter), + (dataset_dir, CocoPersonKeypointsImporter), + + # Subsets of subformats + (osp.join(dataset_dir, 'annotations', 'labels_train.json'), + CocoLabelsImporter), + (osp.join(dataset_dir, 'annotations', 'instances_train.json'), + CocoInstancesImporter), + (osp.join(dataset_dir, 'annotations', 'panoptic_train.json'), + CocoPanopticImporter), + (osp.join(dataset_dir, 'annotations', 'stuff_train.json'), + CocoStuffImporter), + (osp.join(dataset_dir, 'annotations', 'captions_train.json'), + CocoCaptionsImporter), + (osp.join(dataset_dir, 'annotations', 'image_info_train.json'), + CocoImageInfoImporter), + (osp.join(dataset_dir, 'annotations', 'person_keypoints_train.json'), + CocoPersonKeypointsImporter), + ] + + for path, subtask in matrix: + with self.subTest(path=path, task=subtask): + self.assertTrue(subtask.detect(path)) class CocoConverterTest(TestCase): def _test_save_and_load(self, source_dataset, converter, test_dir, diff --git a/tests/test_voc_format.py b/tests/test_voc_format.py index f8b7df6719..328ed83dc6 100644 --- a/tests/test_voc_format.py +++ b/tests/test_voc_format.py @@ -18,7 +18,9 @@ VocActionConverter, VocSegmentationConverter, ) -from datumaro.plugins.voc_format.importer import VocImporter +from datumaro.plugins.voc_format.importer import (VocActionImporter, + VocClassificationImporter, VocDetectionImporter, VocImporter, + VocLayoutImporter, VocSegmentationImporter) from datumaro.components.dataset import Dataset from datumaro.util.image import Image from datumaro.util.mask_tools import load_mask @@ -79,7 +81,8 @@ def categories(self): return VOC.make_voc_categories() -DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'voc_dataset', 'voc_dataset1') +DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'voc_dataset', + 'voc_dataset1') class VocImportTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) @@ -88,7 +91,7 @@ class DstExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='2007_000001', subset='train', - image=Image(path='2007_000001.jpg', size=(10, 20)), + image=np.ones((10, 20, 3)), annotations=[ Label(self._label(l.name)) for l in VOC.VocLabel if l.value % 2 == 1 @@ -102,6 +105,12 @@ def __iter__(self): }, id=1, group=1, ), + # Only main boxes denote instances (have ids) + Mask(image=np.ones([10, 20]), + label=self._label(VOC.VocLabel(2).name), + group=1, + ), + Bbox(4, 5, 2, 2, label=self._label('person'), attributes={ 'truncated': False, @@ -114,16 +123,14 @@ def __iter__(self): }, id=2, group=2, ), - Bbox(5.5, 6, 2, 2, label=self._label( - VOC.VocBodyPart(1).name), + # Only main boxes denote instances (have ids) + Bbox(5.5, 6, 2, 2, + label=self._label(VOC.VocBodyPart(1).name), group=2 ), - Mask(image=np.ones([5, 10]), - label=self._label(VOC.VocLabel(2).name), - group=1, - ), ] ), + DatasetItem(id='2007_000002', subset='test', image=np.ones((10, 20, 3))), ]) @@ -132,9 +139,232 @@ def __iter__(self): compare_datasets(self, DstExtractor(), dataset) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_classification_dataset(self): + class DstExtractor(TestExtractorBase): + def __iter__(self): + return iter([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[ + Label(self._label(l.name)) + for l in VOC.VocLabel if l.value % 2 == 1 + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ]) + expected_dataset = DstExtractor() + + rpath = osp.join('ImageSets', 'Main', 'train.txt') + matrix = [ + ('voc_classification', '', ''), + ('voc_classification', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), + format) + + compare_datasets(self, expected, actual, require_images=True) + + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_layout_dataset(self): + expected_dataset = Dataset.from_iterable([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[ + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, + attributes={ + 'difficult': False, + 'truncated': False, + 'occluded': False, + **{ + a.name : a.value % 2 == 1 + for a in VOC.VocAction + } + } + ), + Bbox(5.5, 6.0, 2.0, 2.0, label=22, group=2), + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) + + rpath = osp.join('ImageSets', 'Layout', 'train.txt') + matrix = [ + ('voc_layout', '', ''), + ('voc_layout', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), + format) + + compare_datasets(self, expected, actual, require_images=True) + + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_detection_dataset(self): + expected_dataset = Dataset.from_iterable([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[ + Bbox(1.0, 2.0, 2.0, 2.0, label=8, id=1, group=1, + attributes={ + 'difficult': False, + 'truncated': True, + 'occluded': False, + 'pose': 'Unspecified' + } + ), + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, + attributes={ + 'difficult': False, + 'truncated': False, + 'occluded': False, + **{ + a.name : a.value % 2 == 1 + for a in VOC.VocAction + } + } + ), + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) + + rpath = osp.join('ImageSets', 'Main', 'train.txt') + matrix = [ + ('voc_detection', '', ''), + ('voc_detection', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), + format) + + compare_datasets(self, expected, actual, require_images=True) + + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_segmentation_dataset(self): + expected_dataset = Dataset.from_iterable([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[ + Mask(image=np.ones([10, 20]), label=2, group=1) + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) + + rpath = osp.join('ImageSets', 'Segmentation', 'train.txt') + matrix = [ + ('voc_segmentation', '', ''), + ('voc_segmentation', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), + format) + + compare_datasets(self, expected, actual, require_images=True) + + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_save_and_load_voc_action_dataset(self): + expected_dataset = Dataset.from_iterable([ + DatasetItem(id='2007_000001', subset='train', + image=np.ones((10, 20, 3)), + annotations=[ + Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, + attributes={ + 'difficult': False, + 'truncated': False, + 'occluded': False, + **{ + a.name : a.value % 2 == 1 + for a in VOC.VocAction + } + } + ) + ]), + + DatasetItem(id='2007_000002', subset='test', + image=np.ones((10, 20, 3))), + ], categories=VOC.make_voc_categories()) + + rpath = osp.join('ImageSets', 'Action', 'train.txt') + matrix = [ + ('voc_action', '', ''), + ('voc_action', 'train', rpath), + ('voc', 'train', rpath), + ] + for format, subset, path in matrix: + with self.subTest(format=format, subset=subset, path=path): + if subset: + expected = expected_dataset.get_subset(subset) + else: + expected = expected_dataset + + actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), + format) + + compare_datasets(self, expected, actual, require_images=True) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_voc(self): - self.assertTrue(VocImporter.detect(DUMMY_DATASET_DIR)) + matrix = [ + # Whole dataset + (DUMMY_DATASET_DIR, VocImporter), + + # Subformats + (DUMMY_DATASET_DIR, VocClassificationImporter), + (DUMMY_DATASET_DIR, VocDetectionImporter), + (DUMMY_DATASET_DIR, VocSegmentationImporter), + (DUMMY_DATASET_DIR, VocLayoutImporter), + (DUMMY_DATASET_DIR, VocActionImporter), + + # Subsets of subformats + (osp.join(DUMMY_DATASET_DIR, 'ImageSets', 'Main', 'train.txt'), + VocClassificationImporter), + (osp.join(DUMMY_DATASET_DIR, 'ImageSets', 'Main', 'train.txt'), + VocDetectionImporter), + (osp.join(DUMMY_DATASET_DIR, 'ImageSets', 'Segmentation', 'train.txt'), + VocSegmentationImporter), + (osp.join(DUMMY_DATASET_DIR, 'ImageSets', 'Layout', 'train.txt'), + VocLayoutImporter), + (osp.join(DUMMY_DATASET_DIR, 'ImageSets', 'Action', 'train.txt'), + VocActionImporter), + ] + + for path, subtask in matrix: + with self.subTest(path=path, task=subtask): + self.assertTrue(subtask.detect(path)) + class VocConverterTest(TestCase): def _test_save_and_load(self, source_dataset, converter, test_dir,