diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5b001c7b..9188c1437a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## \[Unreleased\] ### Added -- TBD +- Support for custom media types, new `PointCloud` media type, + `DatasetItem.media` and `.media_as(type)` members + () +- \[API\] A way to request dataset and extractor media type with `media_type` + () ### Changed - TBD ### Deprecated -- TBD +- `--save-images` is replaced with `--save-media` in CLI and converter API + () +- \[API\] `image`, `point_cloud` and `related_images` of `DatasetItem` are + replaced with `media` and `media_as(type)` members and c-tor parameters + () ### Removed - TBD diff --git a/datumaro/cli/__main__.py b/datumaro/cli/__main__.py index f57a8caa4b..212fff32a7 100644 --- a/datumaro/cli/__main__.py +++ b/datumaro/cli/__main__.py @@ -6,6 +6,7 @@ import logging as log import os.path as osp import sys +import warnings from ..util.telemetry_utils import ( close_telemetry_session, init_telemetry_session, @@ -39,6 +40,10 @@ def init_logger(cls, args=None): log.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=args.loglevel) + # Suppress own deprecation warnings + warnings.filterwarnings('ignore', category=DeprecationWarning, + module=r'datumaro\..*') + @staticmethod def _define_loglevel_option(parser): parser.add_argument('--loglevel', type=loglevel, default='info', diff --git a/datumaro/cli/commands/download.py b/datumaro/cli/commands/download.py index cc50c6fd04..b1c51ab38e 100644 --- a/datumaro/cli/commands/download.py +++ b/datumaro/cli/commands/download.py @@ -47,7 +47,7 @@ def build_parser(parser_ctor=argparse.ArgumentParser): |n Examples:|n - Download the MNIST dataset:|n - |s|s%(prog)s -i tfds:mnist -- --save-images|n + |s|s%(prog)s -i tfds:mnist -- --save-media|n |n - Download the VOC 2012 dataset, saving only the annotations in the COCO format into a specific directory:|n diff --git a/datumaro/cli/contexts/project/__init__.py b/datumaro/cli/contexts/project/__init__.py index c7b3f787b8..330c4f7ce0 100644 --- a/datumaro/cli/contexts/project/__init__.py +++ b/datumaro/cli/contexts/project/__init__.py @@ -371,10 +371,10 @@ def filter_command(args): # Source might be missing in the working dir, so we specify # the output directory. - # We specify save_images here as a heuristic. It can probably + # We specify save_media here as a heuristic. It can probably # be improved by checking if there are images in the dataset # directory. - dataset.save(project.source_data_dir(target), save_images=True) + dataset.save(project.source_data_dir(target), save_media=True) log.info("Finished") else: @@ -389,7 +389,7 @@ def filter_command(args): dst_dir = osp.abspath(dst_dir) dataset.filter(filter_expr, *filter_args) - dataset.save(dst_dir, save_images=True) + dataset.save(dst_dir, save_media=True) log.info("Results have been saved to '%s'" % dst_dir) @@ -557,10 +557,10 @@ def transform_command(args): # Source might be missing in the working dir, so we specify # the output directory - # We specify save_images here as a heuristic. It can probably + # We specify save_media here as a heuristic. It can probably # be improved by checking if there are images in the dataset # directory. - dataset.save(project.source_data_dir(target), save_images=True) + dataset.save(project.source_data_dir(target), save_media=True) log.info("Finished") else: @@ -575,7 +575,7 @@ def transform_command(args): dst_dir = osp.abspath(dst_dir) dataset.transform(args.transform, **extra_args) - dataset.save(dst_dir, save_images=True) + dataset.save(dst_dir, save_media=True) log.info("Results have been saved to '%s'" % dst_dir) diff --git a/datumaro/cli/contexts/project/diff.py b/datumaro/cli/contexts/project/diff.py index 7af106e7c7..f22c28cd2e 100644 --- a/datumaro/cli/contexts/project/diff.py +++ b/datumaro/cli/contexts/project/diff.py @@ -14,6 +14,8 @@ import cv2 import numpy as np +from datumaro.components.media import Image + with warnings.catch_warnings(): warnings.simplefilter("ignore") import tensorboardX as tb @@ -121,7 +123,10 @@ def save(self, a: IDataset, b: IDataset): self.update_mask_confusion(mask_diff) self.save_item_label_diff(item_a, item_b, label_diff) - self.save_item_bbox_diff(item_a, item_b, bbox_diff) + + if a.media_type() and issubclass(a.media_type(), Image) and \ + b.media_type() and issubclass(b.media_type(), Image): + self.save_item_bbox_diff(item_a, item_b, bbox_diff) if len(self.label_confusion_matrix) != 0: self.save_conf_matrix(self.label_confusion_matrix, @@ -243,11 +248,11 @@ def save_item_bbox_diff(self, item_a, item_b, diff): _, mispred, a_unmatched, b_unmatched = diff if 0 < len(a_unmatched) + len(b_unmatched) + len(mispred): - if not item_a.has_image or not item_a.image.has_data: + if not isinstance(item_a.media, Image) or not item_a.media.has_data: log.warning("Item %s: item has no image data, " "it will be skipped" % (item_a.id)) return - img_a = item_a.image.data.copy() + img_a = item_a.media.data.copy() img_b = img_a.copy() for a_bbox, b_bbox in mispred: self.draw_bbox(img_a, a_bbox, self.get_a_label(a_bbox.label), diff --git a/datumaro/components/converter.py b/datumaro/components/converter.py index bc7d30fd9c..bcd2b9fef8 100644 --- a/datumaro/components/converter.py +++ b/datumaro/components/converter.py @@ -8,16 +8,17 @@ import os import os.path as osp import shutil +import warnings from attrs import define, field import attr from datumaro.components.cli_plugin import CliPlugin from datumaro.components.errors import ( - AnnotationExportError, DatumaroError, ItemExportError, + AnnotationExportError, DatasetExportError, DatumaroError, ItemExportError, ) from datumaro.components.extractor import DatasetItem, IExtractor -from datumaro.components.media import Image +from datumaro.components.media import Image, PointCloud from datumaro.components.progress_reporting import ( NullProgressReporter, ProgressReporter, ) @@ -89,8 +90,16 @@ class Converter(CliPlugin): @classmethod def build_cmdline_parser(cls, **kwargs): parser = super().build_cmdline_parser(**kwargs) + + # Deprecated parser.add_argument('--save-images', action='store_true', - help="Save images (default: %(default)s)") + default=None, + help="(Deprecated. Use --save-media instead) " + "Save images (default: False)") + + parser.add_argument('--save-media', action='store_true', + default=None, # TODO: remove default once save-images is removed + help="Save media (default: False)") parser.add_argument('--image-ext', default=None, help="Image extension (default: keep or use format default%s)" % \ (' ' + cls.DEFAULT_IMAGE_EXT if cls.DEFAULT_IMAGE_EXT else '')) @@ -138,7 +147,8 @@ def apply(self): raise NotImplementedError("Should be implemented in a subclass") def __init__(self, extractor: IExtractor, save_dir: str, *, - save_images: bool = False, + save_images=None, # Deprecated + save_media: Optional[bool] = None, image_ext: Optional[str] = None, default_image_ext: Optional[str] = None, save_dataset_meta: bool = False, @@ -147,7 +157,20 @@ def __init__(self, extractor: IExtractor, save_dir: str, *, assert default_image_ext self._default_image_ext = default_image_ext - self._save_images = save_images + if save_images is not None and save_media is not None: + raise DatasetExportError("Can't use both 'save-media' and " + "'save-images'") + + if save_media is not None: + self._save_media = save_media + elif save_images is not None: + self._save_media = save_images + warnings.warn("'save-images' is deprecated and will be " + "removed in future. Use 'save-media' instead.", + DeprecationWarning, stacklevel=2) + else: + self._save_media = False + self._image_ext = image_ext self._extractor = extractor @@ -168,8 +191,8 @@ def __init__(self, extractor: IExtractor, save_dir: str, *, def _find_image_ext(self, item: Union[DatasetItem, Image]): src_ext = None - if isinstance(item, DatasetItem) and item.has_image: - src_ext = item.image.ext + if isinstance(item, DatasetItem) and isinstance(item.media, Image): + src_ext = item.media.ext elif isinstance(item, Image): src_ext = item.ext @@ -192,7 +215,7 @@ def _save_image(self, item, path=None, *, assert not ((subdir or name or basedir) and path), \ "Can't use both subdir or name or basedir and path arguments" - if not item.has_image or not item.image.has_data: + if not isinstance(item.media, Image) or not item.media.has_data: log.warning("Item '%s' has no image", item.id) return @@ -201,14 +224,14 @@ def _save_image(self, item, path=None, *, self._make_image_filename(item, name=name, subdir=subdir)) path = osp.abspath(path) - item.image.save(path) + item.media.save(path) def _save_point_cloud(self, item=None, path=None, *, name=None, subdir=None, basedir=None): assert not ((subdir or name or basedir) and path), \ "Can't use both subdir or name or basedir and path arguments" - if not item.point_cloud: + if not item.media or not isinstance(item.media, PointCloud): log.warning("Item '%s' has no pcd", item.id) return @@ -218,9 +241,9 @@ def _save_point_cloud(self, item=None, path=None, *, path = osp.abspath(path) os.makedirs(osp.dirname(path), exist_ok=True) - if item.point_cloud and osp.isfile(item.point_cloud): - if item.point_cloud != path: - shutil.copyfile(item.point_cloud, path) + if item.media and osp.isfile(item.media.path): + if item.media.path != path: + shutil.copyfile(item.media.path, path) def _save_meta_file(self, path): save_meta_file(path, self._extractor.categories()) diff --git a/datumaro/components/dataset.py b/datumaro/components/dataset.py index d3077514b0..203d6b320a 100644 --- a/datumaro/components/dataset.py +++ b/datumaro/components/dataset.py @@ -27,7 +27,7 @@ ) from datumaro.components.environment import Environment from datumaro.components.errors import ( - CategoriesRedefinedError, ConflictingCategoriesError, + CategoriesRedefinedError, ConflictingCategoriesError, MediaTypeError, MultipleFormatsMatchError, NoMatchingFormatsError, RepeatedItemError, UnknownFormatError, ) @@ -36,6 +36,7 @@ ImportContext, ImportErrorPolicy, ItemTransform, Transform, _ImportFail, ) from datumaro.components.launcher import Launcher, ModelTransform +from datumaro.components.media import Image, MediaElement from datumaro.components.progress_reporting import ( NullProgressReporter, ProgressReporter, ) @@ -158,10 +159,14 @@ def subsets(self): def categories(self): return self.parent.categories() + def media_type(self): + return self.parent.media_type() - def __init__(self, parent: DatasetItemStorage, categories: CategoriesInfo): + def __init__(self, parent: DatasetItemStorage, categories: CategoriesInfo, + media_type: Optional[Type[MediaElement]]): self._parent = parent self._categories = categories + self._media_type = media_type def __iter__(self): yield from self._parent @@ -184,6 +189,8 @@ def subsets(self): def get(self, id, subset=None): return self._parent.get(id, subset=subset) + def media_type(self): + return self._media_type class ItemStatus(Enum): added = auto() @@ -195,7 +202,7 @@ class DatasetPatchWrapper(DatasetItemStorageDatasetView): # The purpose of this class is to indicate that the input dataset is # a patch and autofill patch info in Converter def __init__(self, patch: DatasetPatch, parent: IDataset): - super().__init__(patch.data, parent.categories()) + super().__init__(patch.data, parent.categories(), parent.media_type()) self.patch = patch def subsets(self): @@ -261,19 +268,32 @@ def subsets(self): def categories(self): return self.parent.categories() + def media_type(self): + return self.parent.media_type() + def as_dataset(self) -> Dataset: return Dataset.from_extractors(self, env=self.parent.env) class DatasetStorage(IDataset): def __init__(self, source: Union[IDataset, DatasetItemStorage] = None, - categories: CategoriesInfo = None): + categories: Optional[CategoriesInfo] = None, + media_type: Optional[Type[MediaElement]] = None): if source is None and categories is None: categories = {} elif isinstance(source, IDataset) and categories is not None: raise ValueError("Can't use both source and categories") self._categories = categories + if media_type: + pass + elif isinstance(source, IDataset) and source.media_type(): + media_type = source.media_type() + else: + raise ValueError("Media type must be provided for a dataset") + assert issubclass(media_type, MediaElement) + self._media_type = media_type + # Possible combinations: # 1. source + storage # - Storage contains a patch to the Source data. @@ -330,7 +350,7 @@ def __init__(self, source, transforms): super().__init__(source) self.is_local = True - self.transforms = [] + self.transforms: List[Transform] = [] for transform in transforms: source = transform[0](source, *transform[1], **transform[2]) self.transforms.append(source) @@ -351,6 +371,9 @@ def __iter__(self): def categories(self): return self.transforms[-1].categories() + def media_type(self): + return self.transforms[-1].media_type() + def _update_status(item_id, new_status: ItemStatus): current_status = self._updated_items.get(item_id) @@ -370,9 +393,12 @@ def _update_status(item_id, new_status: ItemStatus): else: assert False, "Unknown status %s" % new_status + media_type = self._media_type patch = self._storage # must be empty after transforming cache = DatasetItemStorage() - source = self._source + source = self._source or \ + DatasetItemStorageDatasetView(self._storage, + categories=self._categories, media_type=media_type) transform = None if self._transforms: @@ -390,8 +416,20 @@ def _update_status(item_id, new_status: ItemStatus): old_ids = set((item.id, item.subset) for item in source) source = transform + if not issubclass(transform.media_type(), media_type): + # TODO: make it statically available + raise MediaTypeError( + "Transforms are not allowed to change media " + "type of dataset items") + i = -1 for i, item in enumerate(source): + if item.media and not isinstance(item.media, media_type): + raise MediaTypeError( + "Unexpected media type of a dataset item '%s'. " \ + "Expected '%s', actual '%s' " % + (item.id, media_type, type(item.media))) + if transform and transform.is_local: old_id = (item.id, item.subset) item = transform.transform_item(item) @@ -458,6 +496,7 @@ def _update_status(item_id, new_status: ItemStatus): else: source_cat = source.categories() if source_cat is not None: + # Don't need to override categories if already defined self._categories = source_cat self._source = None @@ -478,7 +517,8 @@ def _merged(self) -> IDataset: return self._source elif self._source is not None: self.init_cache() - return DatasetItemStorageDatasetView(self._storage, self._categories) + return DatasetItemStorageDatasetView(self._storage, + self._categories, self._media_type) def __len__(self) -> int: if self._length is None: @@ -502,7 +542,15 @@ def define_categories(self, categories: CategoriesInfo): raise CategoriesRedefinedError() self._categories = categories - def put(self, item): + def media_type(self) -> Type[MediaElement]: + return self._media_type + + def put(self, item: DatasetItem): + if item.media and not isinstance(item.media, self._media_type): + raise MediaTypeError("Mismatching item media type '%s', " + "the dataset contains '%s' items." % \ + (type(item.media), self._media_type)) + is_new = self._storage.put(item) if not self.is_cache_initialized() or is_new: @@ -619,12 +667,50 @@ def update(self, self.put(item) class Dataset(IDataset): + """ + Represents a dataset, contains metainfo about labels and dataset items. + Provides iteration and access options to dataset elements. + + By default, all operations are done lazily, it can be changed by + modifying the `eager` property and by using the `eager_mode` + context manager. + + Dataset is supposed to have a single media type for its items. If the + dataset is filled manually or from extractors, and media type does not + match, an error is raised. + """ + _global_eager: bool = False @classmethod def from_iterable(cls, iterable: Iterable[DatasetItem], categories: Union[CategoriesInfo, List[str], None] = None, - env: Optional[Environment] = None) -> Dataset: + *, + env: Optional[Environment] = None, + media_type: Type[MediaElement] = Image) -> Dataset: + """ + Creates a new dataset from an iterable object producing dataset items - + a generator, a list etc. It is a convenient way to create and fill + a custom dataset. + + Parameters: + iterable: An iterable which returns dataset items + categories: A simple list of labels or complete information + about labels. If not specified, an empty list of labels + is assumed. + media_type: Media type for the dataset items. If the sequence + contains items with mismatching media type, an error is + raised during caching + env: A context for plugins, which will be used for this dataset. + If not specified, the builtin plugins will be used. + + Returns: + dataset: A new dataset with specified contents + """ + + # TODO: remove the default value for media_type + # https://github.com/openvinotoolkit/datumaro/issues/675 + if isinstance(categories, list): categories = { AnnotationType.label: LabelCategories.from_iterable(categories) @@ -636,7 +722,8 @@ def from_iterable(cls, iterable: Iterable[DatasetItem], class _extractor(Extractor): def __init__(self): super().__init__(length=len(iterable) \ - if hasattr(iterable, '__len__') else None) + if hasattr(iterable, '__len__') else None, + media_type=media_type) def __iter__(self): return iter(iterable) @@ -649,19 +736,38 @@ def categories(self): @staticmethod def from_extractors(*sources: IDataset, env: Optional[Environment] = None) -> Dataset: + """ + Creates a new dataset from one or several `Extractor`s. + + In case of a single input, creates a lazy wrapper around the input. + In case of several inputs, merges them and caches the resulting + dataset. + + Parameters: + sources: one or many input extractors + env: A context for plugins, which will be used for this dataset. + If not specified, the builtin plugins will be used. + + Returns: + dataset: A new dataset with contents produced by input extractors + """ + if len(sources) == 1: source = sources[0] dataset = Dataset(source=source, env=env) else: from datumaro.components.operations import ExactMerge + media_type = ExactMerge.merge_media_types(sources) source = ExactMerge.merge(*sources) categories = ExactMerge.merge_categories( s.categories() for s in sources) - dataset = Dataset(source=source, categories=categories, env=env) + dataset = Dataset(source=source, categories=categories, + media_type=media_type, env=env) return dataset def __init__(self, source: Optional[IDataset] = None, *, categories: Optional[CategoriesInfo] = None, + media_type: Optional[Type[MediaElement]] = None, env: Optional[Environment] = None) -> None: super().__init__() @@ -669,7 +775,8 @@ def __init__(self, source: Optional[IDataset] = None, *, self._env = env self.eager = None - self._data = DatasetStorage(source, categories=categories) + self._data = DatasetStorage(source, categories=categories, + media_type=media_type) if self.is_eager: self.init_cache() @@ -698,6 +805,9 @@ def subsets(self) -> Dict[str, DatasetSubset]: def categories(self) -> CategoriesInfo: return self._data.categories() + def media_type(self) -> Type[MediaElement]: + return self._data.media_type() + def get(self, id: str, subset: Optional[str] = None) \ -> Optional[DatasetItem]: return self._data.get(id, subset) @@ -777,6 +887,7 @@ def transform(self, method: Union[str, Type[Transform]], Applies some function to dataset items. Results are stored in-place. Modifications are applied lazily. + Transforms are not allowed to change media type of dataset items. Args: method - The transformation to be applied to the dataset. @@ -1125,7 +1236,6 @@ def detect(path: str, *, if 1 < len(matches): raise MultipleFormatsMatchError(matches) - @contextmanager def eager_mode(new_mode: bool = True, dataset: Optional[Dataset] = None) -> None: if dataset is not None: diff --git a/datumaro/components/dataset_filter.py b/datumaro/components/dataset_filter.py index d2d8f43edd..23fad7d999 100644 --- a/datumaro/components/dataset_filter.py +++ b/datumaro/components/dataset_filter.py @@ -12,6 +12,7 @@ PolyLine, ) from datumaro.components.extractor import ItemTransform +from datumaro.components.media import Image class DatasetItemEncoder: @@ -21,8 +22,8 @@ def encode(cls, item, categories=None): ET.SubElement(item_elem, 'id').text = str(item.id) ET.SubElement(item_elem, 'subset').text = str(item.subset) - image = item.image - if image is not None: + image = item.media + if isinstance(image, Image): item_elem.append(cls.encode_image(image)) for ann in item.annotations: diff --git a/datumaro/components/errors.py b/datumaro/components/errors.py index 9b9d4acaf0..8d1057464b 100644 --- a/datumaro/components/errors.py +++ b/datumaro/components/errors.py @@ -206,6 +206,9 @@ def __str__(self): class DatasetError(DatumaroError): pass +class MediaTypeError(DatumaroError): + pass + class CategoriesRedefinedError(DatasetError): def __str__(self): return "Categories can only be set once for a dataset" @@ -268,13 +271,23 @@ def __str__(self): (self.item_id, self.a, self.b) @define(auto_exc=False) -class MismatchingImagePathError(DatasetMergeError): +class MismatchingMediaPathError(DatasetMergeError): item_id: Tuple[str, str] a: str b: str def __str__(self): - return "Item %s: mismatching image path info: %s vs %s" % \ + return "Item %s: mismatching media path info: %s vs %s" % \ + (self.item_id, self.a, self.b) + +@define(auto_exc=False) +class MismatchingMediaError(DatasetMergeError): + item_id: Tuple[str, str] + a: Any + b: Any + + def __str__(self): + return "Item %s: mismatching media info: %s vs %s" % \ (self.item_id, self.a, self.b) @define(auto_exc=False) @@ -332,6 +345,14 @@ def __str__(self): "for ann %s, votes %s, sources %s" % \ (self.item_id, self.ann, self.votes, self.sources) +@define(auto_exc=False) +class VideoMergeError(DatasetMergeError): + item_id = field() + + def __str__(self): + return "Item %s: video merging is not possible" % \ + (self.item_id, ) + @define(auto_exc=False) class DatasetValidationError(DatumaroError): severity = field() diff --git a/datumaro/components/extractor.py b/datumaro/components/extractor.py index 4062bb2ed1..53801e48f5 100644 --- a/datumaro/components/extractor.py +++ b/datumaro/components/extractor.py @@ -7,10 +7,11 @@ from glob import iglob from typing import ( Any, Callable, Dict, Iterator, List, NoReturn, Optional, Sequence, Tuple, - TypeVar, + Type, TypeVar, Union, cast, ) import os import os.path as osp +import warnings from attr import attrs, define, field import attr @@ -26,7 +27,7 @@ from datumaro.components.format_detection import ( FormatDetectionConfidence, FormatDetectionContext, ) -from datumaro.components.media import Image +from datumaro.components.media import Image, MediaElement, PointCloud from datumaro.components.progress_reporting import ( NullProgressReporter, ProgressReporter, ) @@ -35,65 +36,120 @@ DEFAULT_SUBSET_NAME = 'default' -@attrs(slots=True, order=False) +T = TypeVar('T', bound=MediaElement) + +@attrs(order=False, init=False, slots=True) class DatasetItem: id: str = field(converter=lambda x: str(x).replace('\\', '/'), validator=not_empty) - annotations: List[Annotation] = field( - factory=list, validator=default_if_none(list)) + subset: str = field(converter=lambda v: v or DEFAULT_SUBSET_NAME, default=None) - # TODO: introduce "media" field with type info. Replace image and pcd. - image: Optional[Image] = field(default=None) - # TODO: introduce pcd type like Image - point_cloud: Optional[str] = field( - converter=lambda x: str(x).replace('\\', '/') if x else None, - default=None) - related_images: List[Image] = field(default=None) - - def __attrs_post_init__(self): - if (self.has_image and self.has_point_cloud): - raise ValueError("Can't set both image and point cloud info") - if self.related_images and not self.has_point_cloud: - raise ValueError("Related images require point cloud") - - def _image_converter(image): - if callable(image) or isinstance(image, np.ndarray): - image = Image(data=image) - elif isinstance(image, str): - image = Image(path=image) - assert image is None or isinstance(image, Image), type(image) - return image - image.converter = _image_converter - - def _related_image_converter(images): - return list(map(__class__._image_converter, images or [])) - related_images.converter = _related_image_converter - - @point_cloud.validator - def _point_cloud_validator(self, attribute, pcd): - assert pcd is None or isinstance(pcd, str), type(pcd) + media: Optional[MediaElement] = field(default=None, + validator=attr.validators.optional( + attr.validators.instance_of(MediaElement))) + + annotations: List[Annotation] = field( + factory=list, validator=default_if_none(list)) attributes: Dict[str, Any] = field( factory=dict, validator=default_if_none(dict)) + def wrap(item, **kwargs): + return attr.evolve(item, **kwargs) + + def media_as(self, t: Type[T]) -> T: + assert issubclass(t, MediaElement) + return cast(t, self.media) + + def __init__(self, id: str, *, + subset: Optional[str] = None, + media: Union[str, MediaElement, None] = None, + annotations: Optional[List[Annotation]] = None, + attributes: Dict[str, Any] = None, + image=None, point_cloud=None, related_images=None): + if image is not None: + warnings.warn("'image' is deprecated and will be " + "removed in future. Use 'media' instead.", + DeprecationWarning, stacklevel=2) + if isinstance(image, str): + image = Image(path=image) + elif isinstance(image, np.ndarray) or callable(image): + image = Image(data=image) + assert isinstance(image, Image) + media = image + elif point_cloud is not None: + warnings.warn("'point_cloud' is deprecated and will be " + "removed in future. Use 'media' instead.", + DeprecationWarning, stacklevel=2) + if related_images is not None: + warnings.warn("'related_images' is deprecated and will be " + "removed in future. Use 'media' instead.", + DeprecationWarning, stacklevel=2) + if isinstance(point_cloud, str): + point_cloud = PointCloud(path=point_cloud, + extra_images=related_images) + assert isinstance(point_cloud, PointCloud) + media = point_cloud + + self.__attrs_init__(id=id, subset=subset, media=media, + annotations=annotations, attributes=attributes) + + # Deprecated. Provided for backward compatibility. + @property + def image(self) -> Optional[Image]: + warnings.warn("'DatasetItem.image' is deprecated and will be " + "removed in future. Use '.media' and '.media_as()' instead.", + DeprecationWarning, stacklevel=2) + if not isinstance(self.media, Image): + return None + return self.media_as(Image) + + # Deprecated. Provided for backward compatibility. + @property + def point_cloud(self) -> Optional[str]: + warnings.warn("'DatasetItem.point_cloud' is deprecated and will be " + "removed in future. Use '.media' and '.media_as()' instead.", + DeprecationWarning, stacklevel=2) + if not isinstance(self.media, PointCloud): + return None + return self.media_as(PointCloud).path + + # Deprecated. Provided for backward compatibility. + @property + def related_images(self) -> List[Image]: + warnings.warn("'DatasetItem.related_images' is deprecated and will be " + "removed in future. Use '.media' and '.media_as()' instead.", + DeprecationWarning, stacklevel=2) + if not isinstance(self.media, PointCloud): + return [] + return self.media_as(PointCloud).extra_images + + # Deprecated. Provided for backward compatibility. @property def has_image(self): - return self.image is not None + warnings.warn("'DatasetItem.has_image' is deprecated and will be " + "removed in future. Use '.media' and '.media_as()' instead.", + DeprecationWarning, stacklevel=2) + return isinstance(self.media, Image) + # Deprecated. Provided for backward compatibility. @property def has_point_cloud(self): - return self.point_cloud is not None - - def wrap(item, **kwargs): - return attr.evolve(item, **kwargs) + warnings.warn("'DatasetItem.has_point_cloud' is deprecated and will be " + "removed in future. Use '.media' and '.media_as()' instead.", + DeprecationWarning, stacklevel=2) + return isinstance(self.media, PointCloud) CategoriesInfo = Dict[AnnotationType, Categories] class IExtractor: def __iter__(self) -> Iterator[DatasetItem]: + """ + Provides sequential access to dataset items. + """ raise NotImplementedError() def __len__(self) -> int: @@ -103,19 +159,41 @@ def __bool__(self): # avoid __len__ use for truth checking return True def subsets(self) -> Dict[str, IExtractor]: + """ + Enumerates subsets in the dataset. Each subset can be a dataset itself. + """ raise NotImplementedError() def get_subset(self, name) -> IExtractor: raise NotImplementedError() def categories(self) -> CategoriesInfo: + """ + Returns metainfo about dataset labels. + """ + raise NotImplementedError() + + def get(self, id: str, subset: Optional[str] = None) \ + -> Optional[DatasetItem]: + """ + Provides random access to dataset items. + """ raise NotImplementedError() - def get(self, id, subset=None) -> Optional[DatasetItem]: + def media_type(self) -> Type[MediaElement]: + """ + Returns media type of the dataset items. + + All the items are supposed to have the same media type. + Supposed to be constant and known immediately after the + object construction (i.e. doesn't require dataset iteration). + """ raise NotImplementedError() class _ExtractorBase(IExtractor): - def __init__(self, *, length=None, subsets=None): + def __init__(self, *, + length: Optional[int] = None, + subsets: Optional[Sequence[str]] = None): self._length = length self._subsets = subsets @@ -165,6 +243,8 @@ def __iter__(_): return filter(pred, iter(self)) def categories(_): return self.categories() + def media_type(_): + return self.media_type() return _DatasetFilter() @@ -246,10 +326,15 @@ class Extractor(_ExtractorBase, CliPlugin): def __init__(self, *, length: Optional[int] = None, subsets: Optional[Sequence[str]] = None, + media_type: Type[MediaElement] = Image, ctx: Optional[ImportContext] = None): super().__init__(length=length, subsets=subsets) self._ctx: ImportContext = ctx or NullImportContext() + self._media_type = media_type + + def media_type(self): + return self._media_type class SourceExtractor(Extractor): """ @@ -260,9 +345,11 @@ class SourceExtractor(Extractor): def __init__(self, *, length: Optional[int] = None, subset: Optional[str] = None, + media_type: Type[MediaElement] = Image, ctx: Optional[ImportContext] = None): self._subset = subset or DEFAULT_SUBSET_NAME - super().__init__(length=length, subsets=[self._subset], ctx=ctx) + super().__init__(length=length, subsets=[self._subset], + media_type=media_type, ctx=ctx) self._categories = {} self._items = [] @@ -393,6 +480,9 @@ def __len__(self): self._length = len(self._extractor) return super().__len__() + def media_type(self): + return self._extractor.media_type() + class ItemTransform(Transform): def transform_item(self, item: DatasetItem) -> Optional[DatasetItem]: """ diff --git a/datumaro/components/extractor_tfds.py b/datumaro/components/extractor_tfds.py index 6899744f77..43fb03c049 100644 --- a/datumaro/components/extractor_tfds.py +++ b/datumaro/components/extractor_tfds.py @@ -6,7 +6,8 @@ from types import SimpleNamespace as namespace from typing import ( - Any, Callable, Dict, Iterator, Mapping, Optional, Sequence, Tuple, Union, + Any, Callable, Dict, Iterator, Mapping, Optional, Sequence, Tuple, Type, + Union, ) import itertools import logging as log @@ -20,7 +21,7 @@ from datumaro.components.extractor import ( CategoriesInfo, DatasetItem, IExtractor, ) -from datumaro.components.media import ByteImage +from datumaro.components.media import ByteImage, Image, MediaElement from datumaro.util.tf_util import import_tf try: @@ -36,6 +37,7 @@ @frozen class TfdsDatasetMetadata: default_converter_name: str + media_type: Type[MediaElement] @frozen class _TfdsAdapter: @@ -113,7 +115,7 @@ def __call__( else: filename = None - item.image = ByteImage(data=tfds_example[self.feature_name].numpy(), + item.media = ByteImage(data=tfds_example[self.feature_name].numpy(), path=filename) @frozen @@ -168,10 +170,10 @@ def __call__( norm_ymin, norm_xmin, norm_ymax, norm_xmax = tfds_bboxes[i].numpy() new_bbox = Bbox( - x=norm_xmin * item.image.size[1], - y=norm_ymin * item.image.size[0], - w=(norm_xmax - norm_xmin) * item.image.size[1], - h=(norm_ymax - norm_ymin) * item.image.size[0], + x=norm_xmin * item.media.size[1], + y=norm_ymin * item.media.size[0], + w=(norm_xmax - norm_xmin) * item.media.size[1], + h=(norm_ymax - norm_ymin) * item.media.size[0], ) if tfds_labels is not None: @@ -220,7 +222,8 @@ def __call__(self, tfds_example: Any) -> str: _SetImageFromImageFeature('image'), _AddLabelFromClassLabelFeature('label'), ], - metadata=TfdsDatasetMetadata(default_converter_name='mnist'), + metadata=TfdsDatasetMetadata(default_converter_name='mnist', + media_type=Image), ) _CIFAR_ADAPTER = _TfdsAdapter( @@ -230,7 +233,8 @@ def __call__(self, tfds_example: Any) -> str: _AddLabelFromClassLabelFeature('label'), ], id_generator=_GenerateIdFromTextFeature('id'), - metadata=TfdsDatasetMetadata(default_converter_name='cifar'), + metadata=TfdsDatasetMetadata(default_converter_name='cifar', + media_type=Image), ) _COCO_ADAPTER = _TfdsAdapter( @@ -245,7 +249,8 @@ def __call__(self, tfds_example: Any) -> str: _SetAttributeFromFeature('image/id', 'id'), ], id_generator=_GenerateIdFromFilenameFeature('image/filename'), - metadata=TfdsDatasetMetadata(default_converter_name='coco_instances'), + metadata=TfdsDatasetMetadata(default_converter_name='coco_instances', + media_type=Image), ) _IMAGENET_ADAPTER = _TfdsAdapter( @@ -255,7 +260,8 @@ def __call__(self, tfds_example: Any) -> str: _AddLabelFromClassLabelFeature('label'), ], id_generator=_GenerateIdFromFilenameFeature('file_name'), - metadata=TfdsDatasetMetadata(default_converter_name='imagenet_txt'), + metadata=TfdsDatasetMetadata(default_converter_name='imagenet_txt', + media_type=Image), ) def _voc_save_pose_names( @@ -291,7 +297,8 @@ def _voc_save_pose_names( ), ], id_generator=_GenerateIdFromFilenameFeature('image/filename'), - metadata=TfdsDatasetMetadata(default_converter_name='voc'), + metadata=TfdsDatasetMetadata(default_converter_name='voc', + media_type=Image), ) _TFDS_ADAPTERS = { @@ -348,6 +355,9 @@ def get(self, id, subset=None) -> Optional[DatasetItem]: return None + def media_type(self) -> Type[MediaElement]: + return self._parent._media_type + class _TfdsExtractor(IExtractor): _categories: CategoriesInfo @@ -360,6 +370,7 @@ def __init__(self, tfds_ds_name: str) -> None: self._state = namespace() self._adapter.transform_categories( tfds_builder, self._categories, self._state) + self._media_type = self._adapter.metadata.media_type tfds_decoders = {} for tfds_feature_name, tfds_fc in tfds_ds_info.features.items(): @@ -404,6 +415,9 @@ def get(self, id, subset=None) -> Optional[DatasetItem]: return None return self._split_extractors[subset].get(id) + def media_type(self) -> Type[MediaElement]: + return self._media_type + AVAILABLE_TFDS_DATASETS: Mapping[str, TfdsDatasetMetadata] = { name: adapter.metadata for name, adapter in _TFDS_ADAPTERS.items() } diff --git a/datumaro/components/hl_ops.py b/datumaro/components/hl_ops.py index 9f77c09a59..8dbd6563e9 100644 --- a/datumaro/components/hl_ops.py +++ b/datumaro/components/hl_ops.py @@ -99,8 +99,9 @@ def merge(*datasets: IDataset) -> IDataset: """ categories = ExactMerge.merge_categories(d.categories() for d in datasets) + media_type = ExactMerge.merge_media_types(datasets) return DatasetItemStorageDatasetView(ExactMerge.merge(*datasets), - categories=categories) + categories=categories, media_type=media_type) def run_model(dataset: IDataset, model: Union[Launcher, Type[ModelTransform]], *, diff --git a/datumaro/components/launcher.py b/datumaro/components/launcher.py index 2c88230cbb..755fa01b7e 100644 --- a/datumaro/components/launcher.py +++ b/datumaro/components/launcher.py @@ -30,7 +30,7 @@ def __init__(self, extractor, launcher, batch_size=1): def __iter__(self): for batch in take_by(self._extractor, self._batch_size): - inputs = np.array([np.atleast_3d(item.image.data) + inputs = np.array([np.atleast_3d(item.media.data) for item in batch]) inference = self._launcher.launch(inputs) @@ -49,7 +49,7 @@ def categories(self): return self._extractor.categories() def transform_item(self, item): - inputs = np.expand_dims(item.image, axis=0) + inputs = np.expand_dims(item.media, axis=0) annotations = self._launcher.launch(inputs)[0] return self.wrap_item(item, annotations=annotations) diff --git a/datumaro/components/media.py b/datumaro/components/media.py index 5221113e09..b61df81bb2 100644 --- a/datumaro/components/media.py +++ b/datumaro/components/media.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Callable, Iterable, Iterator, Optional, Tuple, Union +from typing import Callable, Iterable, Iterator, List, Optional, Tuple, Union import os import os.path as osp import shutil @@ -20,6 +20,7 @@ class MediaElement: def __init__(self, path: str) -> None: + assert path, "Path can't be empty" self._path = path @property @@ -482,3 +483,9 @@ def __eq__(self, other: object) -> bool: def __hash__(self): # Required for caching return hash((self._path, self._step, self._start_frame, self._end_frame)) + +class PointCloud(MediaElement): + def __init__(self, path: str, extra_images: Optional[List[Image]] = None): + self._path = path + + self.extra_images: List[Image] = extra_images or [] diff --git a/datumaro/components/operations.py b/datumaro/components/operations.py index 2a263cdc28..570dfb55e5 100644 --- a/datumaro/components/operations.py +++ b/datumaro/components/operations.py @@ -4,7 +4,9 @@ from collections import OrderedDict from copy import deepcopy -from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple +from typing import ( + Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Type, Union, +) from unittest import TestCase import hashlib import logging as log @@ -22,12 +24,13 @@ from datumaro.components.dataset import Dataset, DatasetItemStorage, IDataset from datumaro.components.errors import ( AnnotationsTooCloseError, ConflictingCategoriesError, DatasetMergeError, - FailedAttrVotingError, FailedLabelVotingError, MismatchingAttributesError, - MismatchingImageInfoError, MismatchingImagePathError, NoMatchingAnnError, - NoMatchingItemError, WrongGroupError, + FailedAttrVotingError, FailedLabelVotingError, MediaTypeError, + MismatchingAttributesError, MismatchingImageInfoError, + MismatchingMediaError, MismatchingMediaPathError, NoMatchingAnnError, + NoMatchingItemError, VideoMergeError, WrongGroupError, ) from datumaro.components.extractor import CategoriesInfo, DatasetItem -from datumaro.components.media import Image +from datumaro.components.media import Image, MediaElement, PointCloud, Video from datumaro.util import filter_dict, find from datumaro.util.annotation_util import ( OKS, approximate_line, bbox_iou, find_instances, max_bbox, mean_bbox, @@ -116,7 +119,7 @@ def merge(cls, *sources: IDataset) -> DatasetItemStorage: def _merge_items(cls, existing_item: DatasetItem, current_item: DatasetItem) -> DatasetItem: return existing_item.wrap( - image=cls._merge_images(existing_item, current_item), + media=cls._merge_media(existing_item, current_item), attributes=cls._merge_attrs( existing_item.attributes, current_item.attributes, item_id=(existing_item.id, existing_item.subset)), @@ -145,14 +148,50 @@ def _merge_attrs(a: Dict[str, Any], b: Dict[str, Any], return merged + @classmethod + def _merge_media(cls, item_a: DatasetItem, item_b: DatasetItem) \ + -> Union[Image, PointCloud, Video]: + if (not item_a.media or isinstance(item_a.media, Image)) and \ + (not item_b.media or isinstance(item_b.media, Image)): + media = cls._merge_images(item_a, item_b) + elif (not item_a.media or isinstance(item_a.media, PointCloud)) and \ + (not item_b.media or isinstance(item_b.media, PointCloud)): + media = cls._merge_point_clouds(item_a, item_b) + elif (not item_a.media or isinstance(item_a.media, Video)) and \ + (not item_b.media or isinstance(item_b.media, Video)): + media = cls._merge_videos(item_a, item_b) + elif (not item_a.media or isinstance(item_a.media, MediaElement)) and \ + (not item_b.media or isinstance(item_b.media, MediaElement)): + if isinstance(item_a.media, MediaElement) and isinstance(item_b.media, MediaElement): + if item_a.media.path and item_b.media.path and \ + item_a.media.path != item_b.media.path: + raise MismatchingMediaPathError( + (item_a.id, item_a.subset), + item_a.media.path, item_b.media.path) + + if item_a.media.path: + media = item_a.media + else: + media = item_b.media + + elif isinstance(item_a.media, MediaElement): + media = item_a.media + else: + media = item_b.media + else: + raise MismatchingMediaError( + (item_a.id, item_a.subset), + item_a.media, item_b.media) + return media + @staticmethod def _merge_images(item_a: DatasetItem, item_b: DatasetItem) -> Image: - image = None + media = None - if item_a.has_image and item_b.has_image: - if item_a.image.path and item_b.image.path and \ - item_a.image.path != item_b.image.path and \ - item_a.image.has_data is item_b.image.has_data: + if isinstance(item_a.media, Image) and isinstance(item_b.media, Image): + if item_a.media.path and item_b.media.path and \ + item_a.media.path != item_b.media.path and \ + item_a.media.has_data is item_b.media.has_data: # We use has_data as a replacement for path existence check # - If only one image has data, we'll use it. The other # one is just a path metainfo, which is not significant @@ -163,45 +202,97 @@ def _merge_images(item_a: DatasetItem, item_b: DatasetItem) -> Image: # Different paths can aclually point to the same file, # but it's not the case we'd like to allow here to be # a "simple" merging strategy used for extractor joining - raise MismatchingImagePathError( + raise MismatchingMediaPathError( (item_a.id, item_a.subset), - item_a.image.path, item_b.image.path) + item_a.media.path, item_b.media.path) - if item_a.image.has_size and item_b.image.has_size and \ - item_a.image.size != item_b.image.size: + if item_a.media.has_size and item_b.media.has_size and \ + item_a.media.size != item_b.media.size: raise MismatchingImageInfoError( (item_a.id, item_a.subset), - item_a.image.size, item_b.image.size) + item_a.media.size, item_b.media.size) # Avoid direct comparison here for better performance # If there are 2 "data-only" images, they won't be compared and # we just use the first one - if item_a.image.has_data: - image = item_a.image - elif item_b.image.has_data: - image = item_b.image - elif item_a.image.path: - image = item_a.image - elif item_b.image.path: - image = item_b.image - elif item_a.image.has_size: - image = item_a.image - elif item_b.image.has_size: - image = item_b.image + if item_a.media.has_data: + media = item_a.media + elif item_b.media.has_data: + media = item_b.media + elif item_a.media.path: + media = item_a.media + elif item_b.media.path: + media = item_b.media + elif item_a.media.has_size: + media = item_a.media + elif item_b.media.has_size: + media = item_b.media else: assert False, "Unknown image field combination" - if not image.has_data or not image.has_size: - if item_a.image._size: - image._size = item_a.image._size - elif item_b.image._size: - image._size = item_b.image._size - elif item_a.has_image: - image = item_a.image + if not media.has_data or not media.has_size: + if item_a.media._size: + media._size = item_a.media._size + elif item_b.media._size: + media._size = item_b.media._size + elif isinstance(item_a.media, Image): + media = item_a.media + else: + media = item_b.media + + return media + + @staticmethod + def _merge_point_clouds(item_a: DatasetItem, item_b: DatasetItem) -> PointCloud: + media = None + + if isinstance(item_a.media, PointCloud) and isinstance(item_b.media, PointCloud): + if item_a.media.path and item_b.media.path and \ + item_a.media.path != item_b.media.path: + raise MismatchingMediaPathError( + (item_a.id, item_a.subset), + item_a.media.path, item_b.media.path) + + if item_a.media.path or item_a.media.extra_images: + media = item_a.media + + if item_b.media.extra_images: + for image in item_b.media.extra_images: + if image not in media.extra_images: + media.extra_images.append(image) + else: + media = item_b.media + + if item_a.media.extra_images: + for image in item_a.media.extra_images: + if image not in media.extra_images: + media.extra_images.append(image) + + elif isinstance(item_a.media, PointCloud): + media = item_a.media else: - image = item_b.image + media = item_b.media - return image + return media + + @staticmethod + def _merge_videos(item_a: DatasetItem, item_b: DatasetItem) -> Video: + media = None + + if isinstance(item_a.media, Video) and isinstance(item_b.media, Video): + if item_a.media.path is not item_b.media.path or \ + item_a.media._start_frame is not item_b.media._start_frame or \ + item_a.media._end_frame is not item_b.media._end_frame or \ + item_a.media._step is not item_b.media._step: + raise VideoMergeError(item_a.id) + + media = item_a.media + elif isinstance(item_a.media, Video): + media = item_a.media + else: + media = item_b.media + + return media @staticmethod def _merge_anno(a: Iterable[Annotation], b: Iterable[Annotation]) \ @@ -212,6 +303,20 @@ def _merge_anno(a: Iterable[Annotation], b: Iterable[Annotation]) \ def merge_categories(sources: Iterable[IDataset]) -> CategoriesInfo: return merge_categories(sources) + @staticmethod + def merge_media_types(sources: Iterable[IDataset]) -> Type[MediaElement]: + if sources: + media_type = sources[0].media_type() + for s in sources: + if not issubclass(s.media_type(), media_type) or \ + not issubclass(media_type, s.media_type()): + # Symmetric comparision is needed in the case of subclasses: + # eg. Image and ByteImage + raise MediaTypeError("Datasets have different media types") + return media_type + + return None + @attrs class IntersectMerge(MergingStrategy): @attrs(repr_ns='IntersectMerge', kw_only=True) @@ -255,7 +360,8 @@ def add_item_error(self, error, *args, **kwargs): def __call__(self, datasets): self._categories = self._merge_categories( [d.categories() for d in datasets]) - merged = Dataset(categories=self._categories) + merged = Dataset(categories=self._categories, + media_type=ExactMerge.merge_media_types(datasets)) self._check_groups_definition() @@ -1084,14 +1190,14 @@ def __init__(self): self._stats = {} # (id, subset) -> (pixel count, mean vec, std vec) def accumulate(self, item: DatasetItem): - size = item.image.size + size = item.media.size if size is None: log.warning("Item %s: can't detect image size, " "the image will be skipped from pixel statistics", item.id) return - count = np.prod(item.image.size) + count = np.prod(item.media.size) - image = item.image.data + image = item.media.data if len(image.shape) == 2: image = image[:, :, np.newaxis] else: @@ -1468,16 +1574,16 @@ def match_items_by_image_hash(a: IDataset, b: IDataset): class _ItemMatcher: @staticmethod def _default_item_hash(item: DatasetItem): - if not item.image or not item.image.has_data: - if item.image and item.image.path: - return hash(item.image.path) + if not item.media or not item.media.has_data: + if item.media and item.media.path: + return hash(item.media.path) log.warning("Item (%s, %s) has no image " "info, counted as unique", item.id, item.subset) return None # Disable B303:md5, because the hash is not used in a security context - return hashlib.md5(item.image.data.tobytes()).hexdigest() # nosec + return hashlib.md5(item.media.data.tobytes()).hexdigest() # nosec def __init__(self, item_hash: Optional[Callable] = None): self._hash = item_hash or self._default_item_hash diff --git a/datumaro/components/project.py b/datumaro/components/project.py index d0fd2838c1..ab97e4a257 100644 --- a/datumaro/components/project.py +++ b/datumaro/components/project.py @@ -110,6 +110,8 @@ def categories(self): def get(self, id, subset=None): return self._dataset.get(id, subset) + def media_type(self): + return self._dataset.media_type() class IgnoreMode(Enum): rewrite = auto() diff --git a/datumaro/plugins/ade20k2017_format.py b/datumaro/plugins/ade20k2017_format.py index 9bed484b2f..d657dba5ab 100644 --- a/datumaro/plugins/ade20k2017_format.py +++ b/datumaro/plugins/ade20k2017_format.py @@ -15,6 +15,7 @@ ) from datumaro.components.extractor import DatasetItem, Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import ( IMAGE_EXTENSIONS, find_images, lazy_image, load_image, ) @@ -111,7 +112,7 @@ def _load_items(self, subset): + '_parts_%s.png' % (part_level + 1) self._items.append(DatasetItem(item_id, subset=subset, - image=image_path, annotations=item_annotations)) + media=Image(path=image_path), annotations=item_annotations)) def _load_item_info(self, path): attr_path = osp.splitext(path)[0] + '_atr.txt' diff --git a/datumaro/plugins/ade20k2020_format.py b/datumaro/plugins/ade20k2020_format.py index f02bd0f219..1798d4fbc8 100644 --- a/datumaro/plugins/ade20k2020_format.py +++ b/datumaro/plugins/ade20k2020_format.py @@ -15,6 +15,7 @@ ) from datumaro.components.extractor import DatasetItem, Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util import parse_json from datumaro.util.image import ( IMAGE_EXTENSIONS, find_images, lazy_image, load_image, @@ -132,7 +133,7 @@ def _load_items(self, subset): )) self._items.append(DatasetItem(item_id, subset=subset, - image=image_path, annotations=item_annotations)) + media=Image(path=image_path), annotations=item_annotations)) def _load_item_info(self, path): json_path = osp.splitext(path)[0] + '.json' diff --git a/datumaro/plugins/align_celeba_format.py b/datumaro/plugins/align_celeba_format.py index c17917f99a..f6a97cd3b0 100644 --- a/datumaro/plugins/align_celeba_format.py +++ b/datumaro/plugins/align_celeba_format.py @@ -9,6 +9,7 @@ ) from datumaro.components.errors import DatasetImportError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.image import find_images from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -68,8 +69,12 @@ def _load_items(self, root_dir): label_categories.add('class-%d' % len(label_categories)) anno.append(Label(label)) + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id), annotations=anno) + media=image, annotations=anno) landmark_path = osp.join(root_dir, AlignCelebaPath.LANDMARKS_FILE) if osp.isfile(landmark_path): @@ -124,8 +129,12 @@ def _load_items(self, root_dir): for name, ann in zip(attr_names, item_ann)} if item_id not in items: + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id)) + media=image) items[item_id].attributes = attrs @@ -143,8 +152,11 @@ def _load_items(self, root_dir): subset = AlignCelebaPath.SUBSETS[subset_id] if item_id not in items: + image = images.get(item_id) + if image: + image = Image(path=image) items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id)) + media=image) items[item_id].subset = subset diff --git a/datumaro/plugins/camvid_format.py b/datumaro/plugins/camvid_format.py index 3df22c10cd..5602550f5a 100644 --- a/datumaro/plugins/camvid_format.py +++ b/datumaro/plugins/camvid_format.py @@ -17,8 +17,10 @@ ) from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util import find, str_to_bool from datumaro.util.annotation_util import make_label_id_mapping from datumaro.util.image import save_image @@ -212,7 +214,7 @@ def _load_items(self, path): Mask(image=image, label=label_id)) items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image_path, annotations=item_annotations) + media=Image(path=image_path), annotations=item_annotations) return items @@ -287,13 +289,17 @@ def __init__(self, extractor, save_dir, self._load_categories(label_map) def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) for subset_name, subset in self._extractor.subsets().items(): segm_list = {} for item in subset: image_path = self._make_image_filename(item, subdir=subset_name) - if self._save_images: + if self._save_media and item.media: self._save_image(item, osp.join(self._save_dir, image_path)) masks = [a for a in item.annotations @@ -430,7 +436,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_image): + if not (status == ItemStatus.removed or not item.media): continue image_path = osp.join(save_dir, diff --git a/datumaro/plugins/celeba_format.py b/datumaro/plugins/celeba_format.py index 778f43df8b..dabd88bf33 100644 --- a/datumaro/plugins/celeba_format.py +++ b/datumaro/plugins/celeba_format.py @@ -9,6 +9,7 @@ ) from datumaro.components.errors import DatasetImportError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.image import find_images from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -66,8 +67,12 @@ def _load_items(self, root_dir): label_categories.add('class-%d' % len(label_categories)) anno.append(Label(label)) + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id), annotations=anno) + media=image, annotations=anno) landmark_path = osp.join(root_dir, CelebaPath.LANDMARKS_FILE) if osp.isfile(landmark_path): @@ -153,8 +158,12 @@ def _load_items(self, root_dir): for name, ann in zip(attr_names, item_ann)} if item_id not in items: + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id)) + media=image) items[item_id].attributes = attrs @@ -172,8 +181,12 @@ def _load_items(self, root_dir): subset = CelebaPath.SUBSETS[subset_id] if item_id not in items: + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, - image=images.get(item_id)) + media=image) items[item_id].subset = subset diff --git a/datumaro/plugins/cifar_format.py b/datumaro/plugins/cifar_format.py index 7226be2720..094a562e55 100644 --- a/datumaro/plugins/cifar_format.py +++ b/datumaro/plugins/cifar_format.py @@ -15,7 +15,9 @@ ) from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util import cast from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -154,8 +156,11 @@ def _load_items(self, path): .reshape(3, CifarPath.IMAGE_SIZE, CifarPath.IMAGE_SIZE) image = np.transpose(image, (1, 2, 0)) + if image is not None: + image = Image(data=image) + items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image, annotations=annotations) + media=image, annotations=annotations) return items @@ -178,6 +183,10 @@ class CifarConverter(Converter): DEFAULT_IMAGE_EXT = '.png' def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: @@ -224,8 +233,8 @@ def apply(self): labels.append(None) coarse_labels.append(None) - if self._save_images and item.has_image: - image = item.image + if self._save_media and item.media: + image = item.media if not image.has_data: data.append(None) else: diff --git a/datumaro/plugins/cityscapes_format.py b/datumaro/plugins/cityscapes_format.py index 9ca92c411d..0a96cb294a 100644 --- a/datumaro/plugins/cityscapes_format.py +++ b/datumaro/plugins/cityscapes_format.py @@ -16,7 +16,9 @@ ) from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util import find from datumaro.util.annotation_util import make_label_id_mapping from datumaro.util.image import find_images, load_image, save_image @@ -257,13 +259,16 @@ def _load_items(self): label=label_id, id=ann_id, attributes = { 'is_crowd': is_crowd })) + image = image_path_by_id.pop(item_id, None) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image_path_by_id.pop(item_id, None), - annotations=anns) + media=image, annotations=anns) for item_id, path in image_path_by_id.items(): items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=path) + media=Image(path=path)) self._categories = self._load_categories(self._path, use_train_label_map= \ @@ -325,6 +330,10 @@ def __init__(self, extractor, save_dir, self._load_categories(label_map) def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) for subset_name, subset in self._extractor.subsets().items(): @@ -333,7 +342,7 @@ def apply(self): CityscapesPath.ORIGINAL_IMAGE_DIR, subset_name, item.id + CityscapesPath.ORIGINAL_IMAGE + \ self._find_image_ext(item)) - if self._save_images: + if self._save_media: self._save_image(item, osp.join(self._save_dir, image_path)) masks = [a for a in item.annotations @@ -471,8 +480,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or \ - not item.has_image and not item.has_point_cloud): + if not (status == ItemStatus.removed or not item.media): continue image_path = osp.join(save_dir, CityscapesPath.IMGS_FINE_DIR, diff --git a/datumaro/plugins/coco_format/converter.py b/datumaro/plugins/coco_format/converter.py index 17df8911fa..28166508d0 100644 --- a/datumaro/plugins/coco_format/converter.py +++ b/datumaro/plugins/coco_format/converter.py @@ -15,7 +15,9 @@ ) from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.util import cast, dump_json_file, find, str_to_bool from datumaro.util.image import save_image import datumaro.util.annotation_util as anno_tools @@ -67,8 +69,8 @@ def _get_image_id(self, item): def save_image_info(self, item, filename): h = 0 w = 0 - if item.has_image and item.image.size: - h, w = item.image.size + if item.media and item.media.size: + h, w = item.media.size self._data['images'].append({ 'id': self._get_image_id(item), @@ -260,11 +262,11 @@ def save_annotations(self, item): if not instances: return - if not item.has_image or not item.image.size: + if not item.media or not item.media.size: log.warning("Item '%s': skipping writing instances " "since no image info available" % item.id) return - h, w = item.image.size + h, w = item.media.size instances = [self.find_instance_parts(i, w, h) for i in instances] if self._context._crop_covered: @@ -289,8 +291,8 @@ def convert_instance(self, instance, item): area = 0 if segmentation: - if item.has_image and item.image.size: - h, w = item.image.size + if item.media and item.media.size: + h, w = item.media.size else: # Here we can guess the image size as # it is only needed for the area computation @@ -470,7 +472,7 @@ def save_categories(self, dataset): }) def save_annotations(self, item): - if not item.has_image: + if not item.media: return ann_filename = item.id + CocoPath.PANOPTIC_EXT @@ -646,6 +648,10 @@ def _get_image_id(self, item): return image_id def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + self._make_dirs() if self._save_dataset_meta: @@ -662,8 +668,8 @@ def apply(self): for item in pbar.iter(subset, desc=f'Exporting {subset_name}'): try: - if self._save_images: - if item.has_image: + if self._save_media: + if item.media: self._save_image(item, subdir=osp.join( self._images_dir, '' if self._merge_images else subset_name)) @@ -711,7 +717,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_image): + if not (status == ItemStatus.removed or not item.media): continue # Converter supports saving in separate dirs and common image dir diff --git a/datumaro/plugins/coco_format/extractor.py b/datumaro/plugins/coco_format/extractor.py index c362cf8bae..28908ed9d6 100644 --- a/datumaro/plugins/coco_format/extractor.py +++ b/datumaro/plugins/coco_format/extractor.py @@ -145,7 +145,7 @@ def _load_items(self, json_data): items[img_id] = DatasetItem( id=osp.splitext(img_info['file_name'])[0], subset=self._subset, - image=Image( + media=Image( path=osp.join(self._images_dir, img_info['file_name']), size=image_size), annotations=[], diff --git a/datumaro/plugins/cvat_format/converter.py b/datumaro/plugins/cvat_format/converter.py index 779b2412c0..3e905b70be 100644 --- a/datumaro/plugins/cvat_format/converter.py +++ b/datumaro/plugins/cvat_format/converter.py @@ -13,7 +13,9 @@ from datumaro.components.annotation import AnnotationType, LabelCategories from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.util import cast, pairs from .format import CvatPath @@ -170,14 +172,14 @@ def _write_item(self, item, index): image_info = OrderedDict([ ("id", str(index)), ]) filename = self._context._make_image_filename(item) image_info["name"] = filename - if item.has_image: - size = item.image.size + if item.media: + size = item.media.size if size: h, w = size image_info["width"] = str(w) image_info["height"] = str(h) - if self._context._save_images: + if self._context._save_media: self._context._save_image(item, osp.join(self._context._images_dir, filename)) else: @@ -372,6 +374,10 @@ def __init__(self, extractor, save_dir, reindex=False, self._allow_undeclared_attrs = allow_undeclared_attrs def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + self._images_dir = osp.join(self._save_dir, CvatPath.IMAGES_DIR) os.makedirs(self._images_dir, exist_ok=True) @@ -406,7 +412,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_image): + if not (status == ItemStatus.removed or not item.media): ids_to_remove[item_id] = (item, False) else: ids_to_remove.setdefault(item_id, (item, True)) diff --git a/datumaro/plugins/cvat_format/extractor.py b/datumaro/plugins/cvat_format/extractor.py index a92d8e2e43..ce15aba979 100644 --- a/datumaro/plugins/cvat_format/extractor.py +++ b/datumaro/plugins/cvat_format/extractor.py @@ -308,9 +308,11 @@ def _load_items(self, parsed): image_size = (item_desc.get('height'), item_desc.get('width')) if all(image_size): image = Image(path=image, size=tuple(map(int, image_size))) + else: + image = Image(path=image) parsed[frame_id] = DatasetItem(id=osp.splitext(name)[0], - subset=self._subset, image=image, + subset=self._subset, media=image, annotations=item_desc.get('annotations'), attributes={'frame': int(frame_id)}) return parsed diff --git a/datumaro/plugins/datumaro_format/converter.py b/datumaro/plugins/datumaro_format/converter.py index 53661b6220..ac2645ee6c 100644 --- a/datumaro/plugins/datumaro_format/converter.py +++ b/datumaro/plugins/datumaro_format/converter.py @@ -19,6 +19,7 @@ from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus from datumaro.components.extractor import DEFAULT_SUBSET_NAME, DatasetItem +from datumaro.components.media import Image, MediaElement, PointCloud from datumaro.util import cast, dump_json_file from .format import DatumaroPath @@ -45,7 +46,7 @@ def items(self): def is_empty(self): return not self.items - def add_item(self, item): + def add_item(self, item: DatasetItem): annotations = [] item_desc = { 'id': item.id, @@ -55,9 +56,10 @@ def add_item(self, item): if item.attributes: item_desc['attr'] = item.attributes - if item.has_image: - path = item.image.path - if self._context._save_images: + if isinstance(item.media, Image): + image = item.media_as(Image) + path = image.path + if self._context._save_media: path = self._context._make_image_filename(item) self._context._save_image(item, osp.join(self._context._images_dir, item.subset, path)) @@ -65,12 +67,12 @@ def add_item(self, item): item_desc['image'] = { 'path': path, } - if item.image.has_size: # avoid occasional loading - item_desc['image']['size'] = item.image.size - - if item.has_point_cloud: - path = item.point_cloud - if self._context._save_images: + if item.media.has_size: # avoid occasional loading + item_desc['image']['size'] = item.media.size + elif isinstance(item.media, PointCloud): + pcd = item.media_as(PointCloud) + path = pcd.path + if self._context._save_media: path = self._context._make_pcd_filename(item) self._context._save_point_cloud(item, osp.join(self._context._pcd_dir, item.subset, path)) @@ -79,15 +81,14 @@ def add_item(self, item): 'path': path } - if item.related_images: - images = sorted(item.related_images, key=lambda i: i.path) - if self._context._save_images: + images = sorted(pcd.extra_images, key=lambda v: v.path) + if self._context._save_media: related_images = [] for i, img in enumerate(images): ri_desc = {} - # Images can have completely the same names or don't have - # them at all, so we just rename them + # Images can have completely the same names or don't + # have them at all, so we just rename them ri_desc['path'] = \ f'image_{i}{self._context._find_image_ext(img)}' @@ -100,7 +101,13 @@ def add_item(self, item): else: related_images = [{'path': img.path} for img in images] - item_desc['related_images'] = related_images + if related_images: + item_desc['related_images'] = related_images + + if isinstance(item.media, MediaElement): + item_desc['media'] = { + 'path': item.media.path + } self.items.append(item_desc) @@ -326,8 +333,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or \ - not item.has_image and not item.has_point_cloud): + if not (status == ItemStatus.removed or not item.media): continue image_path = osp.join(save_dir, DatumaroPath.IMAGES_DIR, diff --git a/datumaro/plugins/datumaro_format/extractor.py b/datumaro/plugins/datumaro_format/extractor.py index 28fe43267c..3bc99ed617 100644 --- a/datumaro/plugins/datumaro_format/extractor.py +++ b/datumaro/plugins/datumaro_format/extractor.py @@ -8,9 +8,10 @@ AnnotationType, Bbox, Caption, Cuboid3d, Label, LabelCategories, MaskCategories, Points, PointsCategories, Polygon, PolyLine, RleMask, ) +from datumaro.components.errors import DatasetImportError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext -from datumaro.components.media import Image +from datumaro.components.media import Image, MediaElement, PointCloud from datumaro.util import parse_json, parse_json_file from .format import DatumaroPath @@ -85,7 +86,7 @@ def _load_items(self, parsed): for item_desc in parsed['items']: item_id = item_desc['id'] - image = None + media = None image_info = item_desc.get('image') if image_info: image_filename = image_info.get('path') or \ @@ -98,30 +99,40 @@ def _load_items(self, parsed): if osp.isfile(old_image_path): image_path = old_image_path - image = Image(path=image_path, size=image_info.get('size')) + media = Image(path=image_path, size=image_info.get('size')) + self._media_type = Image - point_cloud = None pcd_info = item_desc.get('point_cloud') + if media and pcd_info: + raise DatasetImportError("Dataset cannot contain multiple media types") if pcd_info: pcd_path = pcd_info.get('path') point_cloud = osp.join(self._pcd_dir, self._subset, pcd_path) - related_images = None - ri_info = item_desc.get('related_images') - if ri_info: - related_images = [ - Image(size=ri.get('size'), - path=osp.join(self._related_images_dir, self._subset, - item_id, ri.get('path')) - ) - for ri in ri_info - ] + related_images = None + ri_info = item_desc.get('related_images') + if ri_info: + related_images = [ + Image(size=ri.get('size'), + path=osp.join(self._related_images_dir, self._subset, + item_id, ri.get('path')) + ) + for ri in ri_info + ] + + media = PointCloud(point_cloud, extra_images=related_images) + self._media_type = PointCloud + + media_desc = item_desc.get('media') + if not media and media_desc and media_desc.get('path'): + media = MediaElement(path=media_desc.get('path')) + self._media_type = MediaElement annotations = self._load_annotations(item_desc) item = DatasetItem(id=item_id, subset=self._subset, - annotations=annotations, image=image, point_cloud=point_cloud, - related_images=related_images, attributes=item_desc.get('attr')) + annotations=annotations, media=media, + attributes=item_desc.get('attr')) items.append(item) diff --git a/datumaro/plugins/icdar_format/converter.py b/datumaro/plugins/icdar_format/converter.py index 972fe7d70d..26ca4ca709 100644 --- a/datumaro/plugins/icdar_format/converter.py +++ b/datumaro/plugins/icdar_format/converter.py @@ -7,7 +7,8 @@ from datumaro.components.annotation import AnnotationType, CompiledMask from datumaro.components.converter import Converter -from datumaro.components.errors import DatumaroError +from datumaro.components.errors import DatumaroError, MediaTypeError +from datumaro.components.media import Image from datumaro.util.image import save_image from datumaro.util.mask_tools import generate_colormap, paint_mask @@ -18,11 +19,15 @@ class IcdarWordRecognitionConverter(Converter): DEFAULT_IMAGE_EXT = IcdarPath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + for subset_name, subset in self._extractor.subsets().items(): annotation = '' for item in subset: image_filename = self._make_image_filename(item) - if self._save_images and item.has_image: + if self._save_media and item.media: self._save_image(item, osp.join(self._save_dir, subset_name, IcdarPath.IMAGES_DIR, image_filename)) @@ -43,9 +48,13 @@ class IcdarTextLocalizationConverter(Converter): DEFAULT_IMAGE_EXT = IcdarPath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + for subset_name, subset in self._extractor.subsets().items(): for item in subset: - if self._save_images and item.has_image: + if self._save_media and item.media: self._save_image(item, subdir=osp.join(subset_name, IcdarPath.IMAGES_DIR)) @@ -71,12 +80,16 @@ class IcdarTextSegmentationConverter(Converter): DEFAULT_IMAGE_EXT = IcdarPath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + for subset_name, subset in self._extractor.subsets().items(): for item in subset: self._save_item(subset_name, subset, item) def _save_item(self, subset_name, subset, item): - if self._save_images and item.has_image: + if self._save_media and item.media: self._save_image(item, subdir=osp.join(subset_name, IcdarPath.IMAGES_DIR)) diff --git a/datumaro/plugins/icdar_format/extractor.py b/datumaro/plugins/icdar_format/extractor.py index 348cf59087..e5b15cf1ff 100644 --- a/datumaro/plugins/icdar_format/extractor.py +++ b/datumaro/plugins/icdar_format/extractor.py @@ -14,6 +14,7 @@ ) from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import IMAGE_EXTENSIONS, find_images from datumaro.util.mask_tools import lazy_mask @@ -78,7 +79,7 @@ def _load_recognition_items(self): IcdarPath.IMAGES_DIR, image) if item_id not in items: items[item_id] = DatasetItem(item_id, subset=self._subset, - image=image_path) + media=Image(path=image_path)) annotations = items[item_id].annotations for caption in captions: @@ -106,8 +107,13 @@ def _load_localization_items(self): item_id = item_id.replace('\\', '/') if item_id not in items: + image = None + image_path = images.get(item_id) + if image_path: + image = Image(path=image_path) + items[item_id] = DatasetItem(item_id, subset=self._subset, - image=images.get(item_id)) + media=image) annotations = items[item_id].annotations with open(path, encoding='utf-8') as f: @@ -175,8 +181,13 @@ def _load_segmentation_items(self): item_id = item_id[:-3] if item_id not in items: + image = None + image_path = images.get(item_id) + if image_path: + image = Image(path=image_path) + items[item_id] = DatasetItem(item_id, subset=self._subset, - image=images.get(item_id)) + media=image) annotations = items[item_id].annotations colors = [(255, 255, 255)] diff --git a/datumaro/plugins/image_dir_format.py b/datumaro/plugins/image_dir_format.py index 3c6dc7df0b..0635af9208 100644 --- a/datumaro/plugins/image_dir_format.py +++ b/datumaro/plugins/image_dir_format.py @@ -8,6 +8,7 @@ from datumaro.components.converter import Converter from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.image import find_images @@ -39,7 +40,7 @@ def __init__(self, url, subset=None): for path in find_images(url, recursive=True): item_id = osp.relpath(osp.splitext(path)[0], url) self._items.append(DatasetItem(id=item_id, subset=self._subset, - image=path)) + media=Image(path=path))) class ImageDirConverter(Converter): DEFAULT_IMAGE_EXT = '.jpg' @@ -48,7 +49,7 @@ def apply(self): os.makedirs(self._save_dir, exist_ok=True) for item in self._extractor: - if item.has_image: + if item.media: self._save_image(item) else: log.debug("Item '%s' has no image info", item.id) diff --git a/datumaro/plugins/image_zip_format.py b/datumaro/plugins/image_zip_format.py index 83d8951cdb..8ca9810a6f 100644 --- a/datumaro/plugins/image_zip_format.py +++ b/datumaro/plugins/image_zip_format.py @@ -27,7 +27,7 @@ class ImageZipPath: class ImageZipExtractor(SourceExtractor): def __init__(self, url, subset=None): - super().__init__(subset=subset) + super().__init__(subset=subset, media_type=ByteImage) assert url.endswith('.zip'), url @@ -38,7 +38,7 @@ def __init__(self, url, subset=None): continue image = ByteImage(data=zf.read(path.filename)) self._items.append(DatasetItem( - id=item_id, image=image, subset=self._subset + id=item_id, media=image, subset=self._subset )) class ImageZipImporter(Importer): @@ -99,17 +99,17 @@ def apply(self): with ZipFile(archive_path, 'w', self._compression) as zf: for item in self._extractor: - if item.has_image: + if item.media: self._archive_image(zf, item) else: log.debug("Item '%s' has no image info", item.id) def _archive_image(self, zipfile, item): image_name = self._make_image_filename(item) - if osp.isfile(item.image.path): - zipfile.write(item.image.path, arcname=image_name) - elif isinstance(item.image, ByteImage): - zipfile.writestr(image_name, item.image.get_bytes()) - elif item.image.has_data: + if osp.isfile(item.media.path): + zipfile.write(item.media.path, arcname=image_name) + elif isinstance(item.media, ByteImage): + zipfile.writestr(image_name, item.media.get_bytes()) + elif item.media.has_data: zipfile.writestr(image_name, - encode_image(item.image.data, osp.splitext(image_name)[1])) + encode_image(item.media.data, osp.splitext(image_name)[1])) diff --git a/datumaro/plugins/imagenet_format.py b/datumaro/plugins/imagenet_format.py index 1a5f452ddf..bb1dac083a 100644 --- a/datumaro/plugins/imagenet_format.py +++ b/datumaro/plugins/imagenet_format.py @@ -10,7 +10,9 @@ AnnotationType, Label, LabelCategories, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.image import find_images @@ -44,7 +46,7 @@ def _load_items(self, path): item = items.get(item_id) if item is None: item = DatasetItem(id=item_id, subset=self._subset, - image=image_path) + media=Image(path=image_path)) items[item_id] = item annotations = item.annotations @@ -74,6 +76,10 @@ def _get_dir_name(id_parts, label_name): else: return label_name + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + if 1 < len(self._extractor.subsets()): log.warning("ImageNet format only supports exporting a single " "subset, subset information will not be used.") diff --git a/datumaro/plugins/imagenet_txt_format.py b/datumaro/plugins/imagenet_txt_format.py index f2b8e44e82..e238420795 100644 --- a/datumaro/plugins/imagenet_txt_format.py +++ b/datumaro/plugins/imagenet_txt_format.py @@ -12,9 +12,10 @@ ) from datumaro.components.cli_plugin import CliPlugin from datumaro.components.converter import Converter -from datumaro.components.errors import DatasetImportError +from datumaro.components.errors import DatasetImportError, MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -120,7 +121,7 @@ def _load_items(self, path): anno.append(Label(label)) items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=osp.join(self.image_dir, image), annotations=anno) + media=Image(path=osp.join(self.image_dir, image)), annotations=anno) return items @@ -178,6 +179,10 @@ class ImagenetTxtConverter(Converter): DEFAULT_IMAGE_EXT = '.jpg' def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + subset_dir = self._save_dir os.makedirs(subset_dir, exist_ok=True) @@ -194,7 +199,7 @@ def apply(self): labels[item_id] = set(p.label for p in item.annotations if p.type == AnnotationType.label) - if self._save_images and item.has_image: + if self._save_media and item.media: self._save_image(item, subdir=ImagenetTxtPath.IMAGE_DIR) annotation = '' diff --git a/datumaro/plugins/kitti_format/converter.py b/datumaro/plugins/kitti_format/converter.py index df187a8c6c..f0d9eb8358 100644 --- a/datumaro/plugins/kitti_format/converter.py +++ b/datumaro/plugins/kitti_format/converter.py @@ -14,6 +14,8 @@ AnnotationType, CompiledMask, LabelCategories, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError +from datumaro.components.media import Image from datumaro.util import cast, parse_str_enum_value, str_to_bool from datumaro.util.annotation_util import make_label_id_mapping from datumaro.util.image import save_image @@ -87,6 +89,10 @@ def __init__(self, extractor, save_dir, LabelCategories())} def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) for subset_name, subset in self._extractor.subsets().items(): @@ -95,7 +101,7 @@ def apply(self): KittiPath.INSTANCES_DIR), exist_ok=True) for item in subset: - if self._save_images: + if self._save_media: self._save_image(item, subdir=osp.join(subset_name, KittiPath.IMAGES_DIR)) diff --git a/datumaro/plugins/kitti_format/extractor.py b/datumaro/plugins/kitti_format/extractor.py index 09c4d35fcd..e886f1bae1 100644 --- a/datumaro/plugins/kitti_format/extractor.py +++ b/datumaro/plugins/kitti_format/extractor.py @@ -11,6 +11,7 @@ from datumaro.components.extractor import ( AnnotationType, DatasetItem, SourceExtractor, ) +from datumaro.components.media import Image from datumaro.util.image import find_images, load_image from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -84,9 +85,12 @@ def _load_items(self): label=semantic_id, id=ann_id, attributes={ 'is_crowd': isCrowd })) + image = image_path_by_id.pop(item_id, None) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, annotations=anns, - image=image_path_by_id.pop(item_id, None), - subset=self._subset) + media=image, subset=self._subset) det_dir = osp.join(self._path, KittiPath.LABELS_DIR) if self._task == KittiTask.detection: @@ -123,13 +127,16 @@ def _load_items(self): attributes=attributes, label=label_id, )) + image = image_path_by_id.pop(item_id, None) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, annotations=anns, - image=image_path_by_id.pop(item_id, None), - subset=self._subset) + media=image, subset=self._subset) for item_id, image_path in image_path_by_id.items(): items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image_path) + media=Image(path=image_path)) return items diff --git a/datumaro/plugins/kitti_raw_format/converter.py b/datumaro/plugins/kitti_raw_format/converter.py index c59fb7a60a..7f507e72aa 100644 --- a/datumaro/plugins/kitti_raw_format/converter.py +++ b/datumaro/plugins/kitti_raw_format/converter.py @@ -12,7 +12,9 @@ from datumaro.components.annotation import AnnotationType, LabelCategories from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem +from datumaro.components.media import PointCloud from datumaro.util import cast from datumaro.util.image import find_images @@ -414,23 +416,26 @@ def _write_item(self, item, index): if not self._reindex: index = cast(item.attributes.get('frame'), int, index) - if self._save_images: - if item.has_point_cloud: - self._save_point_cloud(item, subdir=KittiRawPath.PCD_DIR) + if self._save_media and item.media: + self._save_point_cloud(item, subdir=KittiRawPath.PCD_DIR) - images = sorted(item.related_images, key=lambda img: img.path) + images = sorted(item.media.extra_images, key=lambda img: img.path) for i, image in enumerate(images): if image.has_data: image.save(osp.join(self._save_dir, KittiRawPath.IMG_DIR_PREFIX + ('%02d' % i), 'data', item.id + self._find_image_ext(image))) - else: + elif self._save_media and not item.media: log.debug("Item '%s' has no image info", item.id) return index def apply(self): + if self._extractor.media_type() and \ + self._extractor.media_type() is not PointCloud: + raise MediaTypeError("Media type is not a point cloud") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: @@ -458,7 +463,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_point_cloud): + if not (status == ItemStatus.removed or not item.media): continue pcd_path = osp.join(pcd_dir, conv._make_pcd_filename(item)) diff --git a/datumaro/plugins/kitti_raw_format/extractor.py b/datumaro/plugins/kitti_raw_format/extractor.py index eb02c4a010..ff7636219a 100644 --- a/datumaro/plugins/kitti_raw_format/extractor.py +++ b/datumaro/plugins/kitti_raw_format/extractor.py @@ -12,6 +12,7 @@ ) from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image, PointCloud from datumaro.util import cast from datumaro.util.image import find_images from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -28,7 +29,7 @@ def __init__(self, path, subset=None): assert osp.isfile(path), path self._rootdir = osp.dirname(path) - super().__init__(subset=subset) + super().__init__(subset=subset, media_type=PointCloud) items, categories = self._parse(path) self._items = list(self._load_items(items).values()) @@ -245,9 +246,9 @@ def _load_items(self, parsed): for frame_id, item_desc in parsed.items(): name = name_mapping.get(frame_id, '%010d' % int(frame_id)) items[frame_id] = DatasetItem(id=name, subset=self._subset, - point_cloud=osp.join(self._rootdir, - KittiRawPath.PCD_DIR, name + '.pcd'), - related_images=sorted(images.get(name, [])), + media=PointCloud( + osp.join(self._rootdir, KittiRawPath.PCD_DIR, name + '.pcd'), + extra_images=[Image(path=image) for image in sorted(images.get(name, []))]), annotations=item_desc.get('annotations'), attributes={'frame': int(frame_id)}) @@ -256,9 +257,9 @@ def _load_items(self, parsed): continue items[frame_id] = DatasetItem(id=name, subset=self._subset, - point_cloud=osp.join(self._rootdir, - KittiRawPath.PCD_DIR, name + '.pcd'), - related_images=sorted(images.get(name, [])), + media=PointCloud( + osp.join(self._rootdir, KittiRawPath.PCD_DIR, name + '.pcd'), + extra_images=[Image(path=image) for image in sorted(images.get(name, []))]), attributes={'frame': int(frame_id)}) return items diff --git a/datumaro/plugins/labelme_format.py b/datumaro/plugins/labelme_format.py index 84e4634427..c63aec95dd 100644 --- a/datumaro/plugins/labelme_format.py +++ b/datumaro/plugins/labelme_format.py @@ -16,6 +16,7 @@ AnnotationType, Bbox, LabelCategories, Mask, Polygon, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext from datumaro.components.media import Image @@ -94,7 +95,7 @@ def _parse(self, dataset_root): osp.join(dataset_root, subset), categories) items.append(DatasetItem(id=item_id, subset=subset, - image=image, annotations=annotations)) + media=image, annotations=annotations)) subsets.add(items[-1].subset) return items, categories, subsets @@ -338,6 +339,10 @@ class LabelMeConverter(Converter): DEFAULT_IMAGE_EXT = LabelMePath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: @@ -364,8 +369,8 @@ def _save_item(self, item, subset_dir): log.debug("Converting item '%s'", item.id) image_filename = self._make_image_filename(item) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if item.media and item.media.has_data: self._save_image(item, osp.join(subset_dir, image_filename)) else: log.debug("Item '%s' has no image", item.id) @@ -378,9 +383,9 @@ def _save_item(self, item, subset_dir): ET.SubElement(source_elem, 'sourceImage').text = '' ET.SubElement(source_elem, 'sourceAnnotation').text = 'Datumaro' - if item.has_image: + if item.media: image_elem = ET.SubElement(root_elem, 'imagesize') - image_size = item.image.size + image_size = item.media.size ET.SubElement(image_elem, 'nrows').text = str(image_size[0]) ET.SubElement(image_elem, 'ncols').text = str(image_size[1]) diff --git a/datumaro/plugins/lfw_format.py b/datumaro/plugins/lfw_format.py index 413684d9ab..8ded5499ee 100644 --- a/datumaro/plugins/lfw_format.py +++ b/datumaro/plugins/lfw_format.py @@ -10,8 +10,10 @@ AnnotationType, Label, LabelCategories, Points, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import find_images from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -93,8 +95,12 @@ def get_label_id(label_name): annotations.append(Label(label)) item_id = item_id[len(label_name) + 1:] if item_id not in items: + image = images.get(item_id) + if image: + image = Image(path=image) + items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=images.get(image), annotations=annotations) + media=image, annotations=annotations) elif len(pair) == 3: image1, id1 = self.get_image_name(pair[0], pair[1]) image2, id2 = self.get_image_name(pair[0], pair[2]) @@ -103,13 +109,23 @@ def get_label_id(label_name): if id1 not in items: annotations = [] annotations.append(Label(label)) + + image = images.get(image1) + if image: + image = Image(path=image) + items[id1] = DatasetItem(id=id1, subset=self._subset, - image=images.get(image1), annotations=annotations) + media=image, annotations=annotations) if id2 not in items: annotations = [] annotations.append(Label(label)) + + image = images.get(image2) + if image: + image = Image(path=image) + items[id2] = DatasetItem(id=id2, subset=self._subset, - image=images.get(image2), annotations=annotations) + media=image, annotations=annotations) # pairs form a directed graph if not items[id1].annotations[0].attributes.get('positive_pairs'): @@ -127,15 +143,25 @@ def get_label_id(label_name): annotations = [] label = get_label_id(pair[0]) annotations.append(Label(label)) + + image = images.get(image1) + if image: + image = Image(path=image) + items[id1] = DatasetItem(id=id1, subset=self._subset, - image=images.get(image1), annotations=annotations) + media=image, annotations=annotations) if id2 not in items: annotations = [] if pair[2] != '-': label = get_label_id(pair[2]) annotations.append(Label(label)) + + image = images.get(image2) + if image: + image = Image(path=image) + items[id2] = DatasetItem(id=id2, subset=self._subset, - image=images.get(image2), annotations=annotations) + media=image, annotations=annotations) # pairs form a directed graph if not items[id1].annotations[0].attributes.get('negative_pairs'): @@ -193,6 +219,10 @@ class LfwConverter(Converter): DEFAULT_IMAGE_EXT = LfwPath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: self._save_meta_file(self._save_dir) @@ -216,7 +246,7 @@ def apply(self): label_name = label_categories[anns[0].label].name labels[label_name] += 1 - if self._save_images and item.has_image: + if self._save_media and item.media: subdir=osp.join(subset_name, LfwPath.IMAGES_DIR) if label_name: subdir=osp.join(subdir, label_name) diff --git a/datumaro/plugins/mapillary_vistas_format/extractor.py b/datumaro/plugins/mapillary_vistas_format/extractor.py index 62f5493e37..61c9b03678 100644 --- a/datumaro/plugins/mapillary_vistas_format/extractor.py +++ b/datumaro/plugins/mapillary_vistas_format/extractor.py @@ -146,7 +146,7 @@ def _load_panoptic_items(self, config): group=segment_id, attributes=attributes)) items[item_id] = DatasetItem(id=item_id, subset=self._subset, - annotations=annotations, image=image) + annotations=annotations, media=image) self._load_polygons(items) return items.values() @@ -211,10 +211,10 @@ def _load_instances_items(self): item_id = osp.splitext(osp.relpath(image_path, self._images_dir))[0] image = Image(path=image_path) if item_id in items: - items[item_id].image = image + items[item_id].media = image else: items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image) + media=image) self._load_polygons(items) return items.values() @@ -231,7 +231,7 @@ def _load_polygons(self, items): image_size = self._get_image_size(item_info) if image_size and item.has_image: - item.image = Image(path=item.image.path, size=image_size) + item.media = Image(path=item.image.path, size=image_size) polygons = item_info['objects'] annotations = [] diff --git a/datumaro/plugins/market1501_format.py b/datumaro/plugins/market1501_format.py index 84c0660782..a7e243a833 100644 --- a/datumaro/plugins/market1501_format.py +++ b/datumaro/plugins/market1501_format.py @@ -7,7 +7,9 @@ import re from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Extractor, Importer +from datumaro.components.media import Image from datumaro.util import str_to_bool from datumaro.util.image import find_images @@ -91,8 +93,8 @@ def _load_items(self, subset, subset_path): item = items.get(item_id) if item is None: - item = DatasetItem(id=item_id, subset=subset, image=image_path, - attributes=attributes) + item = DatasetItem(id=item_id, subset=subset, + media=Image(path=image_path), attributes=attributes) items[item_id] = item return items @@ -118,6 +120,10 @@ def _make_dir_name(self, item): return dirname def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + for subset_name, subset in self._extractor.subsets().items(): annotation = '' used_frames = {} @@ -139,7 +145,7 @@ def apply(self): image_path = self._make_image_filename(item, name=image_name, subdir=dirname) - if self._save_images and item.has_image: + if self._save_media and item.media: self._save_image(item, osp.join(self._save_dir, image_path)) attrs = Market1501Path.PATTERN.search(image_name) diff --git a/datumaro/plugins/mars_format.py b/datumaro/plugins/mars_format.py index 1822133808..2f3e206f0a 100644 --- a/datumaro/plugins/mars_format.py +++ b/datumaro/plugins/mars_format.py @@ -13,6 +13,7 @@ from datumaro.components.dataset import DatasetItem from datumaro.components.extractor import Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import find_images @@ -76,7 +77,7 @@ def _load_items(self, subset, path): f'the directory name: {label}') continue - items.append(DatasetItem(id=item_id, image=image_path, + items.append(DatasetItem(id=item_id, media=Image(path=image_path), subset=subset, annotations=[Label(label=label_id)], attributes={'person_id': pedestrian_id, 'camera_id': int(image_name[5]), diff --git a/datumaro/plugins/mnist_csv_format.py b/datumaro/plugins/mnist_csv_format.py index 196fec7bad..d8641f8536 100644 --- a/datumaro/plugins/mnist_csv_format.py +++ b/datumaro/plugins/mnist_csv_format.py @@ -11,7 +11,9 @@ AnnotationType, Label, LabelCategories, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -87,11 +89,14 @@ def _load_items(self, path): image = np.array([int(pix) for pix in data[1:]], dtype='uint8').reshape(28, 28) + if image is not None: + image = Image(data=image) + if 0 < len(meta) and len(meta[i]) in [1, 3]: i = meta[i][0] items[i] = DatasetItem(id=i, subset=self._subset, - image=image, annotations=item_anno) + media=image, annotations=item_anno) return items class MnistCsvImporter(Importer): @@ -104,6 +109,10 @@ class MnistCsvConverter(Converter): DEFAULT_IMAGE_EXT = '.png' def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: self._save_meta_file(self._save_dir) @@ -119,8 +128,8 @@ def apply(self): if anns: label = anns[0] - if item.has_image and self._save_images: - image = item.image + if item.media and self._save_media: + image = item.media if not image.has_data: data.append([label, None]) else: diff --git a/datumaro/plugins/mnist_format.py b/datumaro/plugins/mnist_format.py index bc8785cc2f..90f619a67a 100644 --- a/datumaro/plugins/mnist_format.py +++ b/datumaro/plugins/mnist_format.py @@ -12,7 +12,9 @@ AnnotationType, Label, LabelCategories, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -103,11 +105,14 @@ def _load_items(self, path): else: image = images[i].reshape(MnistPath.IMAGE_SIZE, MnistPath.IMAGE_SIZE) + if image is not None: + image = Image(data=image) + if 0 < len(meta) and (len(meta[i]) == 1 or len(meta[i]) == 3): i = meta[i][0] items[i] = DatasetItem(id=i, subset=self._subset, - image=image, annotations=annotations) + media=image, annotations=annotations) return items class MnistImporter(Importer): @@ -120,6 +125,10 @@ class MnistConverter(Converter): DEFAULT_IMAGE_EXT = '.png' def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: self._save_meta_file(self._save_dir) @@ -140,8 +149,8 @@ def apply(self): if item.id != str(len(labels) - 1): item_ids[len(labels) - 1] = item.id - if item.has_image and self._save_images: - image = item.image + if item.media and self._save_media: + image = item.media if not image.has_data: image_sizes[len(images) - 1] = [0, 0] else: diff --git a/datumaro/plugins/mot_format.py b/datumaro/plugins/mot_format.py index da49979f40..073d510080 100644 --- a/datumaro/plugins/mot_format.py +++ b/datumaro/plugins/mot_format.py @@ -15,6 +15,7 @@ from datumaro.components.annotation import AnnotationType, Bbox, LabelCategories from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext from datumaro.components.media import Image @@ -129,7 +130,7 @@ def _load_items(self, path): items[frame_id] = DatasetItem( id=frame_id, subset=self._subset, - image=Image( + media=Image( path=osp.join(self._image_dir, '%06d%s' % (frame_id, self._seq_info['imext'])), size=(self._seq_info['imheight'], self._seq_info['imwidth']) @@ -139,7 +140,7 @@ def _load_items(self, path): for p in find_images(self._image_dir): frame_id = int(osp.splitext(osp.relpath(p, self._image_dir))[0]) items[frame_id] = DatasetItem(id=frame_id, subset=self._subset, - image=p) + media=Image(path=p)) with open(path, newline='', encoding='utf-8') as csv_file: # NOTE: Different MOT files have different count of fields @@ -218,6 +219,10 @@ class MotSeqGtConverter(Converter): def apply(self): extractor = self._extractor + if extractor.media_type() and \ + not issubclass(extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + image_dir = osp.join(self._save_dir, MotPath.IMAGE_DIR) os.makedirs(image_dir, exist_ok=True) @@ -260,8 +265,8 @@ def apply(self): ) }) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if item.media and item.media.has_data: self._save_image(item, subdir=image_dir, name='%06d' % frame_id) else: diff --git a/datumaro/plugins/mots_format.py b/datumaro/plugins/mots_format.py index 74ea68c06b..095dec05ea 100644 --- a/datumaro/plugins/mots_format.py +++ b/datumaro/plugins/mots_format.py @@ -14,7 +14,9 @@ from datumaro.components.annotation import AnnotationType, LabelCategories, Mask from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image from datumaro.util.image import find_images, load_image, save_image from datumaro.util.mask_tools import merge_masks from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -77,9 +79,11 @@ def _parse_items(self): for p in sorted(iglob(self._anno_dir + '/**/*.png', recursive=True)): item_id = osp.splitext(osp.relpath(p, self._anno_dir))[0] + image = images.get(item_id) + if image: + image = Image(path=image) items.append(DatasetItem(id=item_id, subset=self._subset, - image=images.get(item_id), - annotations=self._parse_annotations(p))) + media=image, annotations=self._parse_annotations(p))) return items @staticmethod @@ -127,6 +131,10 @@ class MotsPngConverter(Converter): DEFAULT_IMAGE_EXT = MotsPath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(self._save_dir, exist_ok=True) if self._save_dataset_meta: @@ -141,8 +149,8 @@ def apply(self): for item in subset: log.debug("Converting item '%s'", item.id) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if item.media and item.media.has_data: self._save_image(item, subdir=image_dir) else: log.debug("Item '%s' has no image", item.id) diff --git a/datumaro/plugins/mpii_format/mpii_json.py b/datumaro/plugins/mpii_format/mpii_json.py index cefa25c4b9..14b826ce21 100644 --- a/datumaro/plugins/mpii_format/mpii_json.py +++ b/datumaro/plugins/mpii_format/mpii_json.py @@ -129,7 +129,7 @@ def _load_items(self, path): group_num +=1 items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=Image(path=osp.join(root_dir, ann.get('img_paths', ''))), + media=Image(path=osp.join(root_dir, ann.get('img_paths', ''))), annotations=annotations) return items diff --git a/datumaro/plugins/mpii_format/mpii_mat.py b/datumaro/plugins/mpii_format/mpii_mat.py index 74301e0c3b..73f5c1e8cf 100644 --- a/datumaro/plugins/mpii_format/mpii_mat.py +++ b/datumaro/plugins/mpii_format/mpii_mat.py @@ -127,7 +127,7 @@ def _load_items(self, path): item_id = osp.splitext(image)[0] items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=Image(path=osp.join(root_dir, image)), + media=Image(path=osp.join(root_dir, image)), annotations=annotations) return items diff --git a/datumaro/plugins/ndr.py b/datumaro/plugins/ndr.py index 6b6ff89a4c..a974743b0c 100644 --- a/datumaro/plugins/ndr.py +++ b/datumaro/plugins/ndr.py @@ -168,9 +168,9 @@ def _remove(self): having_image = [] all_imgs = [] for item in working_subset: - if item.image.has_data: + if item.media.has_data: having_image.append(item) - img = item.image.data + img = item.media.data # Not handle empty image, as utils/image.py if check empty if len(img.shape) == 2: img = np.stack((img,)*3, axis=-1) diff --git a/datumaro/plugins/open_images_format.py b/datumaro/plugins/open_images_format.py index 2e61ddb2ec..51d55fc853 100644 --- a/datumaro/plugins/open_images_format.py +++ b/datumaro/plugins/open_images_format.py @@ -25,7 +25,7 @@ from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus from datumaro.components.errors import ( - DatasetError, RepeatedItemError, UndefinedLabel, + DatasetError, MediaTypeError, RepeatedItemError, UndefinedLabel, ) from datumaro.components.extractor import DatasetItem, Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext @@ -333,7 +333,7 @@ def _add_item(self, item_id, subset): else: image = Image(path=image_path, size=self._image_meta.get(item_id)) - item = DatasetItem(id=item_id, image=image, subset=subset) + item = DatasetItem(id=item_id, media=image, subset=subset) self._items.append(item) return item @@ -401,8 +401,8 @@ def _load_bboxes(self, items_by_id): item_id=item.id, subset=item.subset, label_name=label_name, severity=Severity.error) - if item.has_image and item.image.size is not None: - height, width = item.image.size + if item.media and item.media.size is not None: + height, width = item.media.size elif self._image_meta.get(item.id): height, width = self._image_meta[item.id] else: @@ -482,8 +482,8 @@ def _load_masks(self, items_by_id, normalized_coords): item_id=item.id, subset=item.subset, label_name=label_name, severity=Severity.error) - if item.has_image and item.image.has_size: - image_size = item.image.size + if item.media and item.media.has_size: + image_size = item.media.size elif self._image_meta.get(item.id): image_size = self._image_meta.get(item.id) else: @@ -674,6 +674,10 @@ class OpenImagesConverter(Converter): DEFAULT_IMAGE_EXT = '.jpg' def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + self._save(_AnnotationWriter(self._save_dir)) @classmethod @@ -796,8 +800,8 @@ def _save_subsets(self, annotation_writer): 'ImageID': item.id, 'Subset': subset_name, }) - if self._save_images: - if item.has_image: + if self._save_media: + if item.media: self._save_image(item, subdir=osp.join( OpenImagesPath.IMAGES_DIR, subset_name)) else: @@ -850,9 +854,9 @@ def _save_item_annotations( 'Confidence': str(annotation.attributes.get('score', 1)), }) elif annotation.type is AnnotationType.bbox: - if item.has_image and item.image.size is not None: - image_meta[item.id] = item.image.size - height, width = item.image.size + if item.media and item.media.size is not None: + image_meta[item.id] = item.media.size + height, width = item.media.size else: log.warning( "Can't encode box for item '%s' due to missing image file", @@ -897,9 +901,9 @@ def _save_item_annotations( box_coords = {} if instance_box is not None: - if item.has_image and item.image.size is not None: - image_meta[item.id] = item.image.size - height, width = item.image.size + if item.media and item.media.size is not None: + image_meta[item.id] = item.media.size + height, width = item.media.size box_coords = { 'BoxXMin': instance_box.x / width, diff --git a/datumaro/plugins/sampler/relevancy_sampler.py b/datumaro/plugins/sampler/relevancy_sampler.py index 97a3dbaac7..18f366a7a8 100644 --- a/datumaro/plugins/sampler/relevancy_sampler.py +++ b/datumaro/plugins/sampler/relevancy_sampler.py @@ -132,13 +132,13 @@ def _load_inference_from_subset(extractor, subset_name): for item in subset: data_df['ImageID'].append(item.id) - if not item.has_image or item.image.size is None: + if not item.media or item.media.size is None: raise Exception(f"Item {item.id} does not have image info") - width, height = item.image.size + width, height = item.media.size data_df['Width'].append(width) data_df['Height'].append(height) - data_df['ImagePath'].append(item.image.path) + data_df['ImagePath'].append(item.media.path) if not item.annotations: raise Exception(f"Item {item.id} does not have annotations") diff --git a/datumaro/plugins/sly_pointcloud_format/converter.py b/datumaro/plugins/sly_pointcloud_format/converter.py index 730f047535..6c06922609 100644 --- a/datumaro/plugins/sly_pointcloud_format/converter.py +++ b/datumaro/plugins/sly_pointcloud_format/converter.py @@ -17,7 +17,9 @@ from datumaro.components.annotation import AnnotationType, LabelCategories from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, IExtractor +from datumaro.components.media import PointCloud from datumaro.util import cast, dump_json_file from .format import PointCloudPath @@ -61,7 +63,7 @@ def __init__(self, extractor: IExtractor, def _write_related_images(self, item): img_dir = self._related_images_dir - for img in item.related_images: + for img in item.media.extra_images: name = osp.splitext(osp.basename(img.path))[0] img_path = osp.join(img_dir, item.id + '_pcd', name + self._find_image_ext(img)) @@ -346,13 +348,13 @@ def dump(self): self._init_meta() for item in self._context._extractor: - if self._context._save_images: - if item.has_point_cloud: + if self._context._save_media: + if item.media: self._write_pcd(item) else: log.debug("Item '%s' has no point cloud info", item.id) - if item.related_images: + if item.media and item.media.extra_images: self._write_related_images(item) else: log.debug("Item '%s' has no related images info", item.id) @@ -385,6 +387,10 @@ def __init__(self, extractor, save_dir, reindex=False, self._allow_undeclared_attrs = allow_undeclared_attrs def apply(self): + if self._extractor.media_type() and \ + self._extractor.media_type() is not PointCloud: + raise MediaTypeError("Media type is not an image") + if 1 < len(self._extractor.subsets()): log.warning("Supervisely pointcloud format supports only a single " "subset. Subset information will be ignored on export.") @@ -402,7 +408,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_point_cloud): + if not (status == ItemStatus.removed or not item.media): continue pcd_name = conv._make_pcd_filename(item) diff --git a/datumaro/plugins/sly_pointcloud_format/extractor.py b/datumaro/plugins/sly_pointcloud_format/extractor.py index b6e6faa178..6099375ada 100644 --- a/datumaro/plugins/sly_pointcloud_format/extractor.py +++ b/datumaro/plugins/sly_pointcloud_format/extractor.py @@ -9,6 +9,7 @@ AnnotationType, Cuboid3d, LabelCategories, ) from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor +from datumaro.components.media import Image, PointCloud from datumaro.util import parse_json_file from datumaro.util.image import find_images @@ -27,7 +28,7 @@ def __init__(self, path, subset=None): rootdir = osp.abspath(osp.dirname(path)) self._rootdir = rootdir - super().__init__(subset=subset) + super().__init__(subset=subset, media_type=PointCloud) items, categories = self._parse(rootdir) self._items = list(self._load_items(items).values()) @@ -160,10 +161,11 @@ def _load_items(self, parsed): PointCloudPath.RELATED_IMAGES_DIR, name + '_pcd') related_images = None if osp.isdir(related_images_dir): - related_images = find_images(related_images_dir) + related_images = [Image(path=image) + for image in find_images(related_images_dir)] parsed[frame_id] = DatasetItem(id=name, subset=self._subset, - point_cloud=pcd_path, related_images=related_images, + media=PointCloud(pcd_path, extra_images=related_images), annotations=frame_desc.get('annotations'), attributes={'frame': int(frame_id), **frame_desc['attributes']}) diff --git a/datumaro/plugins/synthia_format.py b/datumaro/plugins/synthia_format.py index 5754d6bb6e..f440442e41 100644 --- a/datumaro/plugins/synthia_format.py +++ b/datumaro/plugins/synthia_format.py @@ -12,6 +12,7 @@ ) from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import find_images, load_image from datumaro.util.mask_tools import generate_colormap, lazy_mask from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -139,7 +140,11 @@ def _load_items(self, root_dir): image=self._lazy_extract_mask(labels_mask, segm_id), label=segm_id, attributes=attr)) - items[item_id] = DatasetItem(id=item_id, image=images[item_id], + image = images.get(item_id) + if image: + image = Image(path=image) + + items[item_id] = DatasetItem(id=item_id, media=image, annotations=anno) elif osp.isdir(osp.join(root_dir, SynthiaPath.SEMANTIC_SEGM_DIR)): @@ -158,7 +163,11 @@ def _load_items(self, root_dir): anno.append(Mask(image=self._lazy_extract_mask(color_mask, label_id), label=label_id)) - items[item_id] = DatasetItem(id=item_id, image=images[item_id], + image = images.get(item_id) + if image: + image = Image(path=image) + + items[item_id] = DatasetItem(id=item_id, media=image, annotations=anno) diff --git a/datumaro/plugins/tf_detection_api_format/converter.py b/datumaro/plugins/tf_detection_api_format/converter.py index 19cb2a1982..77c3f064fb 100644 --- a/datumaro/plugins/tf_detection_api_format/converter.py +++ b/datumaro/plugins/tf_detection_api_format/converter.py @@ -12,7 +12,7 @@ from datumaro.components.annotation import AnnotationType, LabelCategories from datumaro.components.converter import Converter -from datumaro.components.media import ByteImage +from datumaro.components.media import ByteImage, Image from datumaro.util.annotation_util import ( find_group_leader, find_instances, max_bbox, ) @@ -159,10 +159,10 @@ def _make_tf_example(self, item): filename = self._make_image_filename(item) features['image/filename'] = bytes_feature(filename.encode('utf-8')) - if not item.has_image: + if not isinstance(item.media, Image): raise Exception("Failed to export dataset item '%s': " "item has no image info" % item.id) - height, width = item.image.size + height, width = item.media.size features.update({ 'image/height': int64_feature(height), @@ -174,8 +174,8 @@ def _make_tf_example(self, item): 'image/format': bytes_feature(b''), 'image/key/sha256': bytes_feature(b''), }) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if isinstance(item.media, Image) and item.media.has_data: buffer, fmt = self._save_image(item, filename) key = hashlib.sha256(buffer).hexdigest() @@ -197,7 +197,7 @@ def _make_tf_example(self, item): return tf_example def _save_image(self, item, path=None): # pylint: disable=arguments-differ - src_ext = item.image.ext.lower() + src_ext = item.media.ext.lower() dst_ext = osp.splitext(osp.basename(path))[1].lower() fmt = DetectionApiPath.IMAGE_EXT_FORMAT.get(dst_ext, '') if not fmt: @@ -205,10 +205,10 @@ def _save_image(self, item, path=None): # pylint: disable=arguments-differ "image extension, the corresponding field will be empty." % \ (item.id, dst_ext)) - if src_ext == dst_ext and isinstance(item.image, ByteImage): - buffer = item.image.get_bytes() + if src_ext == dst_ext and isinstance(item.media, ByteImage): + buffer = item.media.get_bytes() else: - buffer = encode_image(item.image.data, dst_ext) + buffer = encode_image(item.media.data, dst_ext) return buffer, fmt @classmethod diff --git a/datumaro/plugins/tf_detection_api_format/extractor.py b/datumaro/plugins/tf_detection_api_format/extractor.py index de62a2772b..d3f212bb56 100644 --- a/datumaro/plugins/tf_detection_api_format/extractor.py +++ b/datumaro/plugins/tf_detection_api_format/extractor.py @@ -181,7 +181,7 @@ def _parse_tfrecord_file(cls, filepath, subset, images_dir): image = ByteImage(**image_params, size=image_size) dataset_items.append(DatasetItem(id=item_id, subset=subset, - image=image, annotations=annotations, + media=image, annotations=annotations, attributes={'source_id': frame_id})) return dataset_items, dataset_labels diff --git a/datumaro/plugins/transforms.py b/datumaro/plugins/transforms.py index 59f7ec1325..a7eee656a1 100644 --- a/datumaro/plugins/transforms.py +++ b/datumaro/plugins/transforms.py @@ -53,9 +53,9 @@ def transform_item(self, item): if not segments: return item - if not item.has_image: + if not isinstance(item.media, Image): raise Exception("Image info is required for this transform") - h, w = item.image.size + h, w = item.media.size segments = self.crop_segments(segments, w, h) annotations += segments @@ -135,9 +135,9 @@ def transform_item(self, item): if not segments: return item - if not item.has_image: + if not isinstance(item.media, Image): raise Exception("Image info is required for this transform") - h, w = item.image.size + h, w = item.media.size instances = self.find_instances(segments) segments = [self.merge_segments(i, w, h, self._include_polygons) for i in instances] @@ -196,9 +196,9 @@ def transform_item(self, item): annotations = [] for ann in item.annotations: if ann.type == AnnotationType.polygon: - if not item.has_image: + if not isinstance(item.media, Image): raise Exception("Image info is required for this transform") - h, w = item.image.size + h, w = item.media.size annotations.append(self.convert_polygon(ann, h, w)) else: annotations.append(ann) @@ -217,9 +217,9 @@ def transform_item(self, item): annotations = [] for ann in item.annotations: if ann.type == AnnotationType.bbox: - if not item.has_image: + if not isinstance(item.media, Image): raise Exception("Image info is required for this transform") - h, w = item.image.size + h, w = item.media.size annotations.append(self.convert_bbox(ann, h, w)) else: annotations.append(ann) @@ -421,8 +421,8 @@ class IdFromImageName(ItemTransform, CliPlugin): """ def transform_item(self, item): - if item.has_image and item.image.path: - name = osp.splitext(osp.basename(item.image.path))[0] + if isinstance(item.media, Image) and item.media.path: + name = osp.splitext(osp.basename(item.media.path))[0] return self.wrap_item(item, id=name) else: log.debug("Can't change item id for item '%s': " @@ -820,19 +820,19 @@ def _resize_image(): return _resize_image def transform_item(self, item): - if not item.has_image: + if not isinstance(item.media, Image): raise DatumaroError("Item %s: image info is required for this " "transform" % (item.id, )) - h, w = item.image.size + h, w = item.media.size xscale = self._width / float(w) yscale = self._height / float(h) new_size = (self._height, self._width) resized_image = None - if item.image.has_data: - resized_image = self._lazy_resize_image(item.image, new_size) + if item.media.has_data: + resized_image = self._lazy_resize_image(item.media, new_size) resized_annotations = [] for ann in item.annotations: @@ -861,7 +861,7 @@ def transform_item(self, item): assert False, f"Unexpected annotation type {type(ann)}" return self.wrap_item(item, - image=resized_image, + media=resized_image, annotations=resized_annotations) class RemoveItems(ItemTransform): diff --git a/datumaro/plugins/vgg_face2_format.py b/datumaro/plugins/vgg_face2_format.py index 9df1aa61e6..69b6a5bcda 100644 --- a/datumaro/plugins/vgg_face2_format.py +++ b/datumaro/plugins/vgg_face2_format.py @@ -10,8 +10,10 @@ AnnotationType, Bbox, Label, LabelCategories, Points, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Extractor, Importer from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util.image import find_images from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -122,8 +124,11 @@ def _get_label(path): label = _get_label(item_id) if item_id not in items: + image = images.get(row['NAME_ID']) + if image: + image = Image(path=image) items[item_id] = DatasetItem(id=item_id, subset=subset, - image=images.get(row['NAME_ID'])) + media=image) annotations = items[item_id].annotations if [a for a in annotations if a.type == AnnotationType.points]: @@ -150,8 +155,11 @@ def _get_label(path): label = _get_label(item_id) if item_id not in items: + image = images.get(row['NAME_ID']) + if image: + image = Image(path=image) items[item_id] = DatasetItem(id=item_id, subset=subset, - image=images.get(row['NAME_ID'])) + media=image) annotations = items[item_id].annotations if [a for a in annotations if a.type == AnnotationType.bbox]: @@ -201,6 +209,10 @@ def _get_name_id(item_parts, label_name): else: return '/'.join([label_name, *item_parts]) + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + save_dir = self._save_dir os.makedirs(save_dir, exist_ok=True) @@ -224,7 +236,7 @@ def _get_name_id(item_parts, label_name): landmarks_table = [] for item in subset: item_parts = item.id.split('/') - if item.has_image and self._save_images: + if item.media and self._save_media: labels = set(p.label for p in item.annotations if getattr(p, 'label') is not None) if labels: diff --git a/datumaro/plugins/video_formats.py b/datumaro/plugins/video_formats.py index 163bf3533b..4757a22bc0 100644 --- a/datumaro/plugins/video_formats.py +++ b/datumaro/plugins/video_formats.py @@ -11,7 +11,7 @@ from datumaro.components.format_detection import ( FormatDetectionConfidence, FormatDetectionContext, ) -from datumaro.components.media import Video +from datumaro.components.media import Video, VideoFrame from datumaro.util.os_util import find_files # Taken from https://en.wikipedia.org/wiki/Comparison_of_video_container_formats @@ -68,7 +68,7 @@ def __init__(self, url: str, *, step: int = 1, start_frame: int = 0, end_frame: Optional[int] = None) -> None: self._subset = subset or DEFAULT_SUBSET_NAME - super().__init__(subsets=[self._subset]) + super().__init__(subsets=[self._subset], media_type=VideoFrame) assert osp.isfile(url), url @@ -80,7 +80,7 @@ def __init__(self, url: str, *, def __iter__(self): for frame in self._reader: yield DatasetItem(id=self._name_pattern % (frame.index, ), - subset=self._subset, image=frame) + subset=self._subset, media=frame) def get(self, id, subset=None): assert subset == self._subset, '%s != %s' % (subset, self._subset) diff --git a/datumaro/plugins/voc_format/converter.py b/datumaro/plugins/voc_format/converter.py index 9644cb61ab..242e223236 100644 --- a/datumaro/plugins/voc_format/converter.py +++ b/datumaro/plugins/voc_format/converter.py @@ -19,7 +19,9 @@ ) from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.util import find, str_to_bool from datumaro.util.annotation_util import make_label_id_mapping from datumaro.util.image import save_image @@ -134,6 +136,10 @@ def __init__(self, extractor, save_dir, self._patch = None def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + self.make_dirs() self.save_subsets() self.save_label_map() @@ -189,8 +195,8 @@ def save_subsets(self): try: image_filename = self._make_image_filename(item) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if item.media: self._save_image(item, osp.join(self._images_dir, image_filename)) else: @@ -241,8 +247,8 @@ def _export_annotations(self, item: DatasetItem, *, ET.SubElement(source_elem, 'annotation').text = 'Unknown' ET.SubElement(source_elem, 'image').text = 'Unknown' - if item.has_image and item.image.has_size: - h, w = item.image.size + if item.media and item.media.has_size: + h, w = item.media.size size_elem = ET.SubElement(root_elem, 'size') ET.SubElement(size_elem, 'width').text = str(w) ET.SubElement(size_elem, 'height').text = str(h) @@ -685,7 +691,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_image): + if not (status == ItemStatus.removed or not item.media): ids_to_remove[item_id] = (item, False) else: ids_to_remove.setdefault(item_id, (item, True)) diff --git a/datumaro/plugins/voc_format/extractor.py b/datumaro/plugins/voc_format/extractor.py index 3234c7b22f..75864568d1 100644 --- a/datumaro/plugins/voc_format/extractor.py +++ b/datumaro/plugins/voc_format/extractor.py @@ -103,8 +103,11 @@ def __iter__(self): for item_id in self._ctx.progress_reporter.iter(self._items, desc=f"Parsing labels in '{self._subset}'"): log.debug("Reading item '%s'" % item_id) + image = images.get(item_id) + if image: + image = Image(path=image) yield DatasetItem(id=item_id, subset=self._subset, - image=images.get(item_id), annotations=annotations.get(item_id)) + media=image, annotations=annotations.get(item_id)) def _load_annotations(self): annotations = {} @@ -168,7 +171,7 @@ def __iter__(self): image = Image(path=image, size=size) yield DatasetItem(id=item_id, subset=self._subset, - image=image, annotations=anns) + media=image, annotations=anns) except Exception as e: self._report_item_error(e, item_id=(item_id, self._subset)) @@ -292,9 +295,12 @@ def __iter__(self): desc=f"Parsing segmentation in '{self._subset}'"): log.debug("Reading item '%s'" % item_id) + image = images.get(item_id) + if image: + image = Image(path=image) + try: - yield DatasetItem(id=item_id, subset=self._subset, - image=images.get(item_id), + yield DatasetItem(id=item_id, subset=self._subset, media=image, annotations=self._load_annotations(item_id)) except Exception as e: self._report_item_error(e, item_id=(item_id, self._subset)) diff --git a/datumaro/plugins/vott_csv_format.py b/datumaro/plugins/vott_csv_format.py index 7310ef4994..a417eb286e 100644 --- a/datumaro/plugins/vott_csv_format.py +++ b/datumaro/plugins/vott_csv_format.py @@ -42,7 +42,7 @@ def _load_items(self, path): if item_id not in items: items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=Image(path=osp.join(osp.dirname(path), row['image']))) + media=Image(path=osp.join(osp.dirname(path), row['image']))) annotations = items[item_id].annotations diff --git a/datumaro/plugins/vott_json_format.py b/datumaro/plugins/vott_json_format.py index 328e23f756..1a21b6643b 100644 --- a/datumaro/plugins/vott_json_format.py +++ b/datumaro/plugins/vott_json_format.py @@ -71,7 +71,7 @@ def _load_items(self, path): items[item_id] = DatasetItem(id=item_id, subset=self._subset, attributes={'id': id}, - image=Image(path=osp.join(osp.dirname(path), + media=Image(path=osp.join(osp.dirname(path), asset.get('asset', {}).get('path'))), annotations=annotations) diff --git a/datumaro/plugins/widerface_format.py b/datumaro/plugins/widerface_format.py index c2f80f9d36..4432e5f059 100644 --- a/datumaro/plugins/widerface_format.py +++ b/datumaro/plugins/widerface_format.py @@ -10,8 +10,10 @@ AnnotationType, Bbox, Label, LabelCategories, ) from datumaro.components.converter import Converter +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DatasetItem, Importer, SourceExtractor from datumaro.components.format_detection import FormatDetectionContext +from datumaro.components.media import Image from datumaro.util import str_to_bool from datumaro.util.meta_file_util import has_meta_file, parse_meta_file @@ -104,7 +106,7 @@ def _load_items(self, path): item_id = item_id[len(item_id.split('/')[0]) + 1:] items[item_id] = DatasetItem(id=item_id, subset=self._subset, - image=image_path, annotations=annotations) + media=Image(path=image_path), annotations=annotations) try: bbox_count = int(lines[line_idx + 1]) @@ -158,6 +160,10 @@ class WiderFaceConverter(Converter): DEFAULT_IMAGE_EXT = WiderFacePath.IMAGE_EXT def apply(self): + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + save_dir = self._save_dir os.makedirs(save_dir, exist_ok=True) @@ -186,7 +192,7 @@ def apply(self): image_path = self._make_image_filename(item, subdir=WiderFacePath.IMAGES_DIR_NO_LABEL) wider_annotation += image_path + '\n' - if item.has_image and self._save_images: + if item.media and self._save_media: self._save_image(item, osp.join(save_dir, subset_dir, WiderFacePath.IMAGES_DIR, image_path)) diff --git a/datumaro/plugins/yolo_format/converter.py b/datumaro/plugins/yolo_format/converter.py index 3e726497e4..a145d93a2c 100644 --- a/datumaro/plugins/yolo_format/converter.py +++ b/datumaro/plugins/yolo_format/converter.py @@ -10,7 +10,9 @@ from datumaro.components.annotation import AnnotationType, Bbox from datumaro.components.converter import Converter from datumaro.components.dataset import ItemStatus +from datumaro.components.errors import MediaTypeError from datumaro.components.extractor import DEFAULT_SUBSET_NAME, DatasetItem +from datumaro.components.media import Image from .format import YoloPath @@ -33,6 +35,10 @@ def apply(self): extractor = self._extractor save_dir = self._save_dir + if self._extractor.media_type() and \ + not issubclass(self._extractor.media_type(), Image): + raise MediaTypeError("Media type is not an image") + os.makedirs(save_dir, exist_ok=True) if self._save_dataset_meta: @@ -65,14 +71,14 @@ def apply(self): image_paths = OrderedDict() for item in pbar.iter(subset, desc=f"Exporting '{subset_name}'"): try: - if not item.has_image or not \ - (item.image.has_data or item.image.has_size): + if not item.media or not \ + (item.media.has_data or item.media.has_size): raise Exception("Failed to export item '%s': " "item has no image info" % item.id) image_name = self._make_image_filename(item) - if self._save_images: - if item.has_image and item.image.has_data: + if self._save_media: + if item.media: self._save_image(item, osp.join(subset_dir, image_name)) else: @@ -111,7 +117,7 @@ def apply(self): f.write('backup = backup/\n') def _export_item_annotation(self, item): - height, width = item.image.size + height, width = item.media.size yolo_annotation = '' @@ -137,7 +143,7 @@ def patch(cls, dataset, patch, save_dir, **kwargs): else: item = DatasetItem(item_id, subset=subset) - if not (status == ItemStatus.removed or not item.has_image): + if not (status == ItemStatus.removed or not item.media): continue if subset == DEFAULT_SUBSET_NAME: diff --git a/datumaro/plugins/yolo_format/extractor.py b/datumaro/plugins/yolo_format/extractor.py index 88b177524c..cd4b3a63bc 100644 --- a/datumaro/plugins/yolo_format/extractor.py +++ b/datumaro/plugins/yolo_format/extractor.py @@ -136,7 +136,7 @@ def _get(self, item_id, subset_name): annotations = self._parse_annotations(anno_path, image) item = DatasetItem(id=item_id, subset=subset_name, - image=image, annotations=annotations) + media=image, annotations=annotations) subset.items[item_id] = item return item diff --git a/datumaro/util/test_utils.py b/datumaro/util/test_utils.py index a4679f6e4a..7d7475ed0a 100644 --- a/datumaro/util/test_utils.py +++ b/datumaro/util/test_utils.py @@ -1,4 +1,4 @@ -# Copyright (C) 2019-2021 Intel Corporation +# Copyright (C) 2019-2022 Intel Corporation # # SPDX-License-Identifier: MIT @@ -12,11 +12,13 @@ import tempfile import unittest import unittest.mock +import warnings from typing_extensions import Literal from datumaro.components.annotation import AnnotationType from datumaro.components.dataset import Dataset, IDataset +from datumaro.components.media import Image, PointCloud from datumaro.util import filter_dict, find from datumaro.util.os_util import rmfile, rmtree @@ -131,11 +133,14 @@ def _compare_annotations(expected, actual, ignored_attrs=None): def compare_datasets(test, expected: IDataset, actual: IDataset, ignored_attrs: Union[None, Literal['*'], Collection[str]] = None, - require_images: bool = False): + require_media: bool = False, require_images: bool = False): compare_categories(test, expected.categories(), actual.categories()) + test.assertTrue(issubclass(actual.media_type(), expected.media_type())) + test.assertEqual(sorted(expected.subsets()), sorted(actual.subsets())) test.assertEqual(len(expected), len(actual)) + for item_a in expected: item_b = find(actual, lambda x: x.id == item_a.id and \ x.subset == item_a.subset) @@ -148,10 +153,17 @@ def compare_datasets(test, expected: IDataset, actual: IDataset, elif not ignored_attrs: test.assertEqual(item_a.attributes, item_b.attributes, item_a.id) - if (require_images and item_a.has_image and item_a.image.has_data) or \ - item_a.has_image and item_a.image.has_data and \ - item_b.has_image and item_b.image.has_data: - test.assertEqual(item_a.image, item_b.image, item_a.id) + if require_images: + warnings.warn("'require_images' is deprecated and will be " + "removed in future. Use 'require_media' instead.", + DeprecationWarning, stacklevel=2) + require_media = require_media or require_images + + if require_media and item_a.media and item_b.media: + if isinstance(item_a.media, Image): + test.assertEqual(item_a.media, item_b.media, item_a.id) + elif isinstance(item_a.media, PointCloud): + test.assertEqual(item_a.media.extra_images, item_b.media.extra_images, item_a.id) test.assertEqual(len(item_a.annotations), len(item_b.annotations), item_a.id) for ann_a in item_a.annotations: @@ -166,9 +178,10 @@ def compare_datasets(test, expected: IDataset, actual: IDataset, test.fail('ann %s, candidates %s' % (ann_a, ann_b_matches)) item_b.annotations.remove(ann_b) # avoid repeats -def compare_datasets_strict(test, expected, actual): +def compare_datasets_strict(test, expected: IDataset, actual: IDataset): # Compares datasets for strong equality + test.assertEqual(expected.media_type(), actual.media_type()) test.assertEqual(expected.categories(), actual.categories()) test.assertListEqual(sorted(expected.subsets()), sorted(actual.subsets())) @@ -203,12 +216,12 @@ def compare_datasets_3d(test, expected: IDataset, actual: IDataset, elif not ignored_attrs: test.assertEqual(item_a.attributes, item_b.attributes, item_a.id) - if (require_point_cloud and item_a.has_point_cloud) or \ - (item_a.has_point_cloud and item_b.has_point_cloud): - test.assertEqual(item_a.point_cloud, item_b.point_cloud, item_a.id) + if (require_point_cloud and item_a.media) or \ + (item_a.media and item_b.media): + test.assertEqual(item_a.media.path, item_b.media.path, item_a.id) test.assertEqual( - set(img.path for img in item_a.related_images), - set(img.path for img in item_b.related_images), + set(img.path for img in item_a.media.extra_images), + set(img.path for img in item_b.media.extra_images), item_a.id) test.assertEqual(len(item_a.annotations), len(item_b.annotations)) for ann_a in item_a.annotations: diff --git a/site/content/en/docs/formats/ade20k2017.md b/site/content/en/docs/formats/ade20k2017.md index c5536c65af..79cfce3d4b 100644 --- a/site/content/en/docs/formats/ade20k2017.md +++ b/site/content/en/docs/formats/ade20k2017.md @@ -97,12 +97,12 @@ formats using CLI: ```bash datum create datum import -f ade20k2017 -datum export -f coco -o -- --save-images +datum export -f coco -o -- --save-media ``` or ``` bash datum convert -if ade20k2017 -i \ - -f coco -o -- --save-images + -f coco -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/ade20k2020.md b/site/content/en/docs/formats/ade20k2020.md index ef841cbc3d..1bc7f2de39 100644 --- a/site/content/en/docs/formats/ade20k2020.md +++ b/site/content/en/docs/formats/ade20k2020.md @@ -116,12 +116,12 @@ formats using CLI: ```bash datum create datum import -f ade20k2020 -datum export -f coco -o ./save_dir -- --save-images +datum export -f coco -o ./save_dir -- --save-media ``` or ``` bash datum convert -if ade20k2020 -i \ - -f coco -o -- --save-images + -f coco -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/align_celeba.md b/site/content/en/docs/formats/align_celeba.md index d3cf7f0fd3..60529344dc 100644 --- a/site/content/en/docs/formats/align_celeba.md +++ b/site/content/en/docs/formats/align_celeba.md @@ -84,12 +84,12 @@ formats using CLI: ```bash datum create datum import -f align_celeba -datum export -f imagenet_txt -o ./save_dir -- --save-images +datum export -f imagenet_txt -o ./save_dir -- --save-media ``` or ``` bash datum convert -if align_celeba -i \ - -f imagenet_txt -o -- --save-images + -f imagenet_txt -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/celeba.md b/site/content/en/docs/formats/celeba.md index ffab1d23d6..a8310eb15d 100644 --- a/site/content/en/docs/formats/celeba.md +++ b/site/content/en/docs/formats/celeba.md @@ -86,12 +86,12 @@ formats using CLI: ```bash datum create datum import -f celeba -datum export -f imagenet_txt -o ./save_dir -- --save-images +datum export -f imagenet_txt -o ./save_dir -- --save-media ``` or ``` bash datum convert -if celeba -i \ - -f imagenet_txt -o -- --save-images + -f imagenet_txt -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/cifar.md b/site/content/en/docs/formats/cifar.md index 20eccdb292..0cf7938d19 100644 --- a/site/content/en/docs/formats/cifar.md +++ b/site/content/en/docs/formats/cifar.md @@ -121,7 +121,7 @@ datum export -f imagenet -o or ``` bash datum convert -if cifar -i \ - -f imagenet -o -- --save-images + -f imagenet -o -- --save-media ``` Or, using Python API: @@ -130,7 +130,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'cifar') -dataset.export('save_dir', 'imagenet', save_images=True) +dataset.export('save_dir', 'imagenet', save_media=True) ``` ## Export to CIFAR @@ -140,17 +140,17 @@ There are several ways to convert a dataset to CIFAR format: ``` bash # export dataset into CIFAR format from existing project datum export -p -f cifar -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to CIFAR format from other format datum convert -if imagenet -i \ - -f cifar -o -- --save-images + -f cifar -o -- --save-media ``` Extra options for exporting to CIFAR format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext ` allow to specify image extension for exporting the dataset (by default `.png`) diff --git a/site/content/en/docs/formats/cityscapes.md b/site/content/en/docs/formats/cityscapes.md index 9940846645..062dd0dae7 100644 --- a/site/content/en/docs/formats/cityscapes.md +++ b/site/content/en/docs/formats/cityscapes.md @@ -101,7 +101,7 @@ datum export -f voc -o or ``` bash datum convert -if cityscapes -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: @@ -110,7 +110,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'cityscapes') -dataset.export('save_dir', 'voc', save_images=True) +dataset.export('save_dir', 'voc', save_media=True) ``` ## Export to Cityscapes @@ -120,16 +120,16 @@ There are several ways to convert a dataset to Cityscapes format: ``` bash # export dataset into Cityscapes format from existing project datum export -p -f cityscapes -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to Cityscapes format from other format datum convert -if voc -i \ - -f cityscapes -o -- --save-images + -f cityscapes -o -- --save-media ``` Extra options for exporting to Cityscapes format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original or use `.png`, if none) @@ -165,7 +165,7 @@ particular problems with a Cityscapes dataset: datum create -o project datum import -p project -f cityscapes ./Cityscapes/ datum stats -p project -datum export -p project -o dataset/ -f voc -- --save-images +datum export -p project -o dataset/ -f voc -- --save-media ``` ### Example 2. Create a custom Cityscapes-like dataset diff --git a/site/content/en/docs/formats/coco.md b/site/content/en/docs/formats/coco.md index 0d78276681..606d0bbd12 100644 --- a/site/content/en/docs/formats/coco.md +++ b/site/content/en/docs/formats/coco.md @@ -176,7 +176,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'coco') -dataset.export('save_dir', 'voc', save_images=True) +dataset.export('save_dir', 'voc', save_media=True) ``` ## Export to COCO @@ -186,16 +186,16 @@ There are several ways to convert a dataset to COCO format: ``` bash # export dataset into COCO format from existing project datum export -p -f coco -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to COCO format from other format datum convert -if voc -i \ - -f coco -o -- --save-images + -f coco -o -- --save-media ``` Extra options for exporting to COCO format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original or use `.jpg`, if none) @@ -250,7 +250,7 @@ particular problems with a COCO dataset: datum create -o project datum import -p project -f coco_panoptic ./COCO/annotations/panoptic_val2017.json datum stats -p project -datum export -p project -f voc -- --save-images +datum export -p project -f voc -- --save-media ``` ### Example 2. How to create custom COCO-like dataset diff --git a/site/content/en/docs/formats/icdar.md b/site/content/en/docs/formats/icdar.md index d3bb2137e9..0bb04d86e5 100644 --- a/site/content/en/docs/formats/icdar.md +++ b/site/content/en/docs/formats/icdar.md @@ -110,13 +110,13 @@ Datumaro can convert ICDAR dataset into any other format ``` bash # converting ICDAR text segmentation dataset into the VOC with `convert` command datum convert -if icdar_text_segmentation -i source_dataset \ - -f voc -o export_dir -- --save-images + -f voc -o export_dir -- --save-media ``` ``` bash # converting ICDAR text localization into the LabelMe through Datumaro project datum create datum import -f icdar_text_localization source_dataset -datum export -f label_me -o ./export_dir -- --save-images +datum export -f label_me -o ./export_dir -- --save-media ``` > Note: some formats have extra export options. For particular format see the > [docs](/docs/formats/) to get information about it. @@ -128,7 +128,7 @@ attributes, described in previous section. > masks without attribute `color` then it will be generated automatically. Available extra export options for ICDAR dataset formats: -- `--save-images` allow to export dataset with saving images. +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original) diff --git a/site/content/en/docs/formats/image_zip.md b/site/content/en/docs/formats/image_zip.md index ac6dc49b92..27d14ca024 100644 --- a/site/content/en/docs/formats/image_zip.md +++ b/site/content/en/docs/formats/image_zip.md @@ -60,7 +60,7 @@ For example: ```bash datum create -o project datum import -p project -f image_zip ./images.zip -datum export -p project -f coco -o ./new_dir -- --save-images +datum export -p project -f coco -o ./new_dir -- --save-media ``` Or, using Python API: @@ -69,7 +69,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'image_zip') -dataset.export('save_dir', 'coco', save_images=True) +dataset.export('save_dir', 'coco', save_media=True) ``` ## Export an unannotated dataset to a zip archive @@ -82,7 +82,7 @@ datum export -p project -f image_zip -- --name voc_images.zip ``` Extra options for exporting to image_zip format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (default: `False`) - `--image-ext ` allow to specify image extension for exporting dataset (default: use original or `.jpg`, if none) diff --git a/site/content/en/docs/formats/imagenet.md b/site/content/en/docs/formats/imagenet.md index 3129857e9e..cedc08c0ae 100644 --- a/site/content/en/docs/formats/imagenet.md +++ b/site/content/en/docs/formats/imagenet.md @@ -100,7 +100,7 @@ that supports `Label` annotation objects. ``` # Using `convert` command datum convert -if imagenet -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media # Using Datumaro project datum create @@ -115,7 +115,7 @@ import datumaro as dm imagenet_dataset = dm.Dataset.import_from('', format='vgg_face2', save_images=True) +imagenet_dataset.export('', format='vgg_face2', save_media=True) ``` > Note: some formats have extra export options. For particular format see the @@ -129,7 +129,7 @@ dataset into the ImagetNet format, you can use Datumaro for it: ``` # Using convert command datum convert -if open_images -i \ - -f imagenet_txt -o -- --save-images --save-dataset-meta + -f imagenet_txt -o -- --save-media --save-dataset-meta # Using Datumaro project datum create @@ -138,7 +138,7 @@ datum export -f imagenet -o ``` Extra options for exporting to ImageNet formats: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext ` allow to specify image extension for exporting the dataset (by default `.png`) diff --git a/site/content/en/docs/formats/kitti.md b/site/content/en/docs/formats/kitti.md index c13a9bd9e5..53bef9b8aa 100644 --- a/site/content/en/docs/formats/kitti.md +++ b/site/content/en/docs/formats/kitti.md @@ -143,7 +143,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'kitti') -dataset.export('save_dir', 'cityscapes', save_images=True) +dataset.export('save_dir', 'cityscapes', save_media=True) ``` ## Export to KITTI @@ -153,16 +153,16 @@ There are several ways to convert a dataset to KITTI format: ``` bash # export dataset into KITTI format from existing project datum export -p -f kitti -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to KITTI format from other format datum convert -if cityscapes -i \ - -f kitti -o -- --save-images + -f kitti -o -- --save-media ``` Extra options for exporting to KITTI format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original or use `.png`, if none) @@ -209,7 +209,7 @@ particular problems with KITTI dataset: datum create -o project datum import -p project -f kitti ./KITTI/ datum stats -p project -datum export -p project -f cityscapes -- --save-images +datum export -p project -f cityscapes -- --save-media ``` ### Example 2. How to create a custom KITTI-like dataset diff --git a/site/content/en/docs/formats/kitti_raw.md b/site/content/en/docs/formats/kitti_raw.md index 667723766c..32fcdce2e9 100644 --- a/site/content/en/docs/formats/kitti_raw.md +++ b/site/content/en/docs/formats/kitti_raw.md @@ -112,7 +112,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'kitti_raw') -dataset.export('save_dir', 'sly_pointcloud', save_images=True) +dataset.export('save_dir', 'sly_pointcloud', save_media=True) ``` ## Export to KITTI Raw @@ -122,16 +122,16 @@ There are several ways to convert a dataset to KITTI Raw format: ``` bash # export dataset into KITTI Raw format from existing project datum export -p -f kitti_raw -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to KITTI Raw format from other format datum convert -if sly_pointcloud -i \ - -f kitti_raw -o -- --save-images --reindex + -f kitti_raw -o -- --save-media --reindex ``` Extra options for exporting to KITTI Raw format: -- `--save-images` allow to export dataset with saving images. This will +- `--save-media` allow to export dataset with saving media files. This will include point clouds and related images (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original or use `.png`, if none) @@ -155,7 +155,7 @@ datum stats -p project ``` bash datum convert -if sly_pointcloud -i ../sly_pcd/ \ - -f kitti_raw -o my_kitti/ -- --save-images --allow-attrs + -f kitti_raw -o my_kitti/ -- --save-media --allow-attrs ``` ### Example 3. Create a custom dataset @@ -179,7 +179,7 @@ dataset = dm.Dataset.from_iterable([ ), ], categories=['cat', 'dog']) -dataset.export('my_dataset/', format='kitti_raw', save_images=True) +dataset.export('my_dataset/', format='kitti_raw', save_media=True) ``` Examples of using this format from the code can be found in diff --git a/site/content/en/docs/formats/lfw.md b/site/content/en/docs/formats/lfw.md index 19fee6eb3c..993d0698de 100644 --- a/site/content/en/docs/formats/lfw.md +++ b/site/content/en/docs/formats/lfw.md @@ -88,7 +88,7 @@ There is few ways to convert LFW dataset into other format: # Converting to ImageNet with `convert` command: datum convert -if lfw -i ./lfw_dataset \ - -f imagenet -o ./output_dir -- --save-images + -f imagenet -o ./output_dir -- --save-media # Converting to VggFace2 through the Datumaro project: @@ -114,11 +114,11 @@ datum convert -if vgg_face2 -i ./voc_dataset \ # Export dataaset to the LFW format through the Datumaro project: datum create datum import -f voc_classification ../vgg_dataset -datum export -f lfw -o ./output_dir -- --save-images --image-ext png +datum export -f lfw -o ./output_dir -- --save-media --image-ext png ``` Available extra export options for LFW dataset format: -- `--save-images` allow to export dataset with saving images. +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original) diff --git a/site/content/en/docs/formats/market1501.md b/site/content/en/docs/formats/market1501.md index caae432942..252cc17eeb 100644 --- a/site/content/en/docs/formats/market1501.md +++ b/site/content/en/docs/formats/market1501.md @@ -89,7 +89,7 @@ datum convert -if mars -i ./mars_dataset \ # Export dataaset to the Market-1501 format through the Datumaro project: datum create datum add -f mars ../mars -datum export -f market1501 -o ./output_dir -- --save-images --image-ext png +datum export -f market1501 -o ./output_dir -- --save-media --image-ext png ``` > Note: if your dataset contains only person_id attributes Datumaro @@ -97,7 +97,7 @@ datum export -f market1501 -o ./output_dir -- --save-images --image-ext png > and increment frame_id for collisions. Available extra export options for Market-1501 dataset format: -- `--save-images` allow to export dataset with saving images. +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original) diff --git a/site/content/en/docs/formats/mnist.md b/site/content/en/docs/formats/mnist.md index 3950ad106b..690e9f4952 100644 --- a/site/content/en/docs/formats/mnist.md +++ b/site/content/en/docs/formats/mnist.md @@ -133,7 +133,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'mnist') -dataset.export('save_dir', 'imagenet', save_images=True) +dataset.export('save_dir', 'imagenet', save_media=True) ``` These steps also will work for MNIST in CSV, if you use `mnist_csv` @@ -146,16 +146,16 @@ There are several ways to convert a dataset to MNIST format: ``` bash # export dataset into MNIST format from existing project datum export -p -f mnist -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to MNIST format from other format datum convert -if imagenet -i \ - -f mnist -o -- --save-images + -f mnist -o -- --save-media ``` Extra options for exporting to MNIST format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext ` allow to specify image extension for exporting dataset (by default `.png`) diff --git a/site/content/en/docs/formats/mpii.md b/site/content/en/docs/formats/mpii.md index 144cb758a7..c4b18a9924 100644 --- a/site/content/en/docs/formats/mpii.md +++ b/site/content/en/docs/formats/mpii.md @@ -62,12 +62,12 @@ to other dataset formats using CLI: ```bash datum create datum import -f mpii -datum export -f voc -o ./save_dir -- --save-images +datum export -f voc -o ./save_dir -- --save-media ``` or ``` bash datum convert -if mpii -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/mpii_json.md b/site/content/en/docs/formats/mpii_json.md index cd3354327d..234485ef91 100644 --- a/site/content/en/docs/formats/mpii_json.md +++ b/site/content/en/docs/formats/mpii_json.md @@ -65,12 +65,12 @@ to other dataset formats using CLI: ```bash datum create datum import -f mpii_json -datum export -f voc -o ./save_dir -- --save-images +datum export -f voc -o ./save_dir -- --save-media ``` or ``` bash datum convert -if mpii_json -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/open_images.md b/site/content/en/docs/formats/open_images.md index 2cf690a6c2..2b2f3408ce 100644 --- a/site/content/en/docs/formats/open_images.md +++ b/site/content/en/docs/formats/open_images.md @@ -253,7 +253,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'open_images') -dataset.export('save_dir', 'cvat', save_images=True) +dataset.export('save_dir', 'cvat', save_media=True) ``` ## Export to Open Images @@ -263,17 +263,17 @@ There are several ways to convert an existing dataset to the Open Images format: ``` bash # export dataset into Open Images format from existing project datum export -p -f open_images -o \ - -- --save_images + -- --save_media ``` ``` bash # convert a dataset in another format to the Open Images format datum convert -if imagenet -i \ -f open_images -o \ - -- --save-images + -- --save-media ``` Extra options for exporting to the Open Images format: -- `--save-images` - save image files when exporting the dataset +- `--save-media` - save media files when exporting the dataset (by default, `False`) - `--image-ext IMAGE_EXT` - save image files with the specified extension when exporting the dataset (by default, uses the original extension @@ -297,7 +297,7 @@ particular problems with the Open Images dataset: datum create -o project datum import -p project -f open_images ./open-images-dataset/ datum stats -p project -datum export -p project -f cvat -- --save-images +datum export -p project -f cvat -- --save-media ``` ### Example 2. Create a custom OID-like dataset diff --git a/site/content/en/docs/formats/pascal_voc.md b/site/content/en/docs/formats/pascal_voc.md index b39058b5d4..ca9540b774 100644 --- a/site/content/en/docs/formats/pascal_voc.md +++ b/site/content/en/docs/formats/pascal_voc.md @@ -180,7 +180,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'voc') -dataset.export('save_dir', 'coco', save_images=True) +dataset.export('save_dir', 'coco', save_media=True) ``` ## Export to Pascal VOC @@ -195,11 +195,11 @@ datum export -p -f voc -o -- --tasks classificati # converting to Pascal VOC format from other format datum convert -if imagenet -i \ -f voc -o \ - -- --label_map voc --save-images + -- --label_map voc --save-media ``` Extra options for exporting to Pascal VOC format: -- `--save-images` - allow to export dataset with saving images +- `--save-media` - allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` - allow to specify image extension for exporting dataset (by default use original or `.jpg` if none) @@ -257,7 +257,7 @@ datum stats -p project # check statisctics.json -> repeated images datum transform -p project -t ndr -- -w trainval -k 2500 datum filter -p project -e '/item[subset="trainval"]' datum transform -p project -t random_split -- -s train:.8 -s val:.2 -datum export -p project -f voc -- --label-map voc --save-images +datum export -p project -f voc -- --label-map voc --save-media ``` ### Example 2. How to create a custom dataset @@ -309,7 +309,7 @@ def only_jumping(item): train_dataset.select(only_jumping) -train_dataset.export('./jumping_label_me', format='label_me', save_images=True) +train_dataset.export('./jumping_label_me', format='label_me', save_media=True) ``` ### Example 4. Get information about items in Pascal VOC 2012 dataset for segmentation task: diff --git a/site/content/en/docs/formats/sly_pointcloud.md b/site/content/en/docs/formats/sly_pointcloud.md index 1a23731180..a86f74c753 100644 --- a/site/content/en/docs/formats/sly_pointcloud.md +++ b/site/content/en/docs/formats/sly_pointcloud.md @@ -107,7 +107,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'sly_pointcloud') -dataset.export('save_dir', 'kitti_raw', save_images=True) +dataset.export('save_dir', 'kitti_raw', save_media=True) ``` ## Export to Supervisely Point Cloud @@ -117,16 +117,16 @@ There are several ways to convert a dataset to Supervisely Point Cloud format: ``` bash # export dataset into Supervisely Point Cloud format from existing project datum export -p -f sly_pointcloud -o \ - -- --save-images + -- --save-media ``` ``` bash # converting to Supervisely Point Cloud format from other format datum convert -if kitti_raw -i \ - -f sly_pointcloud -o -- --save-images + -f sly_pointcloud -o -- --save-media ``` Extra options for exporting in Supervisely Point Cloud format: -- `--save-images` allow to export dataset with saving images. This will +- `--save-media` allow to export dataset with saving media files. This will include point clouds and related images (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original or use `.png`, if none) @@ -149,7 +149,7 @@ datum stats -p project ``` bash datum convert -if sly_pointcloud -i ../sly_pcd/ \ - -f kitti_raw -o my_kitti/ -- --save-images --reindex --allow-attrs + -f kitti_raw -o my_kitti/ -- --save-media --reindex --allow-attrs ``` ### Example 3. Create a custom dataset @@ -183,7 +183,7 @@ dataset = dm.Dataset.from_iterable([ ), ], categories=['cat', 'dog']) -dataset.export('my_dataset/', format='sly_pointcloud', save_images=True, +dataset.export('my_dataset/', format='sly_pointcloud', save_media=True, allow_undeclared_attrs=True) ``` diff --git a/site/content/en/docs/formats/synthia.md b/site/content/en/docs/formats/synthia.md index a7b79dd900..5434700043 100644 --- a/site/content/en/docs/formats/synthia.md +++ b/site/content/en/docs/formats/synthia.md @@ -112,12 +112,12 @@ formats using CLI: ```bash datum create datum import -f synthia -datum export -f voc -o -- --save-images +datum export -f voc -o -- --save-media ``` or ``` bash datum convert -if synthia -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/vgg_face2.md b/site/content/en/docs/formats/vgg_face2.md index b7b64126dd..4e5de8277f 100644 --- a/site/content/en/docs/formats/vgg_face2.md +++ b/site/content/en/docs/formats/vgg_face2.md @@ -101,7 +101,7 @@ import datumaro as dm vgg_face2_dataset = dm.Dataset.import_from('', format='open_images', save_images=True) +vgg_face2_dataset.export('', format='open_images', save_media=True) ``` > Note: some formats have extra export options. For particular format see the @@ -122,14 +122,14 @@ datum convert -if wider_face -i \ # Using Datumaro project datum create datum import -f wider_face -datum export -f vgg_face2 -o -- --save-images --image-ext '.png' +datum export -f vgg_face2 -o -- --save-media --image-ext '.png' ``` > Note: `vgg_face2` format supports only one `Bbox` per image Extra options for exporting to Vgg Face2 format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext ` allow to specify image extension for exporting the dataset (by default `.png`) diff --git a/site/content/en/docs/formats/vott_csv.md b/site/content/en/docs/formats/vott_csv.md index 737c78c71a..d3cc7ec324 100644 --- a/site/content/en/docs/formats/vott_csv.md +++ b/site/content/en/docs/formats/vott_csv.md @@ -62,12 +62,12 @@ formats using CLI: ```bash datum create datum import -f vott_csv -datum export -f voc -o ./save_dir -- --save-images +datum export -f voc -o ./save_dir -- --save-media ``` or ``` bash datum convert -if vott_csv -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/vott_json.md b/site/content/en/docs/formats/vott_json.md index 82c5429289..dbca77ddc5 100644 --- a/site/content/en/docs/formats/vott_json.md +++ b/site/content/en/docs/formats/vott_json.md @@ -62,12 +62,12 @@ formats using CLI: ```bash datum create datum import -f vott_json -datum export -f voc -o ./save_dir -- --save-images +datum export -f voc -o ./save_dir -- --save-media ``` or ``` bash datum convert -if vott_json -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media ``` Or, using Python API: diff --git a/site/content/en/docs/formats/wider_face.md b/site/content/en/docs/formats/wider_face.md index 1cf4709daf..627d1b2b76 100644 --- a/site/content/en/docs/formats/wider_face.md +++ b/site/content/en/docs/formats/wider_face.md @@ -86,12 +86,12 @@ Few ways to export WIDER Face dataset using CLI: ``` # Using `convert` command datum convert -if wider_face -i \ - -f voc -o -- --save-images + -f voc -o -- --save-media # Through the Datumaro project datum create datum import -f wider_face -datum export -f voc -o -- -save-images +datum export -f voc -o -- -save-media ``` Export WIDER Face dataset using Python API: @@ -103,7 +103,7 @@ dataset = dm.Dataset.import_from(' Note: some formats have extra export options. For particular format see the @@ -120,11 +120,11 @@ into the WIDER Face format: ``` datum create datum import -f voc_detection -datum export -f wider_face -o -- --save-images --image-ext='.png' +datum export -f wider_face -o -- --save-media --image-ext='.png' ``` Available extra export options for WIDER Face dataset format: -- `--save-images` allow to export dataset with saving images. +- `--save-media` allow to export dataset with saving media files (by default `False`) - `--image-ext IMAGE_EXT` allow to specify image extension for exporting dataset (by default - keep original) diff --git a/site/content/en/docs/formats/yolo.md b/site/content/en/docs/formats/yolo.md index 2ee2fc98cd..e5f8096406 100644 --- a/site/content/en/docs/formats/yolo.md +++ b/site/content/en/docs/formats/yolo.md @@ -126,7 +126,7 @@ Or, using Python API: import datumaro as dm dataset = dm.Dataset.import_from('', 'yolo') -dataset.export('save_dir', 'coco_instances', save_images=True) +dataset.export('save_dir', 'coco_instances', save_media=True) ``` ## Export to YOLO format @@ -139,11 +139,11 @@ Example: ```bash datum create datum import -f coco_instances -datum export -f yolo -o -- --save-images +datum export -f yolo -o -- --save-media ``` Extra options for exporting to YOLO format: -- `--save-images` allow to export dataset with saving images +- `--save-media` allow to export dataset with saving media files (default: `False`) - `--image-ext ` allow to specify image extension for exporting dataset (default: use original or `.jpg`, if none) @@ -157,7 +157,7 @@ datum create -o project datum import -p project -f voc ./VOC2012 datum filter -p project -e '/item[subset="train" or subset="val"]' datum transform -p project -t map_subsets -- -s train:train -s val:valid -datum export -p project -f yolo -- --save-images +datum export -p project -f yolo -- --save-media ``` ### Example 2. Remove a class from YOLO dataset @@ -192,7 +192,7 @@ dataset = dm.Dataset.from_iterable([ ) ], categories=['house', 'bridge', 'crosswalk', 'traffic_light']) -dataset.export('../yolo_dataset', format='yolo', save_images=True) +dataset.export('../yolo_dataset', format='yolo', save_media=True) ``` ### Example 4. Get information about objects on each image diff --git a/tests/cli/test_diff.py b/tests/cli/test_diff.py index ea87b0e23f..adec2dcf3b 100644 --- a/tests/cli/test_diff.py +++ b/tests/cli/test_diff.py @@ -30,7 +30,8 @@ def test_can_compare_projects(self): # just a smoke test point_categories1.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), @@ -62,7 +63,7 @@ def test_can_compare_projects(self): # just a smoke test attributes={'a1': 5, 'a2': '42'}), DatasetItem(id=42), - DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), + DatasetItem(id=43, media=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories1, AnnotationType.mask: mask_categories1, @@ -78,7 +79,8 @@ def test_can_compare_projects(self): # just a smoke test point_categories2.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), @@ -110,7 +112,7 @@ def test_can_compare_projects(self): # just a smoke test attributes={'a1': 5, 'a2': '42'}), DatasetItem(id=42), - DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), + DatasetItem(id=43, media=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories2, AnnotationType.mask: mask_categories2, @@ -128,14 +130,16 @@ def test_can_compare_projects(self): # just a smoke test @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_run_distance_diff(self): dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0), ]), ], categories=['a', 'b']) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1), Bbox(5, 6, 7, 8, label=2), @@ -146,8 +150,8 @@ def test_can_run_distance_diff(self): dataset1_url = osp.join(test_dir, 'dataset1') dataset2_url = osp.join(test_dir, 'dataset2') - dataset1.export(dataset1_url, 'coco', save_images=True) - dataset2.export(dataset2_url, 'voc', save_images=True) + dataset1.export(dataset1_url, 'coco', save_media=True) + dataset2.export(dataset2_url, 'voc', save_media=True) result_dir = osp.join(test_dir, 'cmp_result') run(self, 'diff', dataset1_url + ':coco', dataset2_url + ':voc', @@ -159,14 +163,16 @@ def test_can_run_distance_diff(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_run_equality_diff(self): dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0), ]), ], categories=['a', 'b']) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1), Bbox(5, 6, 7, 8, label=2), @@ -177,8 +183,8 @@ def test_can_run_equality_diff(self): dataset1_url = osp.join(test_dir, 'dataset1') dataset2_url = osp.join(test_dir, 'dataset2') - dataset1.export(dataset1_url, 'coco', save_images=True) - dataset2.export(dataset2_url, 'voc', save_images=True) + dataset1.export(dataset1_url, 'coco', save_media=True) + dataset2.export(dataset2_url, 'voc', save_media=True) result_dir = osp.join(test_dir, 'cmp_result') run(self, 'diff', dataset1_url + ':coco', dataset2_url + ':voc', diff --git a/tests/cli/test_download.py b/tests/cli/test_download.py index f7c5211de0..5e4094036e 100644 --- a/tests/cli/test_download.py +++ b/tests/cli/test_download.py @@ -21,11 +21,11 @@ def test_download(self): run(self, 'download', '-i', 'tfds:mnist', '-o', test_dir, - '--', '--save-images') + '--', '--save-media') actual_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_download_custom_format(self): @@ -34,11 +34,11 @@ def test_download_custom_format(self): run(self, 'download', '-i', 'tfds:mnist', '-f', 'datumaro', '-o', test_dir, - '--', '--save-images') + '--', '--save-media') actual_dataset = Dataset.load(test_dir) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_download_fails_on_existing_dir_without_overwrite(self): @@ -58,4 +58,4 @@ def test_download_works_on_existing_dir_without_overwrite(self): run(self, 'download', '-i', 'tfds:mnist', '-f', 'datumaro', '-o', test_dir, - '--overwrite', '--', '--save-images') + '--overwrite', '--', '--save-media') diff --git a/tests/cli/test_filter.py b/tests/cli/test_filter.py index 91ee40916a..f64459dec7 100644 --- a/tests/cli/test_filter.py +++ b/tests/cli/test_filter.py @@ -49,7 +49,7 @@ def test_filter_fails_on_inplace_update_of_stage(self): dataset = Dataset.from_iterable([ DatasetItem(id=1, annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - dataset.export(dataset_url, 'coco', save_images=True) + dataset.export(dataset_url, 'coco', save_media=True) project_dir = osp.join(test_dir, 'proj') with Project.init(project_dir) as project: diff --git a/tests/cli/test_image_zip_format.py b/tests/cli/test_image_zip_format.py index ca64cd8ab3..6b73226757 100644 --- a/tests/cli/test_image_zip_format.py +++ b/tests/cli/test_image_zip_format.py @@ -6,6 +6,7 @@ import numpy as np from datumaro.components.dataset import Dataset, DatasetItem +from datumaro.components.media import Image from datumaro.util.test_utils import TestDir, compare_datasets from datumaro.util.test_utils import run_datum as run @@ -23,8 +24,8 @@ class ImageZipIntegrationScenarios(TestCase): @mark_requirement(Requirements.DATUM_267) def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((5, 5, 3))), - DatasetItem(id='2', image=np.ones((2, 8, 3))) + DatasetItem(id='1', media=Image(data=np.ones((5, 5, 3)))), + DatasetItem(id='2', media=Image(data=np.ones((2, 8, 3)))) ]) with TestDir() as test_dir: @@ -67,8 +68,8 @@ def test_can_export_zip_images_from_coco_dataset(self): @mark_requirement(Requirements.DATUM_267) def test_can_change_extension_for_images_in_zip(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((5, 5, 3))), - DatasetItem(id='2', image=np.ones((2, 8, 3))) + DatasetItem(id='1', media=Image(data=np.ones((5, 5, 3)))), + DatasetItem(id='2', media=Image(data=np.ones((2, 8, 3)))) ]) with TestDir() as test_dir: diff --git a/tests/cli/test_kitti_raw_format.py b/tests/cli/test_kitti_raw_format.py index 135832e06c..d349d79c2e 100644 --- a/tests/cli/test_kitti_raw_format.py +++ b/tests/cli/test_kitti_raw_format.py @@ -6,6 +6,7 @@ ) from datumaro.components.dataset import Dataset from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image, PointCloud from datumaro.util.test_utils import TestDir, compare_datasets_3d from datumaro.util.test_utils import run_datum as run @@ -35,11 +36,11 @@ def test_can_convert_to_kitti_raw(self): label=0, attributes={'occluded': False, 'track_id': 2}) ], - point_cloud=osp.join(export_dir, 'ds0', 'pointcloud', - '0000000000.pcd'), - related_images=[osp.join(export_dir, 'ds0', - 'related_images', '0000000000_pcd', '0000000000.png') - ], + media=PointCloud(osp.join(export_dir, 'ds0', 'pointcloud', + '0000000000.pcd'), + extra_images=[Image(path=osp.join(export_dir, 'ds0', + 'related_images', '0000000000_pcd', '0000000000.png')) + ]), attributes={'frame': 0, 'description': ''} ), @@ -51,11 +52,11 @@ def test_can_convert_to_kitti_raw(self): label=0, attributes={'occluded': True, 'track_id': 2}) ], - point_cloud=osp.join(export_dir, 'ds0', 'pointcloud', - '0000000001.pcd'), - related_images=[osp.join(export_dir, 'ds0', - 'related_images', '0000000001_pcd', '0000000001.png') - ], + media=PointCloud(osp.join(export_dir, 'ds0', 'pointcloud', + '0000000001.pcd'), + extra_images=[Image(path=osp.join(export_dir, 'ds0', + 'related_images', '0000000001_pcd', '0000000001.png')) + ]), attributes={'frame': 1, 'description': ''} ), @@ -66,14 +67,14 @@ def test_can_convert_to_kitti_raw(self): label=1, attributes={'occluded': False, 'track_id': 3}) ], - point_cloud=osp.join(export_dir, 'ds0', 'pointcloud', - '0000000002.pcd'), - related_images=[osp.join(export_dir, 'ds0', - 'related_images', '0000000002_pcd', '0000000002.png') - ], + media=PointCloud(osp.join(export_dir, 'ds0', 'pointcloud', + '0000000002.pcd'), + extra_images=[Image(path=osp.join(export_dir, 'ds0', + 'related_images', '0000000002_pcd', '0000000002.png')) + ]), attributes={'frame': 2, 'description': ''} ), - ], categories={AnnotationType.label: expected_label_cat}) + ], categories={AnnotationType.label: expected_label_cat}, media_type=PointCloud) run(self, 'convert', '-if', 'kitti_raw', '-i', DUMMY_DATASET_DIR, diff --git a/tests/cli/test_merge.py b/tests/cli/test_merge.py index 5e88dd5317..9f436763ce 100644 --- a/tests/cli/test_merge.py +++ b/tests/cli/test_merge.py @@ -7,6 +7,7 @@ AnnotationType, Bbox, LabelCategories, MaskCategories, ) from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.components.project import Dataset, Project from datumaro.util.test_utils import TestDir, compare_datasets from datumaro.util.test_utils import run_datum as run @@ -19,14 +20,16 @@ class MergeTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_run_self_merge(self): dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 3, label=0), ]), ], categories=['a', 'b']) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1), Bbox(5, 6, 2, 3, label=2), @@ -34,7 +37,8 @@ def test_can_run_self_merge(self): ], categories=['a', 'b', 'c']) expected = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=2, id=1, group=1, attributes={'score': 0.5, 'occluded': False, @@ -55,8 +59,8 @@ def test_can_run_self_merge(self): dataset1_url = osp.join(test_dir, 'dataset1') dataset2_url = osp.join(test_dir, 'dataset2') - dataset1.export(dataset1_url, 'coco', save_images=True) - dataset2.export(dataset2_url, 'voc', save_images=True) + dataset1.export(dataset1_url, 'coco', save_media=True) + dataset2.export(dataset2_url, 'voc', save_media=True) proj_dir = osp.join(test_dir, 'proj') with Project.init(proj_dir) as project: @@ -67,19 +71,21 @@ def test_can_run_self_merge(self): dataset1_url + ':coco') compare_datasets(self, expected, Dataset.load(result_dir), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_run_multimerge(self): dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 3, label=0), ]), ], categories=['a', 'b']) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1), Bbox(5, 6, 2, 3, label=2), @@ -87,7 +93,8 @@ def test_can_run_multimerge(self): ], categories=['a', 'b', 'c']) expected = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=2, id=1, group=1, attributes={'score': 0.5, 'occluded': False, @@ -108,27 +115,29 @@ def test_can_run_multimerge(self): dataset1_url = osp.join(test_dir, 'dataset1') dataset2_url = osp.join(test_dir, 'dataset2') - dataset1.export(dataset1_url, 'coco', save_images=True) - dataset2.export(dataset2_url, 'voc', save_images=True) + dataset1.export(dataset1_url, 'coco', save_media=True) + dataset2.export(dataset2_url, 'voc', save_media=True) result_dir = osp.join(test_dir, 'result') run(self, 'merge', '-o', result_dir, dataset2_url + ':voc', dataset1_url + ':coco') compare_datasets(self, expected, Dataset.load(result_dir), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_542) def test_can_save_in_another_format(self): dataset1 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 3, label=0), ]), ], categories=['a', 'b']) dataset2 = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1), Bbox(5, 6, 2, 3, label=2), @@ -136,7 +145,8 @@ def test_can_save_in_another_format(self): ], categories=['a', 'b', 'c']) expected = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=2), Bbox(5, 6, 2, 3, label=3), @@ -148,14 +158,14 @@ def test_can_save_in_another_format(self): dataset1_url = osp.join(test_dir, 'dataset1') dataset2_url = osp.join(test_dir, 'dataset2') - dataset1.export(dataset1_url, 'coco', save_images=True) - dataset2.export(dataset2_url, 'voc', save_images=True) + dataset1.export(dataset1_url, 'coco', save_media=True) + dataset2.export(dataset2_url, 'voc', save_media=True) result_dir = osp.join(test_dir, 'result') run(self, 'merge', '-o', result_dir, '-f', 'yolo', dataset2_url + ':voc', dataset1_url + ':coco', - '--', '--save-images') + '--', '--save-media') compare_datasets(self, expected, Dataset.import_from(result_dir, 'yolo'), - require_images=True) + require_media=True) diff --git a/tests/cli/test_patch.py b/tests/cli/test_patch.py index b0150196ae..ea2e5fc47b 100644 --- a/tests/cli/test_patch.py +++ b/tests/cli/test_patch.py @@ -6,6 +6,7 @@ from datumaro.components.annotation import Bbox from datumaro.components.errors import ReadonlyDatasetError from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.components.project import Dataset, Project from datumaro.util.test_utils import TestDir, compare_datasets from datumaro.util.test_utils import run_datum as run @@ -18,13 +19,14 @@ class PatchTest(TestCase): def test_can_run_patch(self): dataset = Dataset.from_iterable([ # Must be overridden - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 3, label=0), ]), # Must be kept - DatasetItem(id=1, image=np.ones((5, 4, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), @@ -32,7 +34,8 @@ def test_can_run_patch(self): patch = Dataset.from_iterable([ # Must override - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0), # Label must be remapped Bbox(5, 6, 2, 3, label=1), # Label must be remapped @@ -40,25 +43,26 @@ def test_can_run_patch(self): ]), # Must be added - DatasetItem(id=2, image=np.ones((5, 4, 3)), + DatasetItem(id=2, media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 2, label=1) # Label must be remapped ]), ], categories=['b', 'a', 'c']) expected = Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', + media=Image(data=np.ones((10, 6, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1, id=1, group=1), Bbox(5, 6, 2, 3, label=0, id=2, group=2), ]), - DatasetItem(id=1, image=np.ones((5, 4, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1, id=1, group=1) ]), - DatasetItem(id=2, image=np.ones((5, 4, 3)), + DatasetItem(id=2, media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 2, label=0, id=2, group=2) ]), @@ -68,8 +72,8 @@ def test_can_run_patch(self): dataset_url = osp.join(test_dir, 'dataset1') patch_url = osp.join(test_dir, 'dataset2') - dataset.export(dataset_url, 'coco', save_images=True) - patch.export(patch_url, 'voc', save_images=True) + dataset.export(dataset_url, 'coco', save_media=True) + patch.export(patch_url, 'voc', save_media=True) run(self, 'patch', '--overwrite', dataset_url + ':coco', patch_url + ':voc', @@ -77,17 +81,17 @@ def test_can_run_patch(self): compare_datasets(self, expected, Dataset.import_from(dataset_url, format='coco'), - require_images=True, ignored_attrs='*') + require_media=True, ignored_attrs='*') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_patch_fails_on_inplace_update_without_overwrite(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((3, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((3, 5, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) patch = Dataset.from_iterable([ - DatasetItem(id=2, image=np.zeros((3, 4, 3)), + DatasetItem(id=2, media=Image(data=np.zeros((3, 4, 3))), annotations=[ Bbox(1, 2, 3, 2, label=1) ]), ], categories=['b', 'a', 'c']) @@ -95,8 +99,8 @@ def test_patch_fails_on_inplace_update_without_overwrite(self): dataset_url = osp.join(test_dir, 'dataset1') patch_url = osp.join(test_dir, 'dataset2') - dataset.export(dataset_url, 'coco', save_images=True) - patch.export(patch_url, 'coco', save_images=True) + dataset.export(dataset_url, 'coco', save_media=True) + patch.export(patch_url, 'coco', save_media=True) run(self, 'patch', dataset_url + ':coco', patch_url + ':coco', expected_code=1) @@ -104,12 +108,12 @@ def test_patch_fails_on_inplace_update_without_overwrite(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_patch_fails_on_inplace_update_of_stage(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((3, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((3, 5, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) patch = Dataset.from_iterable([ - DatasetItem(id=2, image=np.zeros((3, 4, 3)), + DatasetItem(id=2, media=Image(data=np.zeros((3, 4, 3))), annotations=[ Bbox(1, 2, 3, 2, label=1) ]), ], categories=['b', 'a', 'c']) @@ -117,8 +121,8 @@ def test_patch_fails_on_inplace_update_of_stage(self): dataset_url = osp.join(test_dir, 'dataset1') patch_url = osp.join(test_dir, 'dataset2') - dataset.export(dataset_url, 'coco', save_images=True) - patch.export(patch_url, 'coco', save_images=True) + dataset.export(dataset_url, 'coco', save_media=True) + patch.export(patch_url, 'coco', save_media=True) project_dir = osp.join(test_dir, 'proj') with Project.init(project_dir) as project: diff --git a/tests/cli/test_project.py b/tests/cli/test_project.py index 269b8c7909..8debd0ab69 100644 --- a/tests/cli/test_project.py +++ b/tests/cli/test_project.py @@ -7,6 +7,7 @@ from datumaro.components.annotation import Bbox, Label from datumaro.components.dataset import DEFAULT_FORMAT, Dataset from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.components.project import Project from datumaro.util.scope import scope_add, scoped from datumaro.util.test_utils import TestDir, compare_datasets, compare_dirs @@ -95,11 +96,11 @@ def test_can_use_vcs(self): result_dir = osp.join(project_dir, 'result') Dataset.from_iterable([ - DatasetItem(0, image=np.ones((1, 2, 3)), annotations=[ + DatasetItem(0, media=Image(data=np.ones((1, 2, 3))), annotations=[ Bbox(1, 1, 1, 1, label=0), Bbox(2, 2, 2, 2, label=1), ]) - ], categories=['a', 'b']).save(dataset_dir, save_images=True) + ], categories=['a', 'b']).save(dataset_dir, save_media=True) run(self, 'create', '-o', project_dir) run(self, 'import', '-p', project_dir, '-f', 'datumaro', dataset_dir) @@ -117,12 +118,12 @@ def test_can_use_vcs(self): '-o', result_dir, 'source-1', '--', '--save-images') parsed = Dataset.import_from(result_dir, 'coco') compare_datasets(self, Dataset.from_iterable([ - DatasetItem(0, image=np.ones((1, 2, 3)), + DatasetItem(0, media=Image(data=np.ones((1, 2, 3))), annotations=[ Bbox(2, 2, 2, 2, label=1, group=1, id=1, attributes={'is_crowd': False}), ], attributes={ 'id': 1 }) - ], categories=['a', 'cat']), parsed, require_images=True) + ], categories=['a', 'cat']), parsed, require_media=True) shutil.rmtree(result_dir, ignore_errors=True) run(self, 'checkout', '-p', project_dir, 'HEAD~1') @@ -130,13 +131,13 @@ def test_can_use_vcs(self): '-o', result_dir, '--', '--save-images') parsed = Dataset.import_from(result_dir, 'coco') compare_datasets(self, Dataset.from_iterable([ - DatasetItem(0, image=np.ones((1, 2, 3)), annotations=[ + DatasetItem(0, media=Image(data=np.ones((1, 2, 3))), annotations=[ Bbox(1, 1, 1, 1, label=0, group=1, id=1, attributes={'is_crowd': False}), Bbox(2, 2, 2, 2, label=1, group=2, id=2, attributes={'is_crowd': False}), ], attributes={ 'id': 1 }) - ], categories=['a', 'cat']), parsed, require_images=True) + ], categories=['a', 'cat']), parsed, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) @scoped diff --git a/tests/cli/test_sly_point_cloud_format.py b/tests/cli/test_sly_point_cloud_format.py index 343d4f9076..e2ea756da4 100644 --- a/tests/cli/test_sly_point_cloud_format.py +++ b/tests/cli/test_sly_point_cloud_format.py @@ -6,6 +6,7 @@ ) from datumaro.components.dataset import Dataset from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image, PointCloud from datumaro.util.test_utils import TestDir, compare_datasets_3d from datumaro.util.test_utils import run_datum as run @@ -37,11 +38,11 @@ def test_can_convert_to_kitti_raw(self): attributes={'track_id': 3, 'tag1': 'v12', 'tag3': '', 'occluded': False}), ], - point_cloud=osp.join(export_dir, 'velodyne_points', 'data', - 'frame1.pcd'), - related_images=[osp.join(export_dir, 'image_00', 'data', - 'frame1.png') - ], + media=PointCloud(osp.join(export_dir, 'velodyne_points', 'data', + 'frame1.pcd'), + extra_images=[Image(path=osp.join(export_dir, 'image_00', 'data', + 'frame1.png')) + ]), attributes={'frame': 0} ), @@ -52,14 +53,14 @@ def test_can_convert_to_kitti_raw(self): attributes={'track_id': 1, 'tag1': '', 'tag3': '', 'occluded': False}) ], - point_cloud=osp.join(export_dir, 'velodyne_points', 'data', - 'frame2.pcd'), - related_images=[osp.join(export_dir, 'image_00', 'data', - 'frame2.png') - ], + media=PointCloud(osp.join(export_dir, 'velodyne_points', 'data', + 'frame2.pcd'), + extra_images=[Image(path=osp.join(export_dir, 'image_00', 'data', + 'frame2.png')) + ]), attributes={'frame': 1} ), - ], categories={AnnotationType.label: expected_label_cat}) + ], categories={AnnotationType.label: expected_label_cat}, media_type=PointCloud) run(self, 'convert', '-if', 'sly_pointcloud', '-i', DUMMY_DATASET_DIR, diff --git a/tests/cli/test_transform.py b/tests/cli/test_transform.py index a3dc0aea77..8081db877e 100644 --- a/tests/cli/test_transform.py +++ b/tests/cli/test_transform.py @@ -50,7 +50,7 @@ def test_transform_fails_on_inplace_update_of_stage(self): dataset = Dataset.from_iterable([ DatasetItem(id=1, annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - dataset.export(dataset_url, 'coco', save_images=True) + dataset.export(dataset_url, 'coco', save_media=True) project_dir = osp.join(test_dir, 'proj') with Project.init(project_dir) as project: diff --git a/tests/cli/test_voc_format.py b/tests/cli/test_voc_format.py index 8eebc49814..c75e237153 100644 --- a/tests/cli/test_voc_format.py +++ b/tests/cli/test_voc_format.py @@ -6,6 +6,7 @@ from datumaro.components.annotation import Bbox, Label, Mask from datumaro.components.dataset import Dataset, DatasetItem +from datumaro.components.media import Image from datumaro.util.test_utils import TestDir, compare_datasets from datumaro.util.test_utils import run_datum as run import datumaro.plugins.voc_format.format as VOC @@ -36,7 +37,7 @@ def _test_can_save_and_load(self, project_path, source_path, expected_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) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_preparing_dataset_for_train_model(self): @@ -110,7 +111,8 @@ def test_export_to_voc_format(self): label_map.move_to_end('background', last=False) expected_dataset = Dataset.from_iterable([ - DatasetItem(id='1', subset='train', image=np.ones((10, 15, 3)), + DatasetItem(id='1', subset='train', + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(0.0, 2.0, 4.0, 2.0, attributes={ @@ -145,7 +147,7 @@ def test_export_to_voc_format(self): parsed_dataset = Dataset.import_from(voc_export, format='voc') compare_datasets(self, expected_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_283) def test_convert_to_voc_format(self): @@ -169,7 +171,7 @@ def test_convert_to_voc_format(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='default', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0.0, 4.0, 4.0, 8.0, attributes={ @@ -194,7 +196,7 @@ def test_convert_to_voc_format(self): target_dataset = Dataset.import_from(voc_dir, format='voc') compare_datasets(self, expected_dataset, target_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_283) def test_convert_from_voc_format(self): @@ -219,7 +221,7 @@ def test_convert_from_voc_format(self): subset='default', annotations=[Label(i)]) for i, label in enumerate(labels) ] + [DatasetItem(id='no_label/2007_000002', subset='default', - image=np.ones((10, 20, 3))) + media=Image(data=np.ones((10, 20, 3)))) ], categories=labels ) @@ -231,13 +233,13 @@ def test_convert_from_voc_format(self): target_dataset = Dataset.import_from(imagenet_dir, format='imagenet') compare_datasets(self, expected_dataset, target_dataset, - require_images=True) + require_media=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=np.ones((10, 20, 3)), + media=Image(data=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, id=1, group=1, attributes={ @@ -263,7 +265,7 @@ def test_can_save_and_load_voc_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))) + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) voc_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -275,7 +277,7 @@ def test_can_save_and_load_voc_dataset(self): 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)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=1, group=1, attributes={ @@ -292,7 +294,7 @@ def test_can_save_and_load_voc_layout_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -317,11 +319,11 @@ def test_can_save_and_load_voc_layout_dataset(self): def test_can_save_and_load_voc_classification_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=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))), + media=Image(data=np.ones((10, 20, 3)))), ], categories=VOC.make_voc_categories()) dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -345,7 +347,7 @@ def test_can_save_and_load_voc_classification_dataset(self): 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)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, attributes={ @@ -369,7 +371,7 @@ def test_can_save_and_load_voc_detection_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))), ], categories=VOC.make_voc_categories()) dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -393,13 +395,13 @@ def test_can_save_and_load_voc_detection_dataset(self): 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)), + media=Image(data=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))), + media=Image(data=np.ones((10, 20, 3)))), ], categories=VOC.make_voc_categories()) dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -424,7 +426,7 @@ def test_can_save_and_load_voc_segmentation_dataset(self): 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)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=1, group=1, attributes={ @@ -440,7 +442,7 @@ def test_can_save_and_load_voc_action_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))), ], categories=VOC.make_voc_categories()) dataset_dir = osp.join(DUMMY_DATASETS_DIR, 'voc_dataset1') @@ -465,7 +467,7 @@ def test_can_save_and_load_voc_action_dataset(self): def test_label_projection_with_masks(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(1, 2, 2, 2, label=3, attributes={ @@ -480,7 +482,7 @@ def test_label_projection_with_masks(self): ), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))), ], categories=VOC.make_voc_categories({ 'background': [(0, 0, 0), [], []], # Added on export 'a': [(128, 0, 0), [], []], # Generated by the transform diff --git a/tests/cli/test_yolo_format.py b/tests/cli/test_yolo_format.py index 532f6f7f6e..c157fc87b7 100644 --- a/tests/cli/test_yolo_format.py +++ b/tests/cli/test_yolo_format.py @@ -6,6 +6,7 @@ from datumaro.components.annotation import AnnotationType, Bbox from datumaro.components.dataset import Dataset from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.util.test_utils import TestDir, compare_datasets from datumaro.util.test_utils import run_datum as run import datumaro.plugins.voc_format.format as VOC @@ -18,7 +19,7 @@ class YoloIntegrationScenarios(TestCase): def test_can_save_and_load_yolo_dataset(self): target_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(3.0, 3.0, 2.0, 3.0, label=4), Bbox(0.0, 2.0, 4.0, 2.0, label=2) @@ -68,7 +69,7 @@ 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)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(1.0, 2.0, 2.0, 2.0, label=8), Bbox(4.0, 5.0, 2.0, 2.0, label=15), @@ -88,19 +89,19 @@ def test_can_convert_voc_to_yolo(self): parsed_dataset = Dataset.import_from(yolo_dir, format='yolo') compare_datasets(self, target_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_ignore_non_supported_subsets(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='img1', subset='test', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(1.0, 2.0, 1.0, 1.0, label=0) ] ), DatasetItem(id='img2', subset='train', - image=np.ones((10, 5, 3)), + media=Image(data=np.ones((10, 5, 3))), annotations=[ Bbox(3.0, 1.0, 2.0, 1.0, label=1) ] @@ -109,7 +110,7 @@ def test_can_ignore_non_supported_subsets(self): target_dataset = Dataset.from_iterable([ DatasetItem(id='img2', subset='train', - image=np.ones((10, 5, 3)), + media=Image(data=np.ones((10, 5, 3))), annotations=[ Bbox(3.0, 1.0, 2.0, 1.0, label=1) ] @@ -118,7 +119,7 @@ def test_can_ignore_non_supported_subsets(self): with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset_dir') - source_dataset.save(dataset_dir, save_images=True) + source_dataset.save(dataset_dir, save_media=True) proj_dir = osp.join(test_dir, 'proj') run(self, 'create', '-o', proj_dir) @@ -135,7 +136,7 @@ def test_can_ignore_non_supported_subsets(self): def test_can_delete_labels_from_yolo_dataset(self): target_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(0.0, 2.0, 4.0, 2.0, label=0) ] diff --git a/tests/requirements.py b/tests/requirements.py index 733e7e5541..8047b434a6 100644 --- a/tests/requirements.py +++ b/tests/requirements.py @@ -21,6 +21,7 @@ class Requirements: DATUM_API = "Datumaro API" DATUM_PROGRESS_REPORTING = "Datumaro progress reporting requirement" DATUM_ERROR_REPORTING = "Datumaro error reporting requirement" + DATUM_GENERIC_MEDIA = "Datumaro generic media support" # GitHub issues (not bugs) # https://github.com/openvinotoolkit/datumaro/issues diff --git a/tests/test_ade20k2017_format.py b/tests/test_ade20k2017_format.py index 5d41f375d7..0f7b52817c 100644 --- a/tests/test_ade20k2017_format.py +++ b/tests/test_ade20k2017_format.py @@ -10,6 +10,7 @@ from datumaro.components.annotation import AnnotationType, LabelCategories, Mask from datumaro.components.dataset import Dataset, DatasetItem from datumaro.components.environment import Environment +from datumaro.components.media import Image from datumaro.plugins.ade20k2017_format import Ade20k2017Importer from datumaro.util.test_utils import compare_datasets @@ -32,7 +33,7 @@ def test_can_import(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id='street/1', subset='training', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Mask(image=np.array([[0, 1, 0, 0]] * 3), label=0, group=1, z_order=0, id=1), @@ -43,7 +44,7 @@ def test_can_import(self): attributes={'walkin': True}) ]), DatasetItem(id='2', subset='validation', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Mask(image=np.array([[0, 1, 0, 1]] * 3), label=0, id=1, z_order=0, group=1), @@ -61,14 +62,14 @@ def test_can_import(self): imported_dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'ade20k2017') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_399) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id='street/1', subset='training', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Mask(image=np.array([[0, 1, 0, 0]] * 3), label=0, group=1, z_order=0, id=1), @@ -85,4 +86,4 @@ def test_can_import_with_meta_file(self): imported_dataset = Dataset.import_from(DUMMY_DATASET_DIR_META_FILE, 'ade20k2017') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) diff --git a/tests/test_ade20k2020_format.py b/tests/test_ade20k2020_format.py index d0412eabd2..e46a87a91a 100644 --- a/tests/test_ade20k2020_format.py +++ b/tests/test_ade20k2020_format.py @@ -12,6 +12,7 @@ ) from datumaro.components.dataset import Dataset, DatasetItem from datumaro.components.environment import Environment +from datumaro.components.media import Image from datumaro.plugins.ade20k2020_format import Ade20k2020Importer from datumaro.util.test_utils import compare_datasets @@ -34,7 +35,7 @@ def test_can_import(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id='street/1', subset='training', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Polygon([1, 0, 1, 1, 1, 2, 1, 3, 1, 4], group=1, z_order=0, id=1, label=1, @@ -54,7 +55,7 @@ def test_can_import(self): group=2, z_order=1, id=2), ]), DatasetItem(id='2', subset='validation', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(image=np.array([[0, 0, 1, 1, 1]] * 5), label=0, group=401, z_order=0, id=401), @@ -81,14 +82,14 @@ def test_can_import(self): imported_dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'ade20k2020') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_399) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable( [ DatasetItem(id='street/1', subset='training', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Polygon([1, 0, 1, 1, 1, 2, 1, 3, 1, 4], group=1, z_order=0, id=1, label=1, @@ -114,4 +115,4 @@ def test_can_import_with_meta_file(self): imported_dataset = Dataset.import_from(DUMMY_DATASET_DIR_META_FILE, 'ade20k2020') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) diff --git a/tests/test_align_celeba_format.py b/tests/test_align_celeba_format.py index a12f143832..cead38e41c 100644 --- a/tests/test_align_celeba_format.py +++ b/tests/test_align_celeba_format.py @@ -9,6 +9,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.plugins.align_celeba_format import AlignCelebaImporter from datumaro.util.test_utils import compare_datasets @@ -24,7 +25,7 @@ class AlignCelebaImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='000001', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Label(12), Points([69, 109, 106, 113, 77, 142, 73, 152, 108, 154], @@ -35,7 +36,7 @@ def test_can_import(self): 'Bangs': False, 'Big_Lips': False, 'Big_Nose': False} ), DatasetItem(id='000002', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Label(5), Points([69, 110, 107, 112, 81, 135, 70, 151, 108, 153], @@ -43,7 +44,7 @@ def test_can_import(self): ] ), DatasetItem(id='000003', subset='val', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Label(2), Points([76, 112, 104, 106, 108, 128, 74, 156, 98, 158], @@ -54,7 +55,7 @@ def test_can_import(self): 'Bangs': False, 'Big_Lips': False, 'Big_Nose': True} ), DatasetItem(id='000004', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Label(10), Points([72, 113, 108, 108, 101, 138, 71, 155, 101, 151], @@ -62,7 +63,7 @@ def test_can_import(self): ] ), DatasetItem(id='000005', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[ Label(7), Points([66, 114, 112, 112, 86, 119, 71, 147, 104, 150], @@ -80,29 +81,29 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_ALIGN_DATASET_DIR, 'align_celeba') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='000001', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(1)] ), DatasetItem(id='000002', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(3)] ), DatasetItem(id='000003', subset='val', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(0)] ), DatasetItem(id='000004', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(2)] ), DatasetItem(id='000005', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(6)] ) ], categories=[f'class-{i}' for i in range(7)]) @@ -110,7 +111,7 @@ def test_can_import_with_meta_file(self): dataset = Dataset.import_from(DUMMY_ALIGN_DATASET_DIR_WITH_META_FILE, 'align_celeba') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_detect_align_dataset(self): diff --git a/tests/test_camvid_format.py b/tests/test_camvid_format.py index d48e857354..956c6fe728 100644 --- a/tests/test_camvid_format.py +++ b/tests/test_camvid_format.py @@ -63,7 +63,7 @@ class CamvidImportTest(TestCase): def test_can_import(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='0001TP_008550', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]]), label=1), Mask(image=np.array([[0, 0, 1, 0, 0]]), label=18), @@ -71,7 +71,7 @@ def test_can_import(self): ] ), DatasetItem(id='0001TP_008580', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]]), label=2), Mask(image=np.array([[0, 0, 1, 0, 0]]), label=4), @@ -79,14 +79,14 @@ def test_can_import(self): ] ), DatasetItem(id='0001TP_006690', subset='train', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 1, 1]]), label=3), Mask(image=np.array([[0, 0, 1, 0, 0]]), label=18), ] ), DatasetItem(id='0016E5_07959', subset = 'val', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 1, 0, 0]]), label=1), Mask(image=np.array([[0, 0, 0, 1, 1]]), label=8), @@ -117,7 +117,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='a/b/1', subset='test', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 0]]), label=0), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=3), Mask(image=np.array([[1, 0, 0, 0, 1]]), label=4), @@ -134,21 +134,25 @@ def test_can_save_camvid_segm_unpainted(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id=1, subset='a', image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[0, 0, 0, 1, 0]]), label=0), - Mask(image=np.array([[0, 1, 1, 0, 0]]), label=3), - Mask(image=np.array([[1, 0, 0, 0, 1]]), label=4), - ]), + DatasetItem(id=1, subset='a', media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[0, 0, 0, 1, 0]]), label=0), + Mask(image=np.array([[0, 1, 1, 0, 0]]), label=3), + Mask(image=np.array([[1, 0, 0, 0, 1]]), label=4), + ] + ), ]) class DstExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id=1, subset='a', image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[0, 0, 0, 1, 0]]), label=0), - Mask(image=np.array([[0, 1, 1, 0, 0]]), label=3), - Mask(image=np.array([[1, 0, 0, 0, 1]]), label=4), - ]), + DatasetItem(id=1, subset='a', media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[0, 0, 0, 1, 0]]), label=0), + Mask(image=np.array([[0, 1, 1, 0, 0]]), label=3), + Mask(image=np.array([[1, 0, 0, 0, 1]]), label=4), + ] + ), ]) with TestDir() as test_dir: @@ -162,15 +166,19 @@ def test_can_save_dataset_with_no_subsets(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 0]]), label=0), - Mask(image=np.array([[0, 1, 1, 0, 1]]), label=3), - ]), + DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 0]]), label=0), + Mask(image=np.array([[0, 1, 1, 0, 1]]), label=3), + ] + ), - DatasetItem(id=2, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), - Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), - ]), + DatasetItem(id=2, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), + Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), + ] + ), ]) with TestDir() as test_dir: @@ -183,7 +191,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='кириллица с пробелом', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 0]]), label=0), Mask(image=np.array([[0, 1, 1, 0, 1]]), label=3), ] @@ -200,7 +208,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='a/b/1', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), ), ]) @@ -213,10 +221,12 @@ def __iter__(self): def test_dataset_with_source_labelmap_undefined(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), label=0), - Mask(image=np.array([[0, 0, 1, 0, 0]]), label=1), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), label=0), + Mask(image=np.array([[0, 0, 1, 0, 0]]), label=1), + ] + ) def categories(self): label_cat = LabelCategories() @@ -228,12 +238,14 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), - label=self._label('Label_1')), - Mask(image=np.array([[0, 0, 1, 0, 0]]), - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), + label=self._label('Label_1')), + Mask(image=np.array([[0, 0, 1, 0, 0]]), + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -251,10 +263,12 @@ def categories(self): def test_dataset_with_source_labelmap_defined(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), - Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), + Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), + ] + ) def categories(self): label_map = OrderedDict() @@ -265,12 +279,14 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), - label=self._label('label_1')), - Mask(image=np.array([[0, 0, 1, 0, 1]]), - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), + label=self._label('label_1')), + Mask(image=np.array([[0, 0, 1, 0, 1]]), + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -289,9 +305,9 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): class SrcExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image( + DatasetItem(id='a/b/c/2', media=Image( path='a/b/c/2.bmp', data=np.ones((1, 5, 3)) ), annotations=[ @@ -311,9 +327,9 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image( + DatasetItem(id='a/b/c/2', media=Image( path='a/b/c/2.bmp', data=np.ones((1, 5, 3)) ), annotations=[ @@ -335,8 +351,8 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(SrcExtractor(), - partial(CamvidConverter.convert, save_images=True), - test_dir, require_images=True, + partial(CamvidConverter.convert, save_media=True), + test_dir, require_media=True, target_dataset=DstExtractor()) @mark_requirement(Requirements.DATUM_GENERAL_REQ) @@ -344,11 +360,13 @@ def test_inplace_save_writes_only_updated_data(self): src_mask_cat = MaskCategories.generate(3, include_background=False) expected = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Mask(np.ones((2, 1)), label=2) ]), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3))), + DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3)))), DatasetItem(2, subset='b'), ], categories=Camvid.make_camvid_categories(OrderedDict([ @@ -359,12 +377,14 @@ def test_inplace_save_writes_only_updated_data(self): with TestDir() as path: dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Mask(np.ones((2, 1)), label=1) ]), DatasetItem(2, subset='b'), - DatasetItem(3, subset='c', image=np.ones((2, 2, 3)), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Mask(np.ones((2, 2)), label=0) ]), @@ -372,12 +392,13 @@ def test_inplace_save_writes_only_updated_data(self): ], categories={ AnnotationType.label: LabelCategories.from_iterable(['a', 'b']), AnnotationType.mask: src_mask_cat - }) - dataset.export(path, 'camvid', save_images=True) + }, media_type=Image) + dataset.export(path, 'camvid', save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'a', 'aannot', 'a.txt', 'b.txt', 'label_colors.txt'}, @@ -385,16 +406,18 @@ def test_inplace_save_writes_only_updated_data(self): self.assertEqual({'1.jpg', '2.jpg'}, set(os.listdir(osp.join(path, 'a')))) compare_datasets(self, expected, Dataset.import_from(path, 'camvid'), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_dataset_with_meta_file(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), - Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1), + Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2), + ] + ) def categories(self): label_map = OrderedDict() @@ -405,12 +428,14 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 1, 0, 1, 0]]), - label=self._label('label_1')), - Mask(image=np.array([[0, 0, 1, 0, 1]]), - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 1, 0, 1, 0]]), + label=self._label('label_1')), + Mask(image=np.array([[0, 0, 1, 0, 1]]), + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() diff --git a/tests/test_celeba_format.py b/tests/test_celeba_format.py index d793900718..c5141f7897 100644 --- a/tests/test_celeba_format.py +++ b/tests/test_celeba_format.py @@ -9,6 +9,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.plugins.celeba_format import CelebaImporter from datumaro.util.test_utils import compare_datasets @@ -24,7 +25,7 @@ class CelebaImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='000001', subset='train', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Label(12), Bbox(95, 71, 226, 313, label=12), @@ -36,7 +37,7 @@ def test_can_import(self): 'Bangs': False, 'Big_Lips': False, 'Big_Nose': False} ), DatasetItem(id='000002', subset='train', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Label(5), Bbox(72, 94, 221, 306, label=5), @@ -45,7 +46,7 @@ def test_can_import(self): ] ), DatasetItem(id='000003', subset='val', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Label(2), Bbox(216, 59, 91, 126, label=2), @@ -57,7 +58,7 @@ def test_can_import(self): 'Bangs': False, 'Big_Lips': False, 'Big_Nose': True} ), DatasetItem(id='000004', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Label(10), Bbox(622, 257, 564, 781, label=10), @@ -66,7 +67,7 @@ def test_can_import(self): ] ), DatasetItem(id='000005', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Label(7), Bbox(236, 109, 120, 166, label=7), @@ -85,29 +86,29 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'celeba') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='000001', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(1)] ), DatasetItem(id='000002', subset='train', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(3)] ), DatasetItem(id='000003', subset='val', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(0)] ), DatasetItem(id='000004', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(2)] ), DatasetItem(id='000005', subset='test', - image=np.ones((3, 4, 3)), + media=Image(data=np.ones((3, 4, 3))), annotations=[Label(6)] ) ], categories=[f'class-{i}' for i in range(7)]) @@ -115,7 +116,7 @@ def test_can_import_with_meta_file(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_WITH_META_FILE, 'celeba') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_detect(self): diff --git a/tests/test_cifar_format.py b/tests/test_cifar_format.py index 6140a9c33e..e2420a8962 100644 --- a/tests/test_cifar_format.py +++ b/tests/test_cifar_format.py @@ -21,24 +21,24 @@ class CifarFormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='image_2', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), DatasetItem(id='image_3', subset='test', - image=np.ones((32, 32, 3)) + media=Image(data=np.ones((32, 32, 3))) ), DatasetItem(id='image_4', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ) ], categories=['label_0', 'label_1']) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=True) + CifarConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_without_saving_images(self): @@ -52,63 +52,63 @@ def test_can_save_and_load_without_saving_images(self): ], categories=['x', 'y']) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=False) + CifarConverter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_different_image_size(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='image_1', - image=np.ones((10, 8, 3)), + media=Image(data=np.ones((10, 8, 3))), annotations=[Label(0)] ), DatasetItem(id='image_2', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ), ], categories=['dog', 'cat']) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=True) + CifarConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id="кириллица с пробелом", - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), ], categories=['label_0']) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=True) + CifarConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ DatasetItem(id='q/1', - image=Image(path='q/1.JPEG', data=np.zeros((32, 32, 3)))), + media=Image(path='q/1.JPEG', data=np.zeros((32, 32, 3)))), DatasetItem(id='a/b/c/2', - image=Image(path='a/b/c/2.bmp', data=np.zeros((32, 32, 3)))), + media=Image(path='a/b/c/2.bmp', data=np.zeros((32, 32, 3)))), ], categories=[]) with TestDir() as test_dir: - CifarConverter.convert(dataset, test_dir, save_images=True) + CifarConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_empty_image(self): @@ -118,60 +118,67 @@ def test_can_save_and_load_empty_image(self): ], categories=['label_0']) with TestDir() as test_dir: - CifarConverter.convert(dataset, test_dir, save_images=True) + CifarConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data(self): expected = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Label(0) ]), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3)), + DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))), annotations=[ Label(1) ]), - DatasetItem(2, subset='b', image=np.ones((2, 2, 3)), + DatasetItem(2, subset='b', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Label(1) ]), ], categories=['a', 'b', 'c', 'd']) dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Label(0) ]), - DatasetItem(2, subset='b', image=np.ones((2, 2, 3)), + DatasetItem(2, subset='b', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Label(1) ]), - DatasetItem(3, subset='c', image=np.ones((2, 3, 3)), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 3, 3))), annotations=[ Label(2) ]), ], categories=['a', 'b', 'c', 'd']) with TestDir() as path: - dataset.export(path, 'cifar', save_images=True) + dataset.export(path, 'cifar', save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)), + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))), annotations=[ Label(1) ])) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'a', 'b', 'batches.meta'}, set(os.listdir(path))) compare_datasets(self, expected, Dataset.import_from(path, 'cifar'), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_cifar100(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='image_2', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), DatasetItem(id='image_3', subset='test', - image=np.ones((32, 32, 3)) + media=Image(data=np.ones((32, 32, 3))) ), DatasetItem(id='image_4', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ) ], categories=[ @@ -180,11 +187,11 @@ def test_can_save_and_load_cifar100(self): ]) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=True) + CifarConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_cifar100_without_saving_images(self): @@ -201,11 +208,11 @@ def test_can_save_and_load_cifar100_without_saving_images(self): ]) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=False) + CifarConverter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'cifar') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_catch_pickle_exception(self): @@ -220,26 +227,26 @@ def test_can_catch_pickle_exception(self): def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='image_2', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), DatasetItem(id='image_3', subset='test', - image=np.ones((32, 32, 3)) + media=Image(data=np.ones((32, 32, 3))) ), DatasetItem(id='image_4', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ) ], categories=['label_0', 'label_1']) with TestDir() as test_dir: - CifarConverter.convert(source_dataset, test_dir, save_images=True, + CifarConverter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'cifar') self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_10_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'cifar10_dataset') @@ -252,31 +259,31 @@ class CifarImporterTest(TestCase): def test_can_import_10(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='image_1', subset='data_batch_1', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), DatasetItem(id='image_2', subset='test_batch', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ), DatasetItem(id='image_3', subset='test_batch', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(3)] ), DatasetItem(id='image_4', subset='test_batch', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(2)] ), DatasetItem(id='image_5', subset='test_batch', - image=np.array([[[1, 2, 3], [4, 5, 6]], - [[1, 2, 3], [4, 5, 6]]]), + media=Image(data=np.array([[[1, 2, 3], [4, 5, 6]], + [[1, 2, 3], [4, 5, 6]]])), annotations=[Label(3)] ) ], categories=['airplane', 'automobile', 'bird', 'cat']) dataset = Dataset.import_from(DUMMY_10_DATASET_DIR, 'cifar') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_10(self): @@ -290,29 +297,29 @@ def test_can_import_100(self): # This should be normal on practice. expected_dataset = Dataset.from_iterable([ DatasetItem(id='image_1', subset='train', - image=np.ones((7, 8, 3)), + media=Image(data=np.ones((7, 8, 3))), annotations=[Label(0)] ), DatasetItem(id='image_2', subset='train', - image=np.ones((4, 5, 3)), + media=Image(data=np.ones((4, 5, 3))), annotations=[Label(1)] ), DatasetItem(id='image_3', subset='train', - image=np.ones((4, 5, 3)), + media=Image(data=np.ones((4, 5, 3))), annotations=[Label(2)] ), DatasetItem(id='image_1', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(0)] ), DatasetItem(id='image_2', subset='test', - image=np.ones((32, 32, 3)), + media=Image(data=np.ones((32, 32, 3))), annotations=[Label(1)] ), DatasetItem(id='image_3', subset='test', - image=np.array([[[1, 2, 3], [4, 5, 6]], - [[1, 2, 3], [4, 5, 6]]]), + media=Image(data=np.array([[[1, 2, 3], [4, 5, 6]], + [[1, 2, 3], [4, 5, 6]]])), annotations=[Label(2)] ) ], categories=[ @@ -323,7 +330,7 @@ def test_can_import_100(self): dataset = Dataset.import_from(DUMMY_100_DATASET_DIR, 'cifar') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_100(self): diff --git a/tests/test_cityscapes_format.py b/tests/test_cityscapes_format.py index 7486f6a2c1..47fde5982a 100644 --- a/tests/test_cityscapes_format.py +++ b/tests/test_cityscapes_format.py @@ -63,7 +63,7 @@ def test_can_import(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='defaultcity/defaultcity_000001_000031', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=3, attributes={'is_crowd': True}), @@ -75,7 +75,7 @@ def test_can_import(self): ), DatasetItem(id='defaultcity/defaultcity_000001_000032', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), id=1, label=31, attributes={'is_crowd': False}), @@ -87,7 +87,7 @@ def test_can_import(self): ), DatasetItem(id='defaultcity/defaultcity_000002_000045', subset='train', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 1, 1]]), label=3, attributes={'is_crowd': True}), @@ -97,7 +97,7 @@ def test_can_import(self): ), DatasetItem(id='defaultcity/defaultcity_000001_000019', subset = 'val', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 1, 1]]), label=3, attributes={'is_crowd': True}), @@ -116,7 +116,7 @@ def test_can_import_with_train_label_map(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='defaultcity/defaultcity_000001_000031', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=19, attributes={'is_crowd': True}), @@ -126,7 +126,7 @@ def test_can_import_with_train_label_map(self): ), DatasetItem(id='defaultcity/defaultcity_000001_000032', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=16, attributes={'is_crowd': True}), @@ -138,7 +138,7 @@ def test_can_import_with_train_label_map(self): ), DatasetItem(id='defaultcity/defaultcity_000002_000045', subset='train', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 1, 1]]), label=19, attributes={'is_crowd': True}), @@ -148,7 +148,7 @@ def test_can_import_with_train_label_map(self): ), DatasetItem(id='defaultcity/defaultcity_000001_000019', subset = 'val', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 1, 1, 1]]), label=19, attributes={'is_crowd': True}), @@ -187,7 +187,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='defaultcity_1_2', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[0, 0, 0, 1, 0]]), label=3, attributes={'is_crowd': True}), @@ -199,7 +199,7 @@ def __iter__(self): ), DatasetItem(id='defaultcity_3', subset='val', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 1, 1]]), label=3, attributes={'is_crowd': True}), @@ -212,7 +212,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(CityscapesConverter.convert, label_map='cityscapes', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_267) def test_can_save_with_no_subsets(self): @@ -220,7 +220,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='defaultcity_1_2', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 1, 0]]), label=0, attributes={'is_crowd': True}), @@ -230,7 +230,7 @@ def __iter__(self): ), DatasetItem(id='defaultcity_1_3', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 1, 0]]), label=1, attributes={'is_crowd': True}), @@ -243,7 +243,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(CityscapesConverter.convert, label_map='cityscapes', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_267) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): @@ -251,7 +251,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='кириллица с пробелом', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 1, 1]]), label=3, attributes={'is_crowd': True}), @@ -264,7 +264,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(CityscapesConverter.convert, label_map='cityscapes', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_267) def test_can_save_with_relative_path_in_id(self): @@ -272,7 +272,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='a/b/1', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 1, 1]]), label=3, attributes={'is_crowd': True}), @@ -285,7 +285,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(CityscapesConverter.convert, label_map='cityscapes', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_267) def test_can_save_with_no_masks(self): @@ -293,34 +293,38 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='city_1_2', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), ), ]) with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(CityscapesConverter.convert, label_map='cityscapes', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_267) def test_dataset_with_source_labelmap_undefined(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), label=0), - Mask(np.array([[0, 1, 1, 0, 0]]), label=1), - ]), + DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), label=0), + Mask(np.array([[0, 1, 1, 0, 0]]), label=1), + ] + ), ], categories=['a', 'b']) class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('a')), - Mask(np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('b')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('a')), + Mask(np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('b')), + ] + ) def categories(self): label_map = OrderedDict() @@ -332,27 +336,31 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(CityscapesConverter.convert, label_map='source', - save_images=True), test_dir, target_dataset=DstExtractor()) + save_media=True), test_dir, target_dataset=DstExtractor()) @mark_requirement(Requirements.DATUM_267) def test_dataset_with_save_dataset_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), label=0), - Mask(np.array([[0, 1, 1, 0, 0]]), label=1), - ]), + DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), label=0), + Mask(np.array([[0, 1, 1, 0, 0]]), label=1), + ] + ), ], categories=['a', 'b']) class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('a')), - Mask(np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('b')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('a')), + Mask(np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('b')), + ] + ) def categories(self): label_map = OrderedDict() @@ -364,7 +372,7 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(CityscapesConverter.convert, label_map='source', - save_images=True, save_dataset_meta=True), test_dir, + save_media=True, save_dataset_meta=True), test_dir, target_dataset=DstExtractor()) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) @@ -372,12 +380,14 @@ def categories(self): def test_dataset_with_source_labelmap_defined(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), label=1, id=1, - attributes={'is_crowd': False}), - Mask(np.array([[0, 1, 1, 0, 0]]), label=2, id=2, - attributes={'is_crowd': False}), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), label=1, id=1, + attributes={'is_crowd': False}), + Mask(np.array([[0, 1, 1, 0, 0]]), label=2, id=2, + attributes={'is_crowd': False}), + ] + ) def categories(self): label_map = OrderedDict() @@ -388,14 +398,16 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('label_1')), - Mask(np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('label_1')), + Mask(np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -407,7 +419,7 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(SrcExtractor(), partial(CityscapesConverter.convert, label_map='source', - save_images=True), test_dir, target_dataset=DstExtractor()) + save_media=True), test_dir, target_dataset=DstExtractor()) @mark_requirement(Requirements.DATUM_267) def test_can_save_and_load_image_with_arbitrary_extension(self): @@ -415,11 +427,11 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='q', - image=Image(path='q.JPEG', data=np.zeros((4, 3, 3))) + media=Image(path='q.JPEG', data=np.zeros((4, 3, 3))) ), DatasetItem(id='w', - image=Image(path='w.bmp', data=np.ones((1, 5, 3))), + media=Image(path='w.bmp', data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 1, 0]]), label=0, attributes={'is_crowd': True}), @@ -436,21 +448,24 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), - partial(CityscapesConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CityscapesConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data(self): src_mask_cat = MaskCategories.generate(2, include_background=False) expected = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Mask(np.ones((2, 1)), label=2, id=1) ]), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3))), + DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3)))), - DatasetItem(2, subset='b', image=np.ones((2, 2, 3)), + DatasetItem(2, subset='b', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Mask(np.ones((2, 2)), label=1, id=1) ]), @@ -461,15 +476,18 @@ def test_inplace_save_writes_only_updated_data(self): with TestDir() as path: dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Mask(np.ones((2, 1)), label=1) ]), - DatasetItem(2, subset='b', image=np.ones((2, 2, 3)), + DatasetItem(2, subset='b', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Mask(np.ones((2, 2)), label=0) ]), - DatasetItem(3, subset='c', image=np.ones((2, 3, 3)), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 3, 3))), annotations=[ Mask(np.ones((2, 2)), label=0) ]), @@ -478,11 +496,11 @@ def test_inplace_save_writes_only_updated_data(self): AnnotationType.label: LabelCategories.from_iterable(['a', 'b']), AnnotationType.mask: src_mask_cat }) - dataset.export(path, 'cityscapes', save_images=True) + dataset.export(path, 'cityscapes', save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'a', 'b'}, set(os.listdir(osp.join(path, 'gtFine')))) @@ -504,7 +522,7 @@ def test_inplace_save_writes_only_updated_data(self): set(os.listdir(osp.join(path, 'imgsFine', 'leftImg8bit', 'b')))) compare_datasets(self, expected, Dataset.import_from(path, 'cityscapes'), - require_images=True, ignored_attrs=IGNORE_ALL) + require_media=True, ignored_attrs=IGNORE_ALL) @mark_requirement(Requirements.DATUM_BUG_470) def test_can_save_and_load_without_image_saving(self): @@ -512,7 +530,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='a', subset='test', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[0, 1, 1, 1, 0]]), label=3, attributes={'is_crowd': True}), diff --git a/tests/test_coco_format.py b/tests/test_coco_format.py index c7d603a595..bac298bda9 100644 --- a/tests/test_coco_format.py +++ b/tests/test_coco_format.py @@ -34,7 +34,8 @@ class CocoImporterTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_instances(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Bbox(2, 2, 3, 1, label=1, @@ -42,7 +43,8 @@ def test_can_import_instances(self): ] ), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Polygon([0, 0, 1, 0, 1, 2, 0, 2], label=0, @@ -70,12 +72,13 @@ def test_can_import_instances(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_instances_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Bbox(2, 2, 3, 1, label=1, @@ -88,18 +91,19 @@ def test_can_import_instances_with_any_annotation_filename(self): format = 'coco_instances' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'instances_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json')) imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_instances_with_original_cat_ids(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Bbox(2, 2, 3, 1, label=2, @@ -114,18 +118,20 @@ def test_can_import_instances_with_original_cat_ids(self): 'coco_instances', keep_original_category_ids=True) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_captions(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Caption('hello', id=1, group=1), ]), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Caption('world', id=1, group=1), @@ -149,12 +155,13 @@ def test_can_import_captions(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_captions_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Caption('hello', id=1, group=1), @@ -164,24 +171,26 @@ def test_can_import_captions_with_any_annotation_filename(self): format = 'coco_captions' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'captions_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json')) imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_labels(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Label(1, id=1, group=1), ]), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Label(0, id=1, group=1), @@ -205,12 +214,13 @@ def test_can_import_labels(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_labels_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Label(1, id=1, group=1), @@ -220,18 +230,19 @@ def test_can_import_labels_with_any_annotation_filename(self): format = 'coco_labels' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'labels_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json')) imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_keypoints(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=1, @@ -240,7 +251,8 @@ def test_can_import_keypoints(self): id=1, group=1, attributes={'is_crowd': False}), ]), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Points([1, 2, 3, 4, 2, 3], label=0, @@ -278,12 +290,13 @@ def test_can_import_keypoints(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_keypoints_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=1, @@ -301,7 +314,7 @@ def test_can_import_keypoints_with_any_annotation_filename(self): format = 'coco_person_keypoints' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'person_keypoints_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json') @@ -309,12 +322,13 @@ def test_can_import_keypoints_with_any_annotation_filename(self): imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_keypoints_with_original_cat_ids(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=2, @@ -338,14 +352,16 @@ def test_can_import_keypoints_with_original_cat_ids(self): keep_original_category_ids=True) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_image_info(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}) ]) @@ -365,37 +381,40 @@ def test_can_import_image_info(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_image_info_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}), ]) format = 'coco_image_info' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'image_info_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json')) imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_panoptic(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Mask(np.ones((5, 5)), label=0, id=460551, group=460551, attributes={'is_crowd': False}), ]), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=0, @@ -421,12 +440,13 @@ def test_can_import_panoptic(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_panoptic_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Mask(np.ones((5, 5)), label=0, id=460551, @@ -437,7 +457,7 @@ def test_can_import_panoptic_with_any_annotation_filename(self): format = 'coco_panoptic' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'panoptic_default'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc')) os.rename(osp.join(dataset_dir, 'annotations', 'panoptic_default.json'), @@ -445,12 +465,13 @@ def test_can_import_panoptic_with_any_annotation_filename(self): imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_panoptic_with_original_cat_ids(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Mask(np.ones((5, 5)), label=1, id=460551, @@ -464,12 +485,13 @@ def test_can_import_panoptic_with_original_cat_ids(self): 'coco_panoptic', keep_original_category_ids=True) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_stuff(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Mask(np.array( @@ -478,7 +500,8 @@ def test_can_import_stuff(self): id=7, group=7, attributes={'is_crowd': False}), ]), - DatasetItem(id='b', subset='val', image=np.ones((10, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((10, 5, 3))), attributes={'id': 40}, annotations=[ Mask(np.array( [[1, 1, 0, 0, 0]] * 10 ), label=1, @@ -502,12 +525,13 @@ def test_can_import_stuff(self): with self.subTest(path=path, format=format, subset=subset): dataset = Dataset.import_from(path, format) - compare_datasets(self, expected, dataset, require_images=True) + compare_datasets(self, expected, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_stuff_with_any_annotation_filename(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='default', image=np.ones((5, 10, 3)), + DatasetItem(id='a', subset='default', + media=Image(data=np.ones((5, 10, 3))), attributes={'id': 5}, annotations=[ Mask(np.array( @@ -520,13 +544,13 @@ def test_can_import_stuff_with_any_annotation_filename(self): format = 'coco_stuff' with TestDir() as test_dir: dataset_dir = osp.join(test_dir, 'dataset') - expected_dataset.export(dataset_dir, format, save_images=True) + expected_dataset.export(dataset_dir, format, save_media=True) os.rename(osp.join(dataset_dir, 'annotations', 'stuff_default.json'), osp.join(dataset_dir, 'annotations', 'aa_bbbb_cccc.json')) imported_dataset = Dataset.import_from(dataset_dir, format) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect(self): @@ -605,7 +629,8 @@ def test_can_save_and_load_captions(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_instances(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ # Bbox + single polygon Bbox(0, 1, 2, 2, @@ -615,7 +640,8 @@ def test_can_save_and_load_instances(self): attributes={ 'is_crowd': False }, label=2, group=1, id=1), ], attributes={'id': 1}), - DatasetItem(id=2, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ # Mask + bbox Mask(np.array([ @@ -630,7 +656,8 @@ def test_can_save_and_load_instances(self): attributes={ 'is_crowd': True }), ], attributes={'id': 2}), - DatasetItem(id=3, subset='val', image=np.ones((4, 4, 3)), + DatasetItem(id=3, subset='val', + media=Image(data=np.ones((4, 4, 3))), annotations=[ # Bbox + mask Bbox(0, 1, 2, 2, label=4, group=3, id=3, @@ -647,13 +674,15 @@ def test_can_save_and_load_instances(self): ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Polygon([0, 1, 2, 1, 2, 3, 0, 3], attributes={ 'is_crowd': False }, label=2, group=1, id=1), ], attributes={'id': 1}), - DatasetItem(id=2, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 1, 0, 0], @@ -665,7 +694,8 @@ def test_can_save_and_load_instances(self): label=4, group=3, id=3), ], attributes={'id': 2}), - DatasetItem(id=3, subset='val', image=np.ones((4, 4, 3)), + DatasetItem(id=3, subset='val', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 0, 0, 0], @@ -686,7 +716,8 @@ def test_can_save_and_load_instances(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_panoptic(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(image=np.array([ [0, 1, 0, 0], @@ -698,7 +729,8 @@ def test_can_save_and_load_panoptic(self): label=4, group=3, id=3), ], attributes={'id': 1}), - DatasetItem(id=2, subset='val', image=np.ones((5, 5, 3)), + DatasetItem(id=2, subset='val', + media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(image=np.array([ [0, 0, 0, 0, 0], @@ -723,13 +755,14 @@ def test_can_save_and_load_panoptic(self): with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(CocoPanopticConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CocoPanopticConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_stuff(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 1, 0, 0], @@ -741,7 +774,8 @@ def test_can_save_and_load_stuff(self): label=4, group=3, id=3), ], attributes={'id': 2}), - DatasetItem(id=2, subset='val', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='val', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 0, 0, 0], @@ -761,7 +795,7 @@ def test_can_save_and_load_stuff(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_merge_polygons_on_loading(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((6, 10, 3)), + DatasetItem(id=1, media=Image(data=np.ones((6, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=3, id=4, group=4), @@ -772,7 +806,7 @@ def test_can_merge_polygons_on_loading(self): ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((6, 10, 3)), + DatasetItem(id=1, media=Image(data=np.ones((6, 10, 3))), annotations=[ Mask(np.array([ [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], @@ -799,7 +833,7 @@ def test_can_merge_polygons_on_loading(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_crop_covered_segments(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 1, 1, 1], @@ -816,7 +850,7 @@ def test_can_crop_covered_segments(self): ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 1, 1, 1], @@ -859,7 +893,7 @@ def test_can_convert_polygons_to_mask(self): # 1. Prepare dataset with polygon annotation (source dataset) source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((6, 10, 3)), + DatasetItem(id=1, media=Image(data=np.ones((6, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=3, id=4, group=4), @@ -871,7 +905,7 @@ def test_can_convert_polygons_to_mask(self): # 2. Prepare dataset with expected mask segmentation mode (target dataset) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((6, 10, 3)), + DatasetItem(id=1, media=Image(data=np.ones((6, 10, 3))), annotations=[ Mask(np.array([ [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], @@ -899,7 +933,7 @@ def test_can_convert_polygons_to_mask(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_convert_masks_to_polygons(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), annotations=[ Mask(np.array([ [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], @@ -914,7 +948,7 @@ def test_can_convert_masks_to_polygons(self): ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), annotations=[ Polygon( [1, 0, 3, 2, 3, 0, 1, 0], @@ -954,19 +988,22 @@ def test_can_save_and_load_images(self): @mark_requirement(Requirements.DATUM_231) def test_can_save_dataset_with_cjk_categories(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, group=1, id=1, attributes={ 'is_crowd': False }), ], attributes={'id': 1}), - DatasetItem(id=2, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(1, 0, 2, 2, label=1, group=2, id=2, attributes={ 'is_crowd': False }), ], attributes={'id': 2}), - DatasetItem(id=3, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=3, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(0, 1, 2, 2, label=2, group=3, id=3, attributes={ 'is_crowd': False }), @@ -1009,7 +1046,8 @@ def test_can_save_and_load_labels(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_keypoints(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.zeros((5, 5, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.zeros((5, 5, 3))), annotations=[ # Full instance annotations: polygon + keypoints Points([0, 0, 0, 2, 4, 1], [0, 1, 2], @@ -1039,7 +1077,8 @@ def test_can_save_and_load_keypoints(self): }) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.zeros((5, 5, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.zeros((5, 5, 3))), annotations=[ Points([0, 0, 0, 2, 4, 1], [0, 1, 2], label=3, group=1, id=1, @@ -1096,7 +1135,7 @@ def test_can_save_dataset_with_no_subsets(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_image_info(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=Image(path='1.jpg', size=(10, 15)), + DatasetItem(id=1, media=Image(path='1.jpg', size=(10, 15)), attributes={'id': 1}), ]) @@ -1107,52 +1146,54 @@ def test_can_save_dataset_with_image_info(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3)), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3))), attributes={'id': 1}), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3)), + DatasetItem(id='subdir1/1', media=Image(data=np.ones((2, 6, 3))), attributes={'id': 2}), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3)), + DatasetItem(id='subdir2/1', media=Image(data=np.ones((5, 4, 3))), attributes={'id': 3}), ]) with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(CocoImageInfoConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CocoImageInfoConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3))), attributes={'id': 1}), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), attributes={'id': 2}), ]) with TestDir() as test_dir: self._test_save_and_load(expected, - partial(CocoImageInfoConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CocoImageInfoConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_preserve_coco_ids(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='some/name1', image=np.ones((4, 2, 3)), + DatasetItem(id='some/name1', media=Image(data=np.ones((4, 2, 3))), attributes={'id': 40}), ]) with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(CocoImageInfoConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CocoImageInfoConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_annotation_attributes(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((4, 2, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4], label=5, group=1, id=1, - attributes={'is_crowd': False, 'x': 5, 'y': 'abc'}), - ], attributes={'id': 1}) + DatasetItem(id=1, media=Image(data=np.ones((4, 2, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4], label=5, group=1, id=1, + attributes={'is_crowd': False, 'x': 5, 'y': 'abc'}), + ], attributes={'id': 1} + ) ], categories=[str(i) for i in range(10)]) with TestDir() as test_dir: @@ -1162,16 +1203,20 @@ def test_annotation_attributes(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_auto_annotation_ids(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=2, image=np.ones((4, 2, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4], label=0), - ]) + DatasetItem(id=2, media=Image(data=np.ones((4, 2, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4], label=0), + ] + ) ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=2, image=np.ones((4, 2, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4], label=0, id=1, group=1, - attributes={'is_crowd': False}), - ], attributes={'id': 1}) + DatasetItem(id=2, media=Image(data=np.ones((4, 2, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4], label=0, id=1, group=1, + attributes={'is_crowd': False}), + ], attributes={'id': 1} + ) ], categories=[str(i) for i in range(10)]) with TestDir() as test_dir: @@ -1181,7 +1226,8 @@ def test_auto_annotation_ids(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_subset_can_contain_underscore(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=2, image=np.ones((4, 2, 3)), subset='subset_1', + DatasetItem(id=2, subset='subset_1', + media=Image(data=np.ones((4, 2, 3))), annotations=[Polygon([0, 0, 4, 0, 4, 4], label=0, id=1, group=1, attributes={'is_crowd': False}), ], attributes={'id': 1}) @@ -1195,16 +1241,20 @@ def test_subset_can_contain_underscore(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_reindex(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=2, image=np.ones((4, 2, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4], label=0, id=5), - ], attributes={'id': 22}) + DatasetItem(id=2, media=Image(data=np.ones((4, 2, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4], label=0, id=5), + ], attributes={'id': 22} + ) ], categories=[str(i) for i in range(10)]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=2, image=np.ones((4, 2, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4], label=0, id=1, group=1, - attributes={'is_crowd': False}), - ], attributes={'id': 1}) + DatasetItem(id=2, media=Image(data=np.ones((4, 2, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4], label=0, id=1, group=1, + attributes={'is_crowd': False}), + ], attributes={'id': 1} + ) ], categories=[str(i) for i in range(10)]) with TestDir() as test_dir: @@ -1213,31 +1263,33 @@ def test_reindex(self): test_dir, target_dataset=target_dataset) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_images_in_single_dir(self): + def test_can_save_media_in_single_dir(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((2, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((2, 4, 3))), attributes={'id': 1}), ]) with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(CocoImageInfoConverter.convert, save_images=True, + partial(CocoImageInfoConverter.convert, save_media=True, merge_images=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'images', '1.jpg'))) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_images_in_separate_dirs(self): + def test_can_save_media_in_separate_dirs(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((2, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((2, 4, 3))), attributes={'id': 1}), ]) with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(CocoImageInfoConverter.convert, save_images=True, + partial(CocoImageInfoConverter.convert, save_media=True, merge_images=False), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join( test_dir, 'images', 'train', '1.jpg'))) @@ -1245,7 +1297,7 @@ def test_can_save_images_in_separate_dirs(self): def test_inplace_save_writes_only_updated_data(self): expected = Dataset.from_iterable([ DatasetItem(1, subset='a'), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3))), + DatasetItem(2, subset='a', media=Image(data=np.ones((3, 2, 3)))), DatasetItem(2, subset='b'), ]) @@ -1254,25 +1306,27 @@ def test_inplace_save_writes_only_updated_data(self): dataset = Dataset.from_iterable([ DatasetItem(1, subset='a'), DatasetItem(2, subset='b'), - DatasetItem(3, subset='c', image=np.ones((2, 2, 3))), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 2, 3)))), ]) - dataset.export(path, 'coco', save_images=True) + dataset.export(path, 'coco', save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'image_info_a.json', 'image_info_b.json'}, set(os.listdir(osp.join(path, 'annotations')))) self.assertTrue(osp.isfile(osp.join(path, 'images', 'a', '2.jpg'))) self.assertFalse(osp.isfile(osp.join(path, 'images', 'c', '3.jpg'))) compare_datasets(self, expected, Dataset.import_from(path, 'coco'), - require_images=True, ignored_attrs={'id'}) + require_media=True, ignored_attrs={'id'}) @mark_requirement(Requirements. DATUM_BUG_425) def test_can_save_and_load_grouped_masks_and_polygons(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 0, 0, 0], @@ -1289,7 +1343,7 @@ def test_can_save_and_load_grouped_masks_and_polygons(self): ], categories=['label_1']) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 0, 0, 0], @@ -1312,7 +1366,8 @@ def test_can_save_and_load_grouped_masks_and_polygons(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_panoptic_with_meta_file(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(image=np.array([ [0, 1, 0, 0], @@ -1324,7 +1379,8 @@ def test_can_save_and_load_panoptic_with_meta_file(self): label=4, group=3, id=3), ], attributes={'id': 1}), - DatasetItem(id=2, subset='val', image=np.ones((5, 5, 3)), + DatasetItem(id=2, subset='val', + media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(image=np.array([ [0, 0, 0, 0, 1], @@ -1340,15 +1396,16 @@ def test_can_save_and_load_panoptic_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(CocoPanopticConverter.convert, save_images=True, + partial(CocoPanopticConverter.convert, save_media=True, save_dataset_meta=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_stuff_with_meta_file(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 1, 0, 0], @@ -1360,7 +1417,8 @@ def test_can_save_and_load_stuff_with_meta_file(self): label=4, group=3, id=3), ], attributes={'id': 2}), - DatasetItem(id=2, subset='val', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='val', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Mask(np.array([ [0, 0, 0, 0], @@ -1375,7 +1433,7 @@ def test_can_save_and_load_stuff_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(CocoPanopticConverter.convert, save_images=True, + partial(CocoPanopticConverter.convert, save_media=True, save_dataset_meta=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) diff --git a/tests/test_cvat_format.py b/tests/test_cvat_format.py index ce1e7f1211..501184f089 100644 --- a/tests/test_cvat_format.py +++ b/tests/test_cvat_format.py @@ -41,7 +41,7 @@ def test_can_detect_video(self): def test_can_load_image(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='img0', subset='train', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0, z_order=1, attributes={ @@ -52,7 +52,7 @@ def test_can_load_image(self): attributes={'occluded': False}), ], attributes={'frame': 0}), DatasetItem(id='img1', subset='train', - image=np.ones((10, 10, 3)), + media=Image(data=np.ones((10, 10, 3))), annotations=[ Polygon([1, 2, 3, 4, 6, 5], z_order=1, attributes={'occluded': False}), @@ -74,7 +74,7 @@ def test_can_load_image(self): def test_can_load_video(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='frame_000010', subset='annotations', - image=255 * np.ones((20, 25, 3)), + media=Image(data=255 * np.ones((20, 25, 3))), annotations=[ Bbox(3, 4, 7, 1, label=2, id=0, @@ -93,7 +93,7 @@ def test_can_load_video(self): }), ], attributes={'frame': 10}), DatasetItem(id='frame_000013', subset='annotations', - image=255 * np.ones((20, 25, 3)), + media=Image(data=255 * np.ones((20, 25, 3))), annotations=[ Bbox(7, 6, 7, 2, label=2, id=0, @@ -120,7 +120,7 @@ def test_can_load_video(self): }), ], attributes={'frame': 13}), DatasetItem(id='frame_000016', subset='annotations', - image=Image(path='frame_0000016.png', size=(20, 25)), + media=Image(path='frame_0000016.png', size=(20, 25)), annotations=[ Bbox(8, 7, 6, 10, label=2, id=0, @@ -165,7 +165,8 @@ def test_can_save_and_load(self): src_label_cat.items[2].attributes.update(['a1', 'a2', 'empty']) source_dataset = Dataset.from_iterable([ - DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), + DatasetItem(id=0, subset='s1', + media=Image(data=np.zeros((5, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=1, group=4, @@ -187,7 +188,8 @@ def test_can_save_and_load(self): ] ), - DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), + DatasetItem(id=2, subset='s2', + media=Image(data=np.zeros((5, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=1, label=3, group=4, @@ -196,7 +198,7 @@ def test_can_save_and_load(self): ] ), - DatasetItem(id=3, subset='s3', image=Image( + DatasetItem(id=3, subset='s3', media=Image( path='3.jpg', size=(2, 4))), ], categories={ AnnotationType.label: src_label_cat }) @@ -206,7 +208,8 @@ def test_can_save_and_load(self): target_label_cat.add(str(i), attributes={'common'}) target_label_cat.items[2].attributes.update(['a1', 'a2', 'empty', 'common']) target_dataset = Dataset.from_iterable([ - DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), + DatasetItem(id=0, subset='s1', + media=Image(data=np.zeros((5, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], label=1, group=4, @@ -230,7 +233,8 @@ def test_can_save_and_load(self): ], attributes={'frame': 1} ), - DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), + DatasetItem(id=2, subset='s2', + media=Image(data=np.zeros((5, 10, 3))), annotations=[ Polygon([0, 0, 4, 0, 4, 4], z_order=1, label=3, group=4, @@ -238,14 +242,14 @@ def test_can_save_and_load(self): ], attributes={'frame': 0} ), - DatasetItem(id=3, subset='s3', image=Image( + DatasetItem(id=3, subset='s3', media=Image( path='3.jpg', size=(2, 4)), attributes={'frame': 0}), ], categories={ AnnotationType.label: target_label_cat }) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(CvatConverter.convert, save_images=True), test_dir, + partial(CvatConverter.convert, save_media=True), test_dir, target_dataset=target_dataset) @mark_requirement(Requirements.DATUM_GENERAL_REQ) @@ -275,24 +279,28 @@ def test_can_allow_undeclared_attrs(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3))), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3))), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3)))), + DatasetItem(id='subdir1/1', + media=Image(data=np.ones((2, 6, 3)))), + DatasetItem(id='subdir2/1', + media=Image(data=np.ones((5, 4, 3)))), ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3)), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3))), attributes={'frame': 0}), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3)), + DatasetItem(id='subdir1/1', + media=Image(data=np.ones((2, 6, 3))), attributes={'frame': 1}), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3)), + DatasetItem(id='subdir2/1', + media=Image(data=np.ones((5, 4, 3))), attributes={'frame': 2}), ], categories=[]) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(CvatConverter.convert, save_images=True), test_dir, - target_dataset=target_dataset, require_images=True) + partial(CvatConverter.convert, save_media=True), test_dir, + target_dataset=target_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): @@ -302,8 +310,8 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): label_categories.items[2].attributes.update(['a1', 'a2', 'empty']) source_dataset = Dataset.from_iterable([ - DatasetItem(id='кириллица с пробелом', - subset='s1', image=np.zeros((5, 10, 3)), + DatasetItem(id='кириллица с пробелом', subset='s1', + media=Image(data=np.ones((5, 10, 3))), annotations=[ Label(1), ] @@ -313,8 +321,8 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): }) target_dataset = Dataset.from_iterable([ - DatasetItem(id='кириллица с пробелом', - subset='s1', image=np.zeros((5, 10, 3)), + DatasetItem(id='кириллица с пробелом', subset='s1', + media=Image(data=np.ones((5, 10, 3))), annotations=[ Label(1), ], attributes={'frame': 0} @@ -325,22 +333,22 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(CvatConverter.convert, save_images=True), test_dir, - target_dataset=target_dataset, require_images=True) + partial(CvatConverter.convert, save_media=True), test_dir, + target_dataset=target_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem('q/1', image=Image(path='q/1.JPEG', + DatasetItem('q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3))), attributes={'frame': 1}), - DatasetItem('a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem('a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), attributes={'frame': 2}), ], categories=[]) with TestDir() as test_dir: self._test_save_and_load(expected, - partial(CvatConverter.convert, save_images=True), - test_dir, require_images=True) + partial(CvatConverter.convert, save_media=True), + test_dir, require_media=True) self.assertTrue(osp.isfile( osp.join(test_dir, 'images', 'q', '1.JPEG'))) self.assertTrue(osp.isfile( @@ -349,7 +357,8 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_preserve_frame_ids(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='some/name1', image=np.ones((4, 2, 3)), + DatasetItem(id='some/name1', + media=Image(data=np.ones((4, 2, 3))), attributes={'frame': 40}), ], categories=[]) @@ -360,12 +369,14 @@ def test_preserve_frame_ids(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_reindex(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='some/name1', image=np.ones((4, 2, 3)), + DatasetItem(id='some/name1', + media=Image(data=np.ones((4, 2, 3))), attributes={'frame': 40}), ]) expected_dataset = Dataset.from_iterable([ - DatasetItem(id='some/name1', image=np.ones((4, 2, 3)), + DatasetItem(id='some/name1', + media=Image(data=np.ones((4, 2, 3))), attributes={'frame': 0}), ], categories=[]) @@ -378,7 +389,8 @@ def test_reindex(self): def test_inplace_save_writes_only_updated_data(self): expected = Dataset.from_iterable([ DatasetItem(1, subset='a'), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3))), + DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3)))), DatasetItem(2, subset='b'), ], categories=[]) @@ -388,17 +400,19 @@ def test_inplace_save_writes_only_updated_data(self): dataset = Dataset.from_iterable([ DatasetItem(1, subset='a'), DatasetItem(2, subset='b'), - DatasetItem(3, subset='c', image=np.ones((2, 2, 3))), + DatasetItem(3, subset='c', + media=Image(data=np.ones((3, 2, 3)))), ]) - dataset.export(path, 'cvat', save_images=True) + dataset.export(path, 'cvat', save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'a.xml', 'b.xml', 'images'}, set(os.listdir(path))) self.assertEqual({'2.jpg'}, set(os.listdir(osp.join(path, 'images')))) compare_datasets(self, expected, Dataset.import_from(path, 'cvat'), - require_images=True, ignored_attrs={'frame'}) + require_media=True, ignored_attrs={'frame'}) diff --git a/tests/test_dataset.py b/tests/test_dataset.py index 180bbf89ff..7936b97ab0 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -18,9 +18,9 @@ ) from datumaro.components.environment import Environment from datumaro.components.errors import ( - ConflictingCategoriesError, DatasetNotFoundError, + ConflictingCategoriesError, DatasetNotFoundError, MediaTypeError, MismatchingAttributesError, MismatchingImageInfoError, - MismatchingImagePathError, MultipleFormatsMatchError, + MismatchingMediaPathError, MultipleFormatsMatchError, NoMatchingFormatsError, RepeatedItemError, UnknownFormatError, ) from datumaro.components.extractor import ( @@ -29,7 +29,7 @@ Transform, ) from datumaro.components.launcher import Launcher -from datumaro.components.media import Image +from datumaro.components.media import Image, MediaElement, Video from datumaro.components.progress_reporting import NullProgressReporter from datumaro.util.test_utils import ( TestDir, compare_datasets, compare_datasets_strict, @@ -187,13 +187,13 @@ def test_can_detect_with_nested_folder(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_with_nested_folder_and_multiply_matches(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((3, 3, 3)), + DatasetItem(id=1, media=Image(data=np.ones((3, 3, 3))), annotations=[ Label(2) ]), ], categories=['a', 'b', 'c']) with TestDir() as test_dir: dataset_path = osp.join(test_dir, 'a', 'b') - dataset.export(dataset_path, 'coco', save_images=True) + dataset.export(dataset_path, 'coco', save_media=True) detected_format = Dataset.detect(test_dir, depth=2) @@ -308,11 +308,11 @@ def test_can_export_by_string_format_name(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_remember_export_options(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((1, 2, 3))), + DatasetItem(id=1, media=Image(data=np.ones((1, 2, 3)))), ], categories=['a']) with TestDir() as test_dir: - dataset.save(test_dir, save_images=True) + dataset.save(test_dir, save_media=True) dataset.put(dataset.get(1)) # mark the item modified for patching image_path = osp.join(test_dir, 'images', 'default', '1.jpg') @@ -320,12 +320,12 @@ def test_can_remember_export_options(self): dataset.save(test_dir) - self.assertEqual({'save_images': True}, dataset.options) + self.assertEqual({'save_media': True}, dataset.options) self.assertTrue(osp.isfile(image_path)) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_compute_length_when_created_from_scratch(self): - dataset = Dataset() + dataset = Dataset(media_type=MediaElement) dataset.put(DatasetItem(1)) dataset.put(DatasetItem(2)) @@ -432,10 +432,10 @@ def test_cant_join_different_categories(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_cant_join_different_image_info(self): s1 = Dataset.from_iterable([ - DatasetItem(1, image=Image(path='1.png', size=(2, 4))) + DatasetItem(1, media=Image(path='1.png', size=(2, 4))) ]) s2 = Dataset.from_iterable([ - DatasetItem(1, image=Image(path='1.png', size=(4, 2))) + DatasetItem(1, media=Image(path='1.png', size=(4, 2))) ]) with self.assertRaises(MismatchingImageInfoError): @@ -444,13 +444,13 @@ def test_cant_join_different_image_info(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_cant_join_different_images(self): s1 = Dataset.from_iterable([ - DatasetItem(1, image=Image(path='1.png')) + DatasetItem(1, media=Image(path='1.png')) ]) s2 = Dataset.from_iterable([ - DatasetItem(1, image=Image(path='2.png')) + DatasetItem(1, media=Image(path='2.png')) ]) - with self.assertRaises(MismatchingImagePathError): + with self.assertRaises(MismatchingMediaPathError): Dataset.from_extractors(s1, s2) @mark_requirement(Requirements.DATUM_GENERAL_REQ) @@ -465,6 +465,14 @@ def test_cant_join_different_attrs(self): with self.assertRaises(MismatchingAttributesError): Dataset.from_extractors(s1, s2) + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_cant_join_different_media_types(self): + s1 = Dataset.from_iterable([], media_type=Video) + s2 = Dataset.from_iterable([], media_type=Image) + + with self.assertRaises(MediaTypeError): + Dataset.from_extractors(s1, s2) + @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_join_datasets(self): s1 = Dataset.from_iterable([ DatasetItem(0), DatasetItem(1) ]) @@ -904,7 +912,7 @@ def __iter__(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_put(self): - dataset = Dataset() + dataset = Dataset(media_type=MediaElement) dataset.put(DatasetItem(1)) @@ -1256,7 +1264,7 @@ def test_loader(): called = True dataset = Dataset.from_iterable([ - DatasetItem(1, image=test_loader) + DatasetItem(1, media=Image(data=test_loader)) ]) with TestDir() as test_dir: @@ -1276,14 +1284,14 @@ def test_can_transform_labels(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_run_model(self): dataset = Dataset.from_iterable([ - DatasetItem(i, image=np.array([i])) + DatasetItem(i, media=Image(data=np.array([i]))) for i in range(5) ], categories=['label']) batch_size = 3 expected = Dataset.from_iterable([ - DatasetItem(i, image=np.array([i]), annotations=[ + DatasetItem(i, media=Image(data=np.array([i])), annotations=[ Label(0, attributes={ 'idx': i % batch_size, 'data': i }) ]) for i in range(5) @@ -1303,7 +1311,7 @@ def launch(self, inputs): actual = dataset.run_model(model, batch_size=batch_size) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) self.assertEqual(2, calls) @mark_requirement(Requirements.DATUM_BUG_259) @@ -1388,8 +1396,8 @@ def apply(self): self._save_dir, name + '.txt'), 'w') as f: f.write('\n') - if self._save_images and \ - item.has_image and item.image.has_data: + if self._save_media and \ + item.media and item.media.has_data: self._save_image(item, name=name) env = Environment() @@ -1397,16 +1405,19 @@ def apply(self): with TestDir() as path: dataset = Dataset.from_iterable([ - DatasetItem(1, subset='train', image=np.ones((2, 4, 3))), + DatasetItem(1, subset='train', + media=Image(data=np.ones((2, 4, 3)))), DatasetItem(2, subset='train', - image=Image(path='2.jpg', size=(3, 2))), - DatasetItem(3, subset='valid', image=np.ones((2, 2, 3))), + media=Image(path='2.jpg', size=(3, 2))), + DatasetItem(3, subset='valid', + media=Image(data=np.ones((2, 2, 3)))), ], categories=[], env=env) - dataset.export(path, 'test', save_images=True) + dataset.export(path, 'test', save_media=True) - dataset.put(DatasetItem(2, subset='train', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='train', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'valid') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({ 'train_1.txt', 'train_1.jpg', @@ -1574,7 +1585,7 @@ def split(self, count): def test_can_report_progress_from_extractor_multiple_pbars(self): class TestExtractor(SourceExtractor): def __init__(self, url, **kwargs): - super().__init__(**kwargs) + super().__init__(**kwargs, media_type=MediaElement) def __iter__(self): pbars = self._ctx.progress_reporter.split(2) @@ -1593,7 +1604,8 @@ def split(self, count): iter = mock.MagicMock() progress_reporter = TestProgressReporter() - progress_reporter.split = mock.MagicMock(TestProgressReporter.split) + progress_reporter.split = mock.MagicMock(wraps=lambda count: \ + TestProgressReporter.split(progress_reporter, count)) env = Environment() env.importers.items.clear() @@ -1608,7 +1620,7 @@ def split(self, count): def test_can_report_errors_from_extractor(self): class TestExtractor(SourceExtractor): def __init__(self, url, **kwargs): - super().__init__(**kwargs) + super().__init__(**kwargs, media_type=MediaElement) def __iter__(self): class TestError(Exception): @@ -1654,7 +1666,7 @@ class TestProgressReporter(ProgressReporter): progress_reporter.finish = mock.MagicMock() with TestDir() as test_dir: - Dataset().export(test_dir, TestConverter, + Dataset(media_type=MediaElement).export(test_dir, TestConverter, progress_reporter=progress_reporter) period_mock.assert_called_once() @@ -1682,7 +1694,7 @@ class TestErrorPolicy(ImportErrorPolicy): error_policy.report_annotation_error = mock.MagicMock() with TestDir() as test_dir: - Dataset().export(test_dir, TestConverter, + Dataset(media_type=MediaElement).export(test_dir, TestConverter, error_policy=error_policy) error_policy.report_item_error.assert_called() @@ -1692,7 +1704,7 @@ class TestErrorPolicy(ImportErrorPolicy): def test_can_pickle(self): source = Dataset.from_iterable([ DatasetItem(id=1, subset='subset', - image=np.ones((5, 4, 3)), + media=Image(data=np.ones((5, 4, 3))), annotations=[ Label(0, attributes={'a1': 1, 'a2': '2'}, id=1, group=2), Caption('hello', id=1, group=5), @@ -1713,6 +1725,52 @@ def test_can_pickle(self): compare_datasets_strict(self, source, parsed) + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_can_specify_media_type_in_ctor(self): + dataset = Dataset.from_iterable([ + DatasetItem(id=1, media=Image(data=np.ones((5, 4, 3)))) + ], media_type=Video) + + self.assertTrue(dataset.media_type() is Video) + + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_cant_put_item_with_mismatching_media_type(self): + dataset = Dataset(media_type=Video) + + with self.assertRaises(MediaTypeError): + dataset.put(DatasetItem(id=1, media=Image(data=np.ones((5, 4, 3))))) + + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_cant_change_media_type_with_transform(self): + class TestTransform(Transform): + def media_type(self): + return Image + + dataset = Dataset(media_type=Video) + + with self.assertRaises(MediaTypeError): + dataset.transform(TestTransform) + dataset.init_cache() + + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_can_get_media_type_from_extractor(self): + class TestExtractor(Extractor): + def __init__(self, **kwargs): + super().__init__(media_type=Video, **kwargs) + + dataset = Dataset.from_extractors(TestExtractor()) + + self.assertTrue(dataset.media_type() is Video) + + @mark_requirement(Requirements.DATUM_GENERIC_MEDIA) + def test_can_check_media_type_on_caching(self): + dataset = Dataset.from_iterable([ + DatasetItem(id=1, media=Image(data=np.ones((5, 4, 3)))) + ], media_type=Video) + + with self.assertRaises(MediaTypeError): + dataset.init_cache() + class DatasetItemTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_ctor_requires_id(self): @@ -1725,11 +1783,11 @@ def test_ctor_requires_id(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_ctors_with_image(): for args in [ - { 'id': 0, 'image': None }, - { 'id': 0, 'image': 'path.jpg' }, - { 'id': 0, 'image': np.array([1, 2, 3]) }, - { 'id': 0, 'image': lambda f: np.array([1, 2, 3]) }, - { 'id': 0, 'image': Image(data=np.array([1, 2, 3])) }, + { 'id': 0, 'media': None }, + { 'id': 0, 'media': Image(path='path.jpg') }, + { 'id': 0, 'media': Image(data=np.array([1, 2, 3])) }, + { 'id': 0, 'media': Image(data=lambda f: np.array([1, 2, 3])) }, + { 'id': 0, 'media': Image(data=np.array([1, 2, 3])) }, ]: DatasetItem(**args) @@ -1739,7 +1797,7 @@ class DatasetFilterTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_item_representations(): item = DatasetItem(id=1, subset='subset', - image=np.ones((5, 4, 3)), + media=Image(data=np.ones((5, 4, 3))), annotations=[ Label(0, attributes={'a1': 1, 'a2': '2'}, id=1, group=2), Caption('hello', id=1), diff --git a/tests/test_datumaro_format.py b/tests/test_datumaro_format.py index f499273c71..c9c47d9a02 100644 --- a/tests/test_datumaro_format.py +++ b/tests/test_datumaro_format.py @@ -11,13 +11,14 @@ ) from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem -from datumaro.components.media import Image +from datumaro.components.media import Image, PointCloud from datumaro.components.project import Dataset from datumaro.plugins.datumaro_format.converter import DatumaroConverter from datumaro.plugins.datumaro_format.extractor import DatumaroImporter from datumaro.util.mask_tools import generate_colormap from datumaro.util.test_utils import ( - Dimensions, TestDir, check_save_and_load, compare_datasets_strict, + Dimensions, TestDir, check_save_and_load, compare_datasets, + compare_datasets_strict, ) from .requirements import Requirements, mark_requirement @@ -47,7 +48,7 @@ def test_dataset(self): points_categories.add(index, ['cat1', 'cat2'], joints=[[0, 1]]) return Dataset.from_iterable([ - DatasetItem(id=100, subset='train', image=np.ones((10, 6, 3)), + DatasetItem(id=100, subset='train', media=Image(data=np.ones((10, 6, 3))), annotations=[ Caption('hello', id=1), Caption('world', id=2, group=5), @@ -91,7 +92,7 @@ def test_dataset(self): attributes={'a1': 5, 'a2': '42'}), DatasetItem(id=42), - DatasetItem(id=43, image=Image(path='1/b/c.qq', size=(2, 4))), + DatasetItem(id=43, media=Image(path='1/b/c.qq', size=(2, 4))), ], categories={ AnnotationType.label: label_categories, AnnotationType.mask: mask_categories, @@ -102,14 +103,14 @@ def test_dataset(self): def test_can_save_and_load(self): with TestDir() as test_dir: self._test_save_and_load(self.test_dataset, - partial(DatumaroConverter.convert, save_images=True), test_dir) + partial(DatumaroConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): with TestDir() as test_dir: self._test_save_and_load(self.test_dataset, - partial(DatumaroConverter.convert, save_images=True), test_dir, - compare=None, require_images=False) + partial(DatumaroConverter.convert, save_media=True), test_dir, + compare=None, require_media=False) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect(self): @@ -122,32 +123,35 @@ def test_can_detect(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): test_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3))), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3))), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3)))), + DatasetItem(id='subdir1/1', media=Image(data=np.ones((2, 6, 3)))), + DatasetItem(id='subdir2/1', media=Image(data=np.ones((5, 4, 3)))), ]) with TestDir() as test_dir: self._test_save_and_load(test_dataset, - partial(DatumaroConverter.convert, save_images=True), test_dir) + partial(DatumaroConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_231) def test_can_save_dataset_with_cjk_categories(self): expected = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, group=1, id=1, attributes={ 'is_crowd': False }), ], attributes={'id': 1}), - DatasetItem(id=2, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(1, 0, 2, 2, label=1, group=2, id=2, attributes={ 'is_crowd': False }), ], attributes={'id': 2}), - DatasetItem(id=3, subset='train', image=np.ones((4, 4, 3)), + DatasetItem(id=3, subset='train', + media=Image(data=np.ones((4, 4, 3))), annotations=[ Bbox(0, 1, 2, 2, label=2, group=3, id=3, attributes={ 'is_crowd': False }), @@ -160,38 +164,39 @@ def test_can_save_dataset_with_cjk_categories(self): with TestDir() as test_dir: self._test_save_and_load(expected, - partial(DatumaroConverter.convert, save_images=True), test_dir) + partial(DatumaroConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): test_dataset = Dataset.from_iterable([ - DatasetItem(id='кириллица с пробелом', image=np.ones((4, 2, 3))), + DatasetItem(id='кириллица с пробелом', + media=Image(data=np.ones((4, 2, 3)))) ]) with TestDir() as test_dir: self._test_save_and_load(test_dataset, - partial(DatumaroConverter.convert, save_images=True), + partial(DatumaroConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3))), attributes={'frame': 1}), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), attributes={'frame': 2}), ]) with TestDir() as test_dir: self._test_save_and_load(expected, - partial(DatumaroConverter.convert, save_images=True), + partial(DatumaroConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data_with_direct_changes(self): expected = Dataset.from_iterable([ DatasetItem(1, subset='a'), - DatasetItem(2, subset='a', image=np.ones((3, 2, 3))), + DatasetItem(2, subset='a', media=Image(data=np.ones((3, 2, 3)))), DatasetItem(2, subset='b'), ]) @@ -206,13 +211,15 @@ def test_inplace_save_writes_only_updated_data_with_direct_changes(self): DatasetItem(2, subset='b'), # removed subset - DatasetItem(3, subset='c', image=np.ones((2, 2, 3))), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 2, 3)))), ]) - dataset.save(path, save_images=True) + dataset.save(path, save_media=True) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'a.json', 'b.json'}, set(os.listdir(osp.join(path, 'annotations')))) @@ -225,95 +232,79 @@ def test_inplace_save_writes_only_updated_data_with_transforms(self): with TestDir() as path: expected = Dataset.from_iterable([ DatasetItem(2, subset='test'), - DatasetItem(3, subset='train', image=np.ones((2, 2, 3))), - DatasetItem(4, subset='train', image=np.ones((2, 3, 3))), - DatasetItem(5, subset='test', - point_cloud=osp.join(path, 'point_clouds', 'test', '5.pcd'), - related_images=[ - Image(data=np.ones((3, 4, 3)), - path=osp.join(path, 'test', '5', 'image_0.jpg')), - osp.join(path, 'test', '5', 'a', '5.png'), - ] - ), - ]) + DatasetItem(3, subset='train', + media=Image(data=np.ones((2, 2, 3)))), + DatasetItem(4, subset='test', + media=Image(data=np.ones((2, 3, 3)))), + ], media_type=Image) dataset = Dataset.from_iterable([ DatasetItem(1, subset='a'), DatasetItem(2, subset='b'), - DatasetItem(3, subset='c', image=np.ones((2, 2, 3))), - DatasetItem(4, subset='d', image=np.ones((2, 3, 3))), - DatasetItem(5, subset='e', point_cloud='5.pcd', - related_images=[ - np.ones((3, 4, 3)), - 'a/5.png', - ] - ), - ]) + DatasetItem(3, subset='c', media=Image(data=np.ones((2, 2, 3)))), + DatasetItem(4, subset='d', media=Image(data=np.ones((2, 3, 3)))), + ], media_type=Image) - dataset.save(path, save_images=True) + dataset.save(path, save_media=True) dataset.filter('/item[id >= 2]') dataset.transform('random_split', splits=(('train', 0.5), ('test', 0.5)), seed=42) - dataset.save(save_images=True) + dataset.save(save_media=True) - self.assertEqual( - {'images', 'annotations', 'point_clouds', 'related_images'}, + self.assertEqual({'images', 'annotations'}, set(os.listdir(path))) self.assertEqual({'train.json', 'test.json'}, set(os.listdir(osp.join(path, 'annotations')))) - self.assertEqual({'3.jpg', '4.jpg'}, + self.assertEqual({'3.jpg'}, set(os.listdir(osp.join(path, 'images', 'train')))) - self.assertEqual({'train', 'c', 'd'}, + self.assertEqual({'4.jpg'}, + set(os.listdir(osp.join(path, 'images', 'test')))) + self.assertEqual({'train', 'c', 'd', 'test'}, set(os.listdir(osp.join(path, 'images')))) self.assertEqual(set(), set(os.listdir(osp.join(path, 'images', 'c')))) self.assertEqual(set(), set(os.listdir(osp.join(path, 'images', 'd')))) - self.assertEqual({'image_0.jpg'}, - set(os.listdir(osp.join(path, 'related_images', 'test', '5')))) - compare_datasets_strict(self, expected, Dataset.load(path)) + compare_datasets(self, expected, Dataset.load(path)) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_pointcloud(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='test', point_cloud='1.pcd', - related_images= [ + DatasetItem(id=1, subset='test', + media=PointCloud('1.pcd', extra_images=[ Image(data=np.ones((5, 5, 3)), path='1/a.jpg'), Image(data=np.ones((5, 4, 3)), path='1/b.jpg'), - Image(size=(5, 3), path='1/c.jpg'), - '1/d.jpg', - ], + Image(size=(5, 3), path='1/c.jpg') + ]), annotations=[ Cuboid3d([2, 2, 2], [1, 1, 1], [3, 3, 1], id=1, group=1, label=0, attributes={'x': True} ) ]), - ], categories=['label']) + ], categories=['label'], media_type=PointCloud) with TestDir() as test_dir: target_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='test', - point_cloud=osp.join(test_dir, 'point_clouds', - 'test', '1.pcd'), - related_images= [ - Image(data=np.ones((5, 5, 3)), path=osp.join( - test_dir, 'related_images', 'test', - '1', 'image_0.jpg')), - Image(data=np.ones((5, 4, 3)), path=osp.join( - test_dir, 'related_images', 'test', - '1', 'image_1.jpg')), - Image(size=(5, 3), path=osp.join( - test_dir, 'related_images', 'test', - '1', 'image_2.jpg')), - osp.join(test_dir, 'related_images', 'test', - '1', 'image_3.jpg'), - ], + media=PointCloud(osp.join(test_dir, 'point_clouds', + 'test', '1.pcd'), + extra_images=[ + Image(data=np.ones((5, 5, 3)), path=osp.join( + test_dir, 'related_images', 'test', + '1', 'image_0.jpg')), + Image(data=np.ones((5, 4, 3)), path=osp.join( + test_dir, 'related_images', 'test', + '1', 'image_1.jpg')), + Image(size=(5, 3), path=osp.join( + test_dir, 'related_images', 'test', + '1', 'image_2.jpg')) + ]), annotations=[ Cuboid3d([2, 2, 2], [1, 1, 1], [3, 3, 1], id=1, group=1, label=0, attributes={'x': True} ) ]), - ], categories=['label']) + ], categories=['label'], media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(DatumaroConverter.convert, save_images=True), test_dir, + partial(DatumaroConverter.convert, save_media=True), test_dir, target_dataset, compare=None, dimension=Dimensions.dim_3d) diff --git a/tests/test_diff.py b/tests/test_diff.py index d34fc99794..15bf0b06d8 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -4,6 +4,7 @@ from datumaro.components.annotation import Bbox, Caption, Label, Mask, Points from datumaro.components.extractor import DEFAULT_SUBSET_NAME, DatasetItem +from datumaro.components.media import Image from datumaro.components.operations import DistanceComparator, ExactComparator from datumaro.components.project import Dataset @@ -209,47 +210,66 @@ def test_annotation_comparison(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_image_comparison(self): a = Dataset.from_iterable([ - DatasetItem(id=11, image=np.ones((5, 4, 3)), annotations=[ - Bbox(5, 6, 7, 8), - ]), - DatasetItem(id=12, image=np.ones((5, 4, 3)), annotations=[ - Bbox(1, 2, 3, 4), - Bbox(5, 6, 7, 8), - ]), - DatasetItem(id=13, image=np.ones((5, 4, 3)), annotations=[ - Bbox(9, 10, 11, 12), # mismatch - ]), - - DatasetItem(id=14, image=np.zeros((5, 4, 3)), annotations=[ - Bbox(1, 2, 3, 4), - Bbox(5, 6, 7, 8), - ], attributes={ 'a': 1 }), - - DatasetItem(id=15, image=np.zeros((5, 5, 3)), annotations=[ - Bbox(1, 2, 3, 4), - Bbox(5, 6, 7, 8), - ]), + DatasetItem(id=11, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(5, 6, 7, 8), + ] + ), + DatasetItem(id=12, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(1, 2, 3, 4), + Bbox(5, 6, 7, 8), + ] + ), + DatasetItem(id=13, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(9, 10, 11, 12), # mismatch + ] + ), + + DatasetItem(id=14, media=Image(data=np.zeros((5, 4, 3))), + annotations=[ + Bbox(1, 2, 3, 4), + Bbox(5, 6, 7, 8), + ], attributes={ 'a': 1 } + ), + + DatasetItem(id=15, media=Image(data=np.zeros((5, 5, 3))), + annotations=[ + Bbox(1, 2, 3, 4), + Bbox(5, 6, 7, 8), + ] + ), ], categories=['a', 'b', 'c', 'd']) b = Dataset.from_iterable([ - DatasetItem(id=21, image=np.ones((5, 4, 3)), annotations=[ - Bbox(5, 6, 7, 8), - ]), - DatasetItem(id=22, image=np.ones((5, 4, 3)), annotations=[ - Bbox(1, 2, 3, 4), - Bbox(5, 6, 7, 8), - ]), - DatasetItem(id=23, image=np.ones((5, 4, 3)), annotations=[ - Bbox(10, 10, 11, 12), # mismatch - ]), - - DatasetItem(id=24, image=np.zeros((5, 4, 3)), annotations=[ - Bbox(6, 6, 7, 8), # 1 ann missing, mismatch - ], attributes={ 'a': 2 }), - - DatasetItem(id=25, image=np.zeros((4, 4, 3)), annotations=[ - Bbox(6, 6, 7, 8), - ]), + DatasetItem(id=21, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(5, 6, 7, 8), + ] + ), + DatasetItem(id=22, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(1, 2, 3, 4), + Bbox(5, 6, 7, 8), + ] + ), + DatasetItem(id=23, media=Image(data=np.ones((5, 4, 3))), + annotations=[ + Bbox(10, 10, 11, 12), # mismatch + ] + ), + + DatasetItem(id=24, media=Image(data=np.zeros((5, 4, 3))), + annotations=[ + Bbox(6, 6, 7, 8), # 1 ann missing, mismatch + ], attributes={ 'a': 2 }), + + DatasetItem(id=25, media=Image(data=np.zeros((4, 4, 3))), + annotations=[ + Bbox(6, 6, 7, 8), + ] + ), ], categories=['a', 'b', 'c', 'd']) comp = ExactComparator(match_images=True) diff --git a/tests/test_extractor_tfds.py b/tests/test_extractor_tfds.py index 71659749a0..830b87dedc 100644 --- a/tests/test_extractor_tfds.py +++ b/tests/test_extractor_tfds.py @@ -60,7 +60,7 @@ def test_can_extract_mnist(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='0', subset='train', - image=tfds_example['image'].numpy().squeeze(axis=2), + media=Image(data=tfds_example['image'].numpy().squeeze(axis=2)), annotations=[Label(tfds_example['label'].numpy())], ), ], categories=tfds_info.features['label'].names) @@ -69,7 +69,7 @@ def test_can_extract_mnist(self): actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) def _test_can_extract_cifar(self, name): with mock_tfds_data(): @@ -81,7 +81,7 @@ def _test_can_extract_cifar(self, name): DatasetItem( id=tfds_example['id'].numpy().decode('UTF-8'), subset='train', - image=tfds_example['image'].numpy()[..., ::-1], + media=Image(data=tfds_example['image'].numpy()[..., ::-1]), annotations=[Label(tfds_example['label'].numpy())], ), ], categories=tfds_info.features['label'].names) @@ -90,7 +90,7 @@ def _test_can_extract_cifar(self, name): actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_extract_cifar10(self): @@ -120,7 +120,7 @@ def test_can_extract_coco(self): DatasetItem( id='test', subset='train', - image=np.ones((20, 10)), + media=Image(data=np.ones((20, 10))), annotations=[ Bbox(2, 2, 2, 4, label=5, attributes={'is_crowd': True}), @@ -133,7 +133,7 @@ def test_can_extract_coco(self): actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_extract_imagenet_v2(self): @@ -153,7 +153,7 @@ def test_can_extract_imagenet_v2(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=osp.splitext(example_file_name)[0], subset='train', - image=Image( + media=Image( data=decode_image(tfds_example['image'].numpy()), path=example_file_name, ), @@ -165,7 +165,7 @@ def test_can_extract_imagenet_v2(self): actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_extract_voc(self): @@ -192,7 +192,7 @@ def test_can_extract_voc(self): DatasetItem( id='test', subset='train', - image=np.ones((20, 10)), + media=Image(data=np.ones((20, 10))), annotations=[ Bbox(2, 2, 2, 4, label=5, attributes={ 'difficult': True, 'truncated': False, @@ -206,4 +206,4 @@ def test_can_extract_voc(self): actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, - require_images=True) + require_media=True) diff --git a/tests/test_icdar_format.py b/tests/test_icdar_format.py index fff844af1d..0fb000104f 100644 --- a/tests/test_icdar_format.py +++ b/tests/test_icdar_format.py @@ -48,13 +48,13 @@ def test_can_detect_text_segmentation(self): def test_can_import_captions(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='word_1', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Caption('PROPER'), ] ), DatasetItem(id='word_2', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Caption("Canon"), ] @@ -71,14 +71,14 @@ def test_can_import_captions(self): def test_can_import_bboxes(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='img_1', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Polygon([0, 0, 3, 1, 4, 6, 1, 7], attributes={'text': 'FOOD'}), ] ), DatasetItem(id='img_2', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(0, 0, 2, 3, attributes={'text': 'RED'}), Bbox(3, 3, 2, 3, attributes={'text': 'LION'}), @@ -96,7 +96,7 @@ def test_can_import_bboxes(self): def test_can_import_masks(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Mask(group=0, image=np.array([[0, 1, 1, 0, 0], [0, 0, 0, 0, 0]]), @@ -134,50 +134,50 @@ def _test_save_and_load(self, source_dataset, converter, test_dir, importer, def test_can_save_and_load_captions(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Caption('caption 0'), ]), DatasetItem(id=2, subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Caption('caption_1'), ]), ]) with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(IcdarWordRecognitionConverter.convert, save_images=True), + partial(IcdarWordRecognitionConverter.convert, save_media=True), test_dir, 'icdar_word_recognition') @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_captions_with_no_save_images(self): + def test_can_save_and_load_captions_with_no_save_media(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Caption('caption 0'), ]) ]) with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(IcdarWordRecognitionConverter.convert, save_images=False), + partial(IcdarWordRecognitionConverter.convert, save_media=False), test_dir, 'icdar_word_recognition') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_bboxes(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 3, 6, 10), Bbox(0, 1, 3, 5, attributes={'text': 'word 0'}), ]), DatasetItem(id=2, subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Polygon([0, 0, 3, 0, 4, 7, 1, 8], attributes={'text': 'word 1'}), Polygon([1, 2, 5, 3, 6, 8, 0, 7]), ]), DatasetItem(id=3, subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Polygon([2, 2, 8, 3, 7, 10, 2, 9], attributes={'text': 'word_2'}), Bbox(0, 2, 5, 9, attributes={'text': 'word_3'}), @@ -186,14 +186,14 @@ def test_can_save_and_load_bboxes(self): with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(IcdarTextLocalizationConverter.convert, save_images=True), + partial(IcdarTextLocalizationConverter.convert, save_media=True), test_dir, 'icdar_text_localization') @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_bboxes_with_no_save_images(self): + def test_can_save_and_load_bboxes_with_no_save_media(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=3, subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Polygon([2, 2, 8, 3, 7, 10, 2, 9], attributes={'text': 'word_2'}), Bbox(0, 2, 5, 9, attributes={'text': 'word_3'}), @@ -202,7 +202,7 @@ def test_can_save_and_load_bboxes_with_no_save_images(self): with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(IcdarTextLocalizationConverter.convert, save_images=False), + partial(IcdarTextLocalizationConverter.convert, save_media=False), test_dir, 'icdar_text_localization') @@ -210,7 +210,7 @@ def test_can_save_and_load_bboxes_with_no_save_images(self): def test_can_save_and_load_masks(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 1]]), group=1, attributes={ 'index': 1, 'color': '82 174 214', 'text': 'j', 'center': '0 3' }), @@ -219,7 +219,7 @@ def test_can_save_and_load_masks(self): 'center': '0 1' }), ]), DatasetItem(id=2, subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 0, 0, 1]]), group=0, attributes={ 'index': 3, 'color': '183 6 28', 'text': ' ', 'center': '0 5' }), @@ -238,14 +238,14 @@ def test_can_save_and_load_masks(self): with TestDir() as test_dir: self._test_save_and_load(expected_dataset, partial(IcdarTextSegmentationConverter.convert, - save_images=True), + save_media=True), test_dir, 'icdar_text_segmentation') @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_masks_with_no_save_images(self): + def test_can_save_and_load_masks_with_no_save_media(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 1]]), group=1, attributes={ 'index': 1, 'color': '82 174 214', 'text': 'j', 'center': '0 3' }), @@ -258,13 +258,13 @@ def test_can_save_and_load_masks_with_no_save_images(self): with TestDir() as test_dir: self._test_save_and_load(expected_dataset, partial(IcdarTextSegmentationConverter.convert, - save_images=False), + save_media=False), test_dir, 'icdar_text_segmentation') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_no_subsets(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((8, 8, 3)), + DatasetItem(id=1, media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 1, 3, 5), ]), @@ -279,7 +279,7 @@ def test_can_save_and_load_with_no_subsets(self): def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', - image=np.ones((8, 8, 3))), + media=Image(data=np.ones((8, 8, 3)))) ]) for importer, converter in [ @@ -289,15 +289,15 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): ]: with self.subTest(subformat=converter), TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(converter.convert, save_images=True), - test_dir, importer, require_images=True) + partial(converter.convert, save_media=True), + test_dir, importer, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), ]) @@ -308,27 +308,27 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): ]: with self.subTest(subformat=converter), TestDir() as test_dir: self._test_save_and_load(expected, - partial(converter.convert, save_images=True), - test_dir, importer, require_images=True) + partial(converter.convert, save_media=True), + test_dir, importer, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_captions_with_quotes(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((5, 5, 3)), + DatasetItem(id='1', media=Image(data=np.ones((5, 5, 3))), annotations=[Caption('caption\"')] ) ]) with TestDir() as test_dir: self._test_save_and_load(expected_dataset, - partial(IcdarWordRecognitionConverter.convert, save_images=True), + partial(IcdarWordRecognitionConverter.convert, save_media=True), test_dir, 'icdar_word_recognition') @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_segm_wo_color_attribute(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 1]]), group=1, attributes={'index': 1, 'text': 'j', 'center': '0 3', 'color': '0 128 0'}), @@ -341,7 +341,7 @@ def test_can_save_and_load_segm_wo_color_attribute(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((10, 15, 3)), annotations=[ + media=Image(data=np.ones((10, 15, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 1]]), group=1, attributes={'index': 1, 'text': 'j', 'center': '0 3', 'color': '0 128 0'}), @@ -356,5 +356,5 @@ def test_can_save_and_load_segm_wo_color_attribute(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(IcdarTextSegmentationConverter.convert, save_images=True), + partial(IcdarTextSegmentationConverter.convert, save_media=True), test_dir, 'icdar_text_segmentation', expected_dataset) diff --git a/tests/test_image_dir_format.py b/tests/test_image_dir_format.py index 6401805984..8a0cf15ed7 100644 --- a/tests/test_image_dir_format.py +++ b/tests/test_image_dir_format.py @@ -15,20 +15,20 @@ class ImageDirFormatTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_load(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((10, 6, 3))), - DatasetItem(id=2, image=np.ones((5, 4, 3))), + DatasetItem(id=1, media=Image(data=np.ones((10, 6, 3)))), + DatasetItem(id=2, media=Image(data=np.ones((5, 4, 3)))), ]) with TestDir() as test_dir: check_save_and_load(self, dataset, ImageDirConverter.convert, - test_dir, importer='image_dir', require_images=True) + test_dir, importer='image_dir', require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3))), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3))), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3)))), + DatasetItem(id='subdir1/1', media=Image(data=np.ones((2, 6, 3)))), + DatasetItem(id='subdir2/1', media=Image(data=np.ones((5, 4, 3)))), ]) with TestDir() as test_dir: @@ -38,7 +38,7 @@ def test_relative_paths(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): dataset = Dataset.from_iterable([ - DatasetItem(id='кириллица с пробелом', image=np.ones((4, 2, 3))), + DatasetItem(id='кириллица с пробелом', media=Image(data=np.ones((4, 2, 3)))), ]) with TestDir() as test_dir: @@ -48,12 +48,12 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), ]) with TestDir() as test_dir: check_save_and_load(self, dataset, ImageDirConverter.convert, - test_dir, importer='image_dir', require_images=True) + test_dir, importer='image_dir', require_media=True) diff --git a/tests/test_image_zip_format.py b/tests/test_image_zip_format.py index c39032dc43..3f401ceee6 100644 --- a/tests/test_image_zip_format.py +++ b/tests/test_image_zip_format.py @@ -26,8 +26,8 @@ def _test_can_save_and_load(self, source_dataset, test_dir, @mark_requirement(Requirements.DATUM_267) def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((10, 6, 3))), - DatasetItem(id='2', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((10, 6, 3)))), + DatasetItem(id='2', media=Image(data=np.ones((5, 4, 3)))), ]) with TestDir() as test_dir: @@ -36,7 +36,7 @@ def test_can_save_and_load(self): @mark_requirement(Requirements.DATUM_267) def test_can_save_and_load_with_custom_archive_name(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='img_1', image=np.ones((10, 10, 3))), + DatasetItem(id='img_1', media=Image(data=np.ones((10, 10, 3)))), ]) with TestDir() as test_dir: @@ -46,9 +46,9 @@ def test_can_save_and_load_with_custom_archive_name(self): @mark_requirement(Requirements.DATUM_267) def test_relative_paths(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((10, 10, 3))), - DatasetItem(id='a/2', image=np.ones((4, 5, 3))), - DatasetItem(id='a/b/3', image=np.ones((20, 10, 3))) + DatasetItem(id='1', media=Image(data=np.ones((10, 10, 3)))), + DatasetItem(id='a/2', media=Image(data=np.ones((4, 5, 3)))), + DatasetItem(id='a/b/3', media=Image(data=np.ones((20, 10, 3)))) ]) with TestDir() as test_dir: @@ -57,8 +57,8 @@ def test_relative_paths(self): @mark_requirement(Requirements.DATUM_267) def test_can_save_and_load_custom_compresion_method(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((5, 5, 3))), - DatasetItem(id='2', image=np.ones((4, 3, 3))), + DatasetItem(id='1', media=Image(data=np.ones((5, 5, 3)))), + DatasetItem(id='2', media=Image(data=np.ones((4, 3, 3)))), ]) with TestDir() as test_dir: @@ -69,16 +69,16 @@ def test_can_save_and_load_custom_compresion_method(self): def test_can_save_and_load_with_arbitrary_extensions(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='subset/1', - image=Image(data=np.ones((10, 10, 3)), path='subset/1.png')), + media=Image(data=np.ones((10, 10, 3)), path='subset/1.png')), DatasetItem(id='2', - image=Image(data=np.ones((4, 5, 3)), path='2.jpg')), + media=Image(data=np.ones((4, 5, 3)), path='2.jpg')), ]) with TestDir() as test_dir: save_image(osp.join(test_dir, '2.jpg'), - source_dataset.get('2').image.data) + source_dataset.get('2').media.data) save_image(osp.join(test_dir, 'subset', '1.png'), - source_dataset.get('subset/1').image.data, + source_dataset.get('subset/1').media.data, create_dir=True) self._test_can_save_and_load(source_dataset, test_dir) @@ -89,7 +89,7 @@ class ImageZipImporterTest(TestCase): @mark_requirement(Requirements.DATUM_267) def test_can_import(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((10, 10, 3))) + DatasetItem(id='1', media=Image(data=np.ones((10, 10, 3)))) ]) zip_path = osp.join(DUMMY_DATASET_DIR, '1.zip') @@ -100,8 +100,8 @@ def test_can_import(self): @mark_requirement(Requirements.DATUM_267) def test_can_import_from_directory(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((10, 10, 3))), - DatasetItem(id='2', image=np.ones((5, 10, 3))) + DatasetItem(id='1', media=Image(data=np.ones((10, 10, 3)))), + DatasetItem(id='2', media=Image(data=np.ones((5, 10, 3)))) ]) parsed_dataset = Dataset.import_from(DUMMY_DATASET_DIR, format='image_zip') diff --git a/tests/test_imagenet_format.py b/tests/test_imagenet_format.py index 7f4c226bf6..e241835a77 100644 --- a/tests/test_imagenet_format.py +++ b/tests/test_imagenet_format.py @@ -24,11 +24,11 @@ class ImagenetFormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='label_0/1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(0)] ), DatasetItem(id='label_1/2', - image=np.ones((10, 10, 3)), + media=Image(data=np.ones((10, 10, 3))), annotations=[Label(1)] ), ], categories={ @@ -37,22 +37,22 @@ def test_can_save_and_load(self): }) with TestDir() as test_dir: - ImagenetConverter.convert(source_dataset, test_dir, save_images=True) + ImagenetConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_multiple_labels(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(0), Label(1)] ), DatasetItem(id='2', - image=np.ones((8, 8, 3)) + media=Image(data=np.ones((8, 8, 3))) ), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -61,59 +61,59 @@ def test_can_save_and_load_with_multiple_labels(self): excepted_dataset = Dataset.from_iterable([ DatasetItem(id='label_0/1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(0)] ), DatasetItem(id='label_1/1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(1)] ), DatasetItem(id='no_label/2', - image=np.ones((8, 8, 3)) + media=Image(data=np.ones((8, 8, 3))) ), ], categories=['label_0', 'label_1']) with TestDir() as test_dir: - ImagenetConverter.convert(source_dataset, test_dir, save_images=True) + ImagenetConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet') compare_datasets(self, excepted_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id="label_0/кириллица с пробелом", - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(0)] ), ], categories=['label_0']) with TestDir() as test_dir: - ImagenetConverter.convert(source_dataset, test_dir, save_images=True) + ImagenetConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='no_label/a', image=Image(path='a.JPEG', + DatasetItem(id='no_label/a', media=Image(path='a.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='no_label/b', image=Image(path='b.bmp', + DatasetItem(id='no_label/b', media=Image(path='b.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: - ImagenetConverter.convert(dataset, test_dir, save_images=True) + ImagenetConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'imagenet_dataset') @@ -122,15 +122,15 @@ class ImagenetImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='label_0/label_0_1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(0)] ), DatasetItem(id='label_0/label_0_2', - image=np.ones((10, 10, 3)), + media=Image(data=np.ones((10, 10, 3))), annotations=[Label(0)] ), DatasetItem(id='label_1/label_1_1', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(1)] ) ], categories={ @@ -140,7 +140,7 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'imagenet') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_imagenet(self): diff --git a/tests/test_imagenet_txt_format.py b/tests/test_imagenet_txt_format.py index 53319e28ff..4b8fd8814d 100644 --- a/tests/test_imagenet_txt_format.py +++ b/tests/test_imagenet_txt_format.py @@ -25,7 +25,8 @@ def test_can_save_and_load(self): DatasetItem(id='1', subset='train', annotations=[Label(0)] ), - DatasetItem(id='2', subset='train', image=np.zeros((8, 8, 3)), + DatasetItem(id='2', subset='train', + media=Image(data=np.zeros((8, 8, 3))), annotations=[Label(1)] ), ], categories={ @@ -35,15 +36,15 @@ def test_can_save_and_load(self): with TestDir() as test_dir: ImagenetTxtConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', annotations=[Label(0)] @@ -52,7 +53,7 @@ def test_can_save_and_load_with_no_save_images(self): with TestDir() as test_dir: ImagenetTxtConverter.convert(source_dataset, test_dir, - save_images=False) + save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') @@ -71,7 +72,7 @@ def test_dataset_with_save_dataset_meta_file(self): with TestDir() as test_dir: ImagenetTxtConverter.convert(source_dataset, test_dir, - save_images=False, save_dataset_meta=True) + save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') @@ -84,7 +85,8 @@ def test_can_save_and_load_with_multiple_labels(self): DatasetItem(id='1', subset='train', annotations=[Label(1), Label(2), Label(3)] ), - DatasetItem(id='2', subset='train', image=np.zeros((2, 8, 3)), + DatasetItem(id='2', subset='train', + media=Image(data=np.zeros((2, 8, 3))), ), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -93,17 +95,17 @@ def test_can_save_and_load_with_multiple_labels(self): with TestDir() as test_dir: ImagenetTxtConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_subsets(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/c', image=np.zeros((8, 4, 3)), + DatasetItem(id='a/b/c', media=Image(data=np.zeros((8, 4, 3))), annotations=[Label(1)] ), ], categories={ @@ -113,18 +115,18 @@ def test_can_save_dataset_with_no_subsets(self): with TestDir() as test_dir: ImagenetTxtConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): dataset = Dataset.from_iterable([ DatasetItem(id="кириллица с пробелом", - image=np.ones((8, 8, 3)), + media=Image(data=np.zeros((8, 8, 3))), annotations=[Label(0), Label(1)] ), ], categories={ @@ -133,29 +135,29 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): }) with TestDir() as test_dir: - ImagenetTxtConverter.convert(dataset, test_dir, save_images=True) + ImagenetTxtConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a/1', image=Image(path='a/1.JPEG', + DatasetItem(id='a/1', media=Image(path='a/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='b/c/d/2', image=Image(path='b/c/d/2.bmp', + DatasetItem(id='b/c/d/2', media=Image(path='b/c/d/2.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: - ImagenetTxtConverter.convert(dataset, test_dir, save_images=True) + ImagenetTxtConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'imagenet_txt') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_DATASET_DIR = osp.join( osp.dirname(__file__), 'assets/imagenet_txt_dataset/basic') @@ -168,10 +170,12 @@ class ImagenetTxtImporterTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='1', subset='train', image=np.zeros((8, 6, 3)), + DatasetItem(id='1', subset='train', + media=Image(data=np.zeros((8, 6, 3))), annotations=[Label(0)] ), - DatasetItem(id='2', subset='train', image=np.zeros((2, 8, 3)), + DatasetItem(id='2', subset='train', + media=Image(data=np.zeros((2, 8, 3))), annotations=[Label(5)] ), DatasetItem(id='3', subset='train', @@ -187,7 +191,7 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'imagenet_txt') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_with_custom_labels_file(self): @@ -201,7 +205,7 @@ def test_can_import_with_custom_labels_file(self): DUMMY_DATASET_WITH_CUSTOM_LABELS_DIR, 'imagenet_txt', labels_file='synsets-alt.txt') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_with_no_labels_file(self): @@ -215,7 +219,7 @@ def test_can_import_with_no_labels_file(self): DUMMY_DATASET_WITH_NO_LABELS_DIR, 'imagenet_txt', labels='generate') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_imagenet(self): diff --git a/tests/test_kitti_format.py b/tests/test_kitti_format.py index 460d588667..287ef42fc9 100644 --- a/tests/test_kitti_format.py +++ b/tests/test_kitti_format.py @@ -64,7 +64,7 @@ def test_can_import_segmentation(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='000030_10', subset='training', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]]), id=0, label=3, attributes={'is_crowd': True}), @@ -76,7 +76,7 @@ def test_can_import_segmentation(self): ), DatasetItem(id='000030_11', subset='training', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]]), id=1, label=31, attributes={'is_crowd': False}), @@ -98,7 +98,7 @@ def test_can_import_detection(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='000030_10', subset='training', - image=np.ones((10, 10, 3)), + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, id=0, attributes={'truncated': True, 'occluded': False}), @@ -107,7 +107,7 @@ def test_can_import_detection(self): ]), DatasetItem(id='000030_11', subset='training', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 0, 2, 2, label=1, id=0, attributes={'truncated': True, 'occluded': True}), Bbox(4, 4, 2, 2, label=1, id=1, @@ -171,7 +171,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='1_2', subset='test', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=24, id=1, @@ -180,7 +180,7 @@ def __iter__(self): attributes={'is_crowd': True}), ]), DatasetItem(id='3', subset='val', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 1, 1]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 0, 1, 0, 0]]), label=5, id=0, @@ -190,19 +190,19 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_kitti_detection(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1_2', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, id=0, attributes={'truncated': False, 'occluded': False, 'score': 1.0}), ]), DatasetItem(id='1_3', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 0, 2, 2, label=1, id=0, attributes={'truncated': True, 'occluded': False, 'score': 1.0}), @@ -215,7 +215,7 @@ def test_can_save_kitti_detection(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(KittiConverter.convert, - save_images=True, tasks=KittiTask.detection), test_dir) + save_media=True, tasks=KittiTask.detection), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_kitti_segm_unpainted(self): @@ -223,7 +223,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='1_2', subset='test', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=24, id=1, @@ -236,7 +236,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True, apply_colormap=False), test_dir) + save_media=True, apply_colormap=False), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_kitti_dataset_with_no_subsets(self): @@ -244,7 +244,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='1_2', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 0]]), label=0, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 1]]), label=3, id=0, @@ -252,7 +252,7 @@ def __iter__(self): ]), DatasetItem(id='1_3', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 1, 0, 1, 0]]), label=1, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 0, 1, 0, 1]]), label=2, id=0, @@ -263,7 +263,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_kitti_dataset_without_frame_and_sequence(self): @@ -271,7 +271,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='data', subset='test', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 1]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=24, id=1, @@ -281,7 +281,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): @@ -289,7 +289,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='кириллица с пробелом', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 1]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=24, id=1, @@ -300,7 +300,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_kitti_dataset_with_complex_id(self): @@ -308,7 +308,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='a/b/1', subset='test', - image=np.ones((1, 5, 3)), annotations=[ + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 1]]), label=3, id=0, attributes={'is_crowd': True}), Mask(image=np.array([[0, 1, 1, 0, 0]]), label=24, id=1, @@ -319,7 +319,7 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_with_no_masks(self): @@ -327,25 +327,27 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='city_1_2', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), ), ]) with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(KittiConverter.convert, label_map='kitti', - save_images=True), test_dir) + save_media=True), test_dir) @mark_requirement(Requirements.DATUM_280) def test_dataset_with_source_labelmap_undefined(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, - attributes={'is_crowd': False}), - Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, - attributes={'is_crowd': False}), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, + attributes={'is_crowd': False}), + Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, + attributes={'is_crowd': False}), + ] + ) def categories(self): label_cat = LabelCategories() @@ -358,14 +360,16 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('Label_1')), - Mask(image=np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('Label_1')), + Mask(image=np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -377,18 +381,20 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(SrcExtractor(), partial(KittiConverter.convert, label_map='source', - save_images=True), test_dir, target_dataset=DstExtractor()) + save_media=True), test_dir, target_dataset=DstExtractor()) @mark_requirement(Requirements.DATUM_280) def test_dataset_with_source_labelmap_defined(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, - attributes={'is_crowd': False}), - Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, - attributes={'is_crowd': False}), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, + attributes={'is_crowd': False}), + Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, + attributes={'is_crowd': False}), + ] + ) def categories(self): label_map = OrderedDict() @@ -399,14 +405,16 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('label_1')), - Mask(image=np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('label_1')), + Mask(image=np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -418,17 +426,17 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(SrcExtractor(), partial(KittiConverter.convert, label_map='source', - save_images=True), test_dir, target_dataset=DstExtractor()) + save_media=True), test_dir, target_dataset=DstExtractor()) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image( + DatasetItem(id='a/b/c/2', media=Image( path='a/b/c/2.bmp', data=np.ones((1, 5, 3)) ), annotations=[ Mask(image=np.array([[1, 0, 0, 1, 0]]), label=0, id=0, @@ -446,8 +454,8 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), - partial(KittiConverter.convert, save_images=True), - test_dir, require_images=True) + partial(KittiConverter.convert, save_media=True), + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'default', KittiPath.IMAGES_DIR, 'a/b/c/2.bmp'))) @@ -455,11 +463,11 @@ def categories(self): KittiPath.IMAGES_DIR, 'q/1.JPEG'))) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images_segmentation(self): + def test_can_save_and_load_with_no_save_media_segmentation(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='a', image=np.ones((5, 5, 3)), + DatasetItem(id='a', media=Image(data=np.ones((5, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]] * 5), label=0, attributes={'is_crowd': True}), @@ -471,13 +479,14 @@ def __iter__(self): with TestDir() as test_dir: self._test_save_and_load(TestExtractor(), - partial(KittiConverter.convert, save_images=False, + partial(KittiConverter.convert, save_media=False, label_map='kitti'), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images_detection(self): + def test_can_save_and_load_with_no_save_media_detection(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='b', subset='val', image=np.ones((5, 5, 3)), + DatasetItem(id='b', subset='val', + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(0, 0, 3, 3, label=0, attributes={ 'truncated': True, 'occluded': False, @@ -489,7 +498,7 @@ def test_can_save_and_load_with_no_save_images_detection(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(KittiConverter.convert, tasks=KittiTask.detection, - save_images=False), test_dir) + save_media=False), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_segmentation_with_unordered_labels(self): @@ -500,7 +509,7 @@ def test_can_save_and_load_segmentation_with_unordered_labels(self): } source_dataset = Dataset.from_iterable([ - DatasetItem(id='a', image=np.ones((1, 5, 3)), + DatasetItem(id='a', media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]]), attributes={'is_crowd': False}, label=0, id=1), @@ -519,7 +528,7 @@ def test_can_save_and_load_segmentation_with_unordered_labels(self): } expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', image=np.ones((1, 5, 3)), + DatasetItem(id='a', media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]]), attributes={'is_crowd': False}, label=0, id=1), @@ -541,13 +550,13 @@ def test_can_save_and_load_segmentation_with_unordered_labels(self): def test_can_save_detection_with_score_attribute(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1_2', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, id=0, attributes={'truncated': False, 'occluded': False, 'score': 0.78}), ]), DatasetItem(id='1_3', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 0, 2, 2, label=1, id=0, attributes={'truncated': True, 'occluded': False, 'score': 0.8}), @@ -560,19 +569,19 @@ def test_can_save_detection_with_score_attribute(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(KittiConverter.convert, - save_images=True, tasks=KittiTask.detection), test_dir) + save_media=True, tasks=KittiTask.detection), test_dir) @mark_requirement(Requirements.DATUM_280) def test_can_save_detection_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1_2', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 1, 2, 2, label=0, id=0, attributes={'truncated': False, 'occluded': False, 'score': 1.0}), ]), DatasetItem(id='1_3', subset='test', - image=np.ones((10, 10, 3)), annotations=[ + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 0, 2, 2, label=1, id=0, attributes={'truncated': True, 'occluded': False, 'score': 1.0}), @@ -585,19 +594,21 @@ def test_can_save_detection_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, partial(KittiConverter.convert, - save_images=True, save_dataset_meta=True, + save_media=True, save_dataset_meta=True, tasks=KittiTask.detection), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_segmentation_with_meta_file(self): class SrcExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, - attributes={'is_crowd': False}), - Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, - attributes={'is_crowd': False}), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), label=1, id=1, + attributes={'is_crowd': False}), + Mask(image=np.array([[0, 1, 1, 0, 0]]), label=2, id=2, + attributes={'is_crowd': False}), + ] + ) def categories(self): label_map = OrderedDict() @@ -608,14 +619,16 @@ def categories(self): class DstExtractor(TestExtractorBase): def __iter__(self): - yield DatasetItem(id=1, image=np.ones((1, 5, 3)), annotations=[ - Mask(image=np.array([[1, 0, 0, 1, 1]]), - attributes={'is_crowd': False}, id=1, - label=self._label('label_1')), - Mask(image=np.array([[0, 1, 1, 0, 0]]), - attributes={'is_crowd': False}, id=2, - label=self._label('label_2')), - ]) + yield DatasetItem(id=1, media=Image(data=np.ones((1, 5, 3))), + annotations=[ + Mask(image=np.array([[1, 0, 0, 1, 1]]), + attributes={'is_crowd': False}, id=1, + label=self._label('label_1')), + Mask(image=np.array([[0, 1, 1, 0, 0]]), + attributes={'is_crowd': False}, id=2, + label=self._label('label_2')), + ] + ) def categories(self): label_map = OrderedDict() @@ -627,6 +640,6 @@ def categories(self): with TestDir() as test_dir: self._test_save_and_load(SrcExtractor(), partial(KittiConverter.convert, label_map='source', - save_images=True, save_dataset_meta=True), test_dir, + save_media=True, save_dataset_meta=True), test_dir, target_dataset=DstExtractor()) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) diff --git a/tests/test_kitti_raw_format.py b/tests/test_kitti_raw_format.py index 7a0821b195..8491ce805f 100644 --- a/tests/test_kitti_raw_format.py +++ b/tests/test_kitti_raw_format.py @@ -8,6 +8,7 @@ ) from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image, PointCloud from datumaro.components.project import Dataset from datumaro.plugins.kitti_raw_format.converter import KittiRawConverter from datumaro.plugins.kitti_raw_format.extractor import KittiRawImporter @@ -36,12 +37,12 @@ def test_can_load(self): pcd3 = osp.join(DUMMY_DATASET_DIR, 'velodyne_points', 'data', '0000000002.pcd') - image1 = osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000000.png') - image2 = osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000001.png') - image3 = osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000002.png') + image1 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000000.png')) + image2 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000001.png')) + image3 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000002.png')) expected_label_cat = LabelCategories(attributes={'occluded'}) expected_label_cat.add('bus') @@ -55,7 +56,7 @@ def test_can_load(self): Cuboid3d(position=[1, 1, 0], scale=[8.34, 23.01, -0.76], label=0, attributes={'occluded': False, 'track_id': 2}) ], - point_cloud=pcd1, related_images=[image1], + media=PointCloud(pcd1, extra_images=[image1]), attributes={'frame': 0}), DatasetItem(id='0000000001', @@ -64,7 +65,7 @@ def test_can_load(self): rotation=[1, 1, 3], label=0, attributes={'occluded': True, 'track_id': 2}) ], - point_cloud=pcd2, related_images=[image2], + media=PointCloud(pcd2, extra_images=[image2]), attributes={'frame': 1}), DatasetItem(id='0000000002', @@ -72,10 +73,10 @@ def test_can_load(self): Cuboid3d(position=[1, 2, 3], scale=[-9.41, 13.54, 0.24], label=1, attributes={'occluded': False, 'track_id': 3}) ], - point_cloud=pcd3, related_images=[image3], + media=PointCloud(pcd3, extra_images=[image3]), attributes={'frame': 2}) - ], categories={AnnotationType.label: expected_label_cat}) + ], categories={AnnotationType.label: expected_label_cat}, media_type=PointCloud) parsed_dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'kitti_raw') @@ -91,12 +92,12 @@ class KittiRawConverterTest(TestCase): pcd3 = osp.abspath(osp.join(DUMMY_DATASET_DIR, 'velodyne_points', 'data', '0000000002.pcd')) - image1 = osp.abspath(osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000000.png')) - image2 = osp.abspath(osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000001.png')) - image3 = osp.abspath(osp.join(DUMMY_DATASET_DIR, - 'IMAGE_00', 'data', '0000000002.png')) + image1 = Image(path=osp.abspath(osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000000.png'))) + image2 = Image(path=osp.abspath(osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000001.png'))) + image3 = Image(path=osp.abspath(osp.join(DUMMY_DATASET_DIR, + 'IMAGE_00', 'data', '0000000002.png'))) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def _test_save_and_load(self, source_dataset, converter, test_dir, @@ -117,7 +118,7 @@ def test_can_save_and_load(self): Cuboid3d(position=[3.4, -2.11, 4.4], label=1, attributes={'occluded': True, 'track_id': 2}) ], - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 0} ), @@ -136,10 +137,10 @@ def test_can_save_and_load(self): Cuboid3d(position=[0.4, -1, 2.24], scale=[2, 1, 2], label=0, attributes={'track_id': 3}), ], - point_cloud=self.pcd3, + media=PointCloud(self.pcd3), attributes={'frame': 2} ), - ], categories=['cat', 'dog']) + ], categories=['cat', 'dog'], media_type=PointCloud) with TestDir() as test_dir: target_label_cat = LabelCategories(attributes={'occluded'}) @@ -157,11 +158,11 @@ def test_can_save_and_load(self): attributes={ 'occluded': True, 'track_id': 2}) ], - point_cloud=osp.join(test_dir, - 'velodyne_points', 'data', '0000000000.pcd'), - related_images=[osp.join(test_dir, - 'image_00', 'data', '0000000000.png') - ], + media=PointCloud(osp.join(test_dir, + 'velodyne_points', 'data', '0000000000.pcd'), + extra_images=[Image(path=osp.join(test_dir, + 'image_00', 'data', '0000000000.png')) + ]), attributes={'frame': 0} ), @@ -183,14 +184,14 @@ def test_can_save_and_load(self): label=0, attributes={ 'occluded': False, 'track_id': 3}), ], - point_cloud=osp.join(test_dir, - 'velodyne_points', 'data', '0000000002.pcd'), + media=PointCloud(osp.join(test_dir, + 'velodyne_points', 'data', '0000000002.pcd')), attributes={'frame': 2} ), - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(KittiRawConverter.convert, save_images=True), + partial(KittiRawConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, require_point_cloud=True) @@ -198,7 +199,7 @@ def test_can_save_and_load(self): def test_preserve_frame_ids(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='abc', attributes={'frame': 40}) - ], categories=[]) + ], categories=[], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -208,11 +209,11 @@ def test_preserve_frame_ids(self): def test_reindex_frames(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='abc') - ], categories=[]) + ], categories=[], media_type=PointCloud) expected_dataset = Dataset.from_iterable([ DatasetItem(id='abc', attributes={'frame': 0}) - ], categories=[]) + ], categories=[], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -227,7 +228,7 @@ def test_requires_track_id(self): Cuboid3d(position=[0.4, -1, 2.24], label=0), ] ) - ], categories=['dog']) + ], categories=['dog'], media_type=PointCloud) with TestDir() as test_dir: with self.assertRaisesRegex(Exception, 'track_id'): @@ -241,7 +242,7 @@ def test_reindex_allows_single_annotations(self): Cuboid3d(position=[0.4, -1, 2.24], label=0), ] ) - ], categories=['dog']) + ], categories=['dog'], media_type=PointCloud) expected_dataset = Dataset.from_iterable([ DatasetItem(id='abc', @@ -250,7 +251,7 @@ def test_reindex_allows_single_annotations(self): attributes={'track_id': 1, 'occluded': False}), ], attributes={'frame': 0}) - ], categories=['dog']) + ], categories=['dog'], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -268,7 +269,7 @@ def test_can_save_and_load_attributes(self): ], attributes={'frame': 0} ) - ], categories=['cat']) + ], categories=['cat'], media_type=PointCloud) target_label_cat = LabelCategories(attributes={'occluded'}) target_label_cat.add('cat', attributes=['a', 'b']) @@ -281,7 +282,7 @@ def test_can_save_and_load_attributes(self): ], attributes={'frame': 0} ) - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -298,7 +299,7 @@ def test_can_discard_attributes(self): ], attributes={'frame': 0} ) - ], categories=['cat']) + ], categories=['cat'], media_type=PointCloud) target_label_cat = LabelCategories(attributes={'occluded'}) target_label_cat.add('cat') @@ -310,7 +311,7 @@ def test_can_discard_attributes(self): ], attributes={'frame': 0} ) - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -321,7 +322,7 @@ def test_can_discard_attributes(self): def test_can_save_and_load_without_annotations(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='0000000000', attributes={'frame': 0}) - ], categories=[]) + ], categories=[], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -335,10 +336,10 @@ def test_can_save_and_load_arbitrary_paths(self): Cuboid3d(position=[1, 2, 3], label=0, attributes={'track_id': 1}) ], - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 3} ), - ], categories=['cat']) + ], categories=['cat'], media_type=PointCloud) with TestDir() as test_dir: target_label_cat = LabelCategories(attributes={'occluded'}) @@ -349,17 +350,17 @@ def test_can_save_and_load_arbitrary_paths(self): Cuboid3d(position=[1, 2, 3], label=0, attributes={'track_id': 1, 'occluded': False}) ], - point_cloud=osp.join(test_dir, - 'velodyne_points', 'data', 'a', 'd.pcd'), - related_images=[ - osp.join(test_dir, 'image_00', 'data', 'a', 'd.png'), - ], + media=PointCloud(osp.join(test_dir, + 'velodyne_points', 'data', 'a', 'd.pcd'), + extra_images=[ + Image(path=osp.join(test_dir, 'image_00', 'data', 'a', 'd.png')), + ]), attributes={'frame': 3} ), - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(KittiRawConverter.convert, save_images=True), + partial(KittiRawConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, require_point_cloud=True) self.assertTrue(osp.isfile(osp.join( @@ -373,11 +374,11 @@ def test_can_save_and_load_multiple_related_images(self): Cuboid3d(position=[1, 2, 3], label=0, attributes={'track_id': 1}) ], - point_cloud=self.pcd1, - related_images=[self.image1, self.image2, self.image3], + media=PointCloud(self.pcd1, + extra_images=[self.image1, self.image2, self.image3]), attributes={'frame': 3} ), - ], categories=['cat']) + ], categories=['cat'], media_type=PointCloud) with TestDir() as test_dir: target_label_cat = LabelCategories(attributes={'occluded'}) @@ -388,19 +389,19 @@ def test_can_save_and_load_multiple_related_images(self): Cuboid3d(position=[1, 2, 3], label=0, attributes={'track_id': 1, 'occluded': False}) ], - point_cloud=osp.join(test_dir, - 'velodyne_points', 'data', 'a', 'd.pcd'), - related_images=[ - osp.join(test_dir, 'image_00', 'data', 'a', 'd.png'), - osp.join(test_dir, 'image_01', 'data', 'a', 'd.png'), - osp.join(test_dir, 'image_02', 'data', 'a', 'd.png'), - ], + media=PointCloud(osp.join(test_dir, + 'velodyne_points', 'data', 'a', 'd.pcd'), + extra_images=[ + Image(path=osp.join(test_dir, 'image_00', 'data', 'a', 'd.png')), + Image(path=osp.join(test_dir, 'image_01', 'data', 'a', 'd.png')), + Image(path=osp.join(test_dir, 'image_02', 'data', 'a', 'd.png')), + ]), attributes={'frame': 3} ), - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(KittiRawConverter.convert, save_images=True), + partial(KittiRawConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, require_point_cloud=True) self.assertTrue(osp.isfile(osp.join( @@ -419,22 +420,22 @@ def test_inplace_save_writes_only_updated_data(self): Cuboid3d(position=[3.5, 9.8, 0.3], label=0, attributes={'track_id': 1}) ], - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 0} ) - ], categories=['car', 'bus']) - dataset.export(path, 'kitti_raw', save_images=True) + ], categories=['car', 'bus'], media_type=PointCloud) + dataset.export(path, 'kitti_raw', save_media=True) dataset.put(DatasetItem('frame2', annotations=[ Cuboid3d(position=[1, 2, 0], label=1, attributes={'track_id': 1}) ], - point_cloud=self.pcd2, related_images=[self.image2], + media=PointCloud(self.pcd2, extra_images=[self.image2]), attributes={'frame': 1} )) dataset.remove('frame1') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'frame2.png'}, set(os.listdir( osp.join(path, 'image_00', 'data')))) @@ -449,7 +450,7 @@ def test_can_save_and_load_with_meta_file(self): Cuboid3d(position=[13.54, -9.41, 0.24], label=0, attributes={'occluded': False, 'track_id': 1}) ], - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 0} ), @@ -459,7 +460,7 @@ def test_can_save_and_load_with_meta_file(self): attributes={'track_id': 2}) ], ) - ], categories=['cat', 'dog']) + ], categories=['cat', 'dog'], media_type=PointCloud) with TestDir() as test_dir: target_label_cat = LabelCategories(attributes={'occluded'}) @@ -473,11 +474,11 @@ def test_can_save_and_load_with_meta_file(self): attributes={ 'occluded': False, 'track_id': 1}) ], - point_cloud=osp.join(test_dir, - 'velodyne_points', 'data', '0000000000.pcd'), - related_images=[osp.join(test_dir, - 'image_00', 'data', '0000000000.png') - ], + media=PointCloud(osp.join(test_dir, + 'velodyne_points', 'data', '0000000000.pcd'), + extra_images=[Image(path=osp.join(test_dir, + 'image_00', 'data', '0000000000.png')) + ]), attributes={'frame': 0} ), @@ -488,10 +489,10 @@ def test_can_save_and_load_with_meta_file(self): ], attributes={'frame': 1} ) - ], categories={AnnotationType.label: target_label_cat}) + ], categories={AnnotationType.label: target_label_cat}, media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(KittiRawConverter.convert, save_images=True, + partial(KittiRawConverter.convert, save_media=True, save_dataset_meta=True), test_dir, target_dataset=target_dataset, require_point_cloud=True) diff --git a/tests/test_labelme_format.py b/tests/test_labelme_format.py index e496cc9303..1129719412 100644 --- a/tests/test_labelme_format.py +++ b/tests/test_labelme_format.py @@ -29,7 +29,7 @@ def _test_save_and_load(self, source_dataset, converter, test_dir, def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='dir1/1', subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2, group=2), Polygon([0, 4, 4, 4, 5, 6], label=3, attributes={ @@ -52,7 +52,7 @@ def test_can_save_and_load(self): target_dataset = Dataset.from_iterable([ DatasetItem(id='dir1/1', subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=0, group=2, id=0, attributes={ @@ -89,35 +89,35 @@ def test_can_save_and_load(self): with TestDir() as test_dir: self._test_save_and_load( source_dataset, - partial(LabelMeConverter.convert, save_images=True), - test_dir, target_dataset=target_dataset, require_images=True) + partial(LabelMeConverter.convert, save_media=True), + test_dir, target_dataset=target_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a/1', image=Image(path='a/1.JPEG', + DatasetItem(id='a/1', media=Image(path='a/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='b/c/d/2', image=Image(path='b/c/d/2.bmp', + DatasetItem(id='b/c/d/2', media=Image(path='b/c/d/2.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(LabelMeConverter.convert, save_images=True), - test_dir, require_images=True) + partial(LabelMeConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Polygon([0, 4, 4, 4, 5, 6], label=3) ] ), ], categories=['label_' + str(label) for label in range(10)]) target_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Polygon([0, 4, 4, 4, 5, 6], label=0, id=0, attributes={ 'occluded': False, 'username': '' } @@ -129,52 +129,56 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): with TestDir() as test_dir: self._test_save_and_load( source_dataset, - partial(LabelMeConverter.convert, save_images=True), - test_dir, target_dataset=target_dataset, require_images=True) + partial(LabelMeConverter.convert, save_media=True), + test_dir, target_dataset=target_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', image=np.ones((4, 2, 3))), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3))), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3)))), + DatasetItem(id='subdir1/1', media=Image(data=np.ones((2, 6, 3)))), + DatasetItem(id='subdir2/1', media=Image(data=np.ones((5, 4, 3)))), - DatasetItem(id='sub/dir3/1', image=np.ones((3, 4, 3)), annotations=[ - Mask(np.array([ - [0, 1, 1, 0], - [0, 1, 1, 0], - [0, 0, 0, 0], - ]), label=1, attributes={ - 'occluded': False, 'username': 'user' - } - ) - ]), + DatasetItem(id='sub/dir3/1', media=Image(data=np.ones((3, 4, 3))), + annotations=[ + Mask(np.array([ + [0, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 0], + ]), label=1, attributes={ + 'occluded': False, 'username': 'user' + } + ) + ] + ), - DatasetItem(id='subdir3/1', subset='a', image=np.ones((5, 4, 3)), + DatasetItem(id='subdir3/1', subset='a', + media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0, attributes={ 'occluded': False, 'username': 'user' }) ]), - DatasetItem(id='subdir3/1', subset='b', image=np.ones((4, 4, 3))), + DatasetItem(id='subdir3/1', subset='b', + media=Image(data=np.ones((4, 4, 3)))) ], categories=['label1', 'label2']) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(LabelMeConverter.convert, save_images=True), - test_dir, require_images=True) + partial(LabelMeConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_to_correct_dir_with_correct_filename(self): dataset = Dataset.from_iterable([ - DatasetItem(id='dir/a', image=Image(path='dir/a.JPEG', + DatasetItem(id='dir/a', media=Image(path='dir/a.JPEG', data=np.zeros((4, 3, 3)))), ], categories=[]) with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(LabelMeConverter.convert, save_images=True), - test_dir, require_images=True) + partial(LabelMeConverter.convert, save_media=True), + test_dir, require_media=True) xml_dirpath = osp.join(test_dir, 'default/dir') self.assertEqual(os.listdir(osp.join(test_dir, 'default')), ['dir']) @@ -183,7 +187,8 @@ def test_can_save_dataset_to_correct_dir_with_correct_filename(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='sub/dir3/1', image=np.ones((3, 4, 3)), annotations=[ + DatasetItem(id='sub/dir3/1', + media=Image(data=np.ones((3, 4, 3))), annotations=[ Mask(np.array([ [0, 1, 1, 0], [0, 1, 1, 0], @@ -194,7 +199,8 @@ def test_save_and_load_with_meta_file(self): ) ]), - DatasetItem(id='subdir3/1', subset='a', image=np.ones((5, 4, 3)), + DatasetItem(id='subdir3/1', subset='a', + media=Image(data=np.ones((5, 4, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0, attributes={ 'occluded': False, 'username': 'user' @@ -204,9 +210,9 @@ def test_save_and_load_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(LabelMeConverter.convert, save_images=True, + partial(LabelMeConverter.convert, save_media=True, save_dataset_meta=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'labelme_dataset') @@ -242,7 +248,7 @@ def test_can_import(self): ] target_dataset = Dataset.from_iterable([ - DatasetItem(id='example_folder/img1', image=img1, + DatasetItem(id='example_folder/img1', media=Image(data=img1), annotations=[ Polygon([43, 34, 45, 34, 45, 37, 43, 37], label=0, id=0, @@ -308,8 +314,8 @@ def test_can_import(self): def test_can_convert(self): source_dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'label_me') with TestDir() as test_dir: - LabelMeConverter.convert(source_dataset, test_dir, save_images=True) + LabelMeConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'label_me') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) diff --git a/tests/test_lfw_format.py b/tests/test_lfw_format.py index 0182ec84c3..dbd1fd03df 100644 --- a/tests/test_lfw_format.py +++ b/tests/test_lfw_format.py @@ -21,26 +21,26 @@ class LfwFormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0002'] })] ), DatasetItem(id='name0_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0001'], 'negative_pairs': ['name1/name1_0001'] })] ), DatasetItem(id='name1_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'] })] ), DatasetItem(id='name1_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'], 'negative_pairs': ['name0/name0_0001'] @@ -50,37 +50,37 @@ def test_can_save_and_load(self): with TestDir() as test_dir: LfwConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0002'] })] ), DatasetItem(id='name0_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0001'], 'negative_pairs': ['name1/name1_0001'] })] ), DatasetItem(id='name1_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1, attributes={})] ), ], categories=['name0', 'name1']) with TestDir() as test_dir: LfwConverter.convert(source_dataset, test_dir, - save_images=False) + save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'lfw') compare_datasets(self, source_dataset, parsed_dataset) @@ -88,8 +88,8 @@ def test_can_save_and_load_with_no_save_images(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_landmarks(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='name0_0001', - subset='test', image=np.ones((2, 5, 3)), + DatasetItem(id='name0_0001', subset='test', + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(0, attributes={ 'positive_pairs': ['name0/name0_0002'] @@ -97,8 +97,8 @@ def test_can_save_and_load_with_landmarks(self): Points([0, 4, 3, 3, 2, 2, 1, 0, 3, 0], label=0), ] ), - DatasetItem(id='name0_0002', - subset='test', image=np.ones((2, 5, 3)), + DatasetItem(id='name0_0002', subset='test', + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(0), Points([0, 5, 3, 5, 2, 2, 1, 0, 3, 0], label=0), @@ -107,7 +107,7 @@ def test_can_save_and_load_with_landmarks(self): ], categories=['name0']) with TestDir() as test_dir: - LfwConverter.convert(source_dataset, test_dir, save_images=True) + LfwConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') compare_datasets(self, source_dataset, parsed_dataset) @@ -116,19 +116,19 @@ def test_can_save_and_load_with_landmarks(self): def test_can_save_and_load_with_no_subsets(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0002'] })], ), DatasetItem(id='name0_0002', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0)] ), ], categories=['name0']) with TestDir() as test_dir: - LfwConverter.convert(source_dataset, test_dir, save_images=True) + LfwConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') compare_datasets(self, source_dataset, parsed_dataset) @@ -137,27 +137,27 @@ def test_can_save_and_load_with_no_subsets(self): def test_can_save_and_load_with_no_format_names(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='a/1', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/b/2'], 'negative_pairs': ['d/4'] })], ), DatasetItem(id='b/2', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0)] ), DatasetItem(id='c/3', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1)] ), DatasetItem(id='d/4', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), ), ], categories=['name0', 'name1']) with TestDir() as test_dir: - LfwConverter.convert(source_dataset, test_dir, save_images=True) + LfwConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') compare_datasets(self, source_dataset, parsed_dataset) @@ -166,10 +166,10 @@ def test_can_save_and_load_with_no_format_names(self): def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', - image=np.ones((2, 5, 3)) + media=Image(data=np.ones((2, 5, 3))) ), DatasetItem(id='name0_0002', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'negative_pairs': ['кириллица с пробелом'] })] @@ -177,54 +177,54 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): ], categories=['name0']) with TestDir() as test_dir: - LfwConverter.convert(dataset, test_dir, save_images=True) + LfwConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a/1', image=Image( + DatasetItem(id='a/1', media=Image( path='a/1.JPEG', data=np.zeros((4, 3, 3))), annotations=[Label(0)] ), - DatasetItem(id='b/c/d/2', image=Image( + DatasetItem(id='b/c/d/2', media=Image( path='b/c/d/2.bmp', data=np.zeros((3, 4, 3))), annotations=[Label(1)] ), ], categories=['name0', 'name1']) with TestDir() as test_dir: - LfwConverter.convert(dataset, test_dir, save_images=True) + LfwConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0002'] })] ), DatasetItem(id='name0_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(0, attributes={ 'positive_pairs': ['name0/name0_0001'], 'negative_pairs': ['name1/name1_0001'] })] ), DatasetItem(id='name1_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'] })] ), DatasetItem(id='name1_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'], 'negative_pairs': ['name0/name0_0001'] @@ -234,12 +234,12 @@ def test_can_save_and_load_with_meta_file(self): with TestDir() as test_dir: LfwConverter.convert(source_dataset, test_dir, - save_images=True, save_dataset_meta=True) + save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'lfw') self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'lfw_dataset') @@ -253,7 +253,7 @@ def test_can_detect(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(0, attributes={ 'negative_pairs': ['name1/name1_0001', @@ -263,7 +263,7 @@ def test_can_import(self): ] ), DatasetItem(id='name1_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'], @@ -272,7 +272,7 @@ def test_can_import(self): ] ), DatasetItem(id='name1_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(1), Points([0, 5, 3, 5, 2, 2, 1, 0, 3, 0], label=1), @@ -288,7 +288,7 @@ def test_can_import(self): def test_can_import_without_people_file(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='name0_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(0, attributes={ 'negative_pairs': ['name1/name1_0001', @@ -298,7 +298,7 @@ def test_can_import_without_people_file(self): ] ), DatasetItem(id='name1_0001', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(1, attributes={ 'positive_pairs': ['name1/name1_0002'], @@ -307,7 +307,7 @@ def test_can_import_without_people_file(self): ] ), DatasetItem(id='name1_0002', subset='test', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), annotations=[ Label(1), Points([0, 5, 3, 5, 2, 2, 1, 0, 3, 0], label=1), diff --git a/tests/test_mapillary_vistas_format.py b/tests/test_mapillary_vistas_format.py index 5bbc3becd7..110d201292 100644 --- a/tests/test_mapillary_vistas_format.py +++ b/tests/test_mapillary_vistas_format.py @@ -8,6 +8,7 @@ AnnotationType, LabelCategories, Mask, MaskCategories, Polygon, ) from datumaro.components.dataset import Dataset, DatasetItem +from datumaro.components.media import Image from datumaro.plugins.mapillary_vistas_format.format import ( MapillaryVistasLabelMaps, make_mapillary_instance_categories, ) @@ -39,16 +40,16 @@ def test_can_import_v1_2(self): Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), label=0), Mask(image=np.array([[0, 0, 1, 1, 0]] * 5), label=1), Mask(image=np.array([[0, 0, 0, 0, 1]] * 5), label=2) - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='1', subset='train', annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), label=0, id=0), Mask(image=np.array([[0, 0, 0, 0, 1]] * 5), label=0, id=1), Mask(image=np.array([[0, 0, 1, 1, 0]] * 5), label=1, id=0), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='2', subset='train', annotations=[ Mask(image=np.array([[1, 1, 0, 1, 1]] * 5), label=1), Mask(image=np.array([[0, 0, 1, 0, 0]] * 5), label=2), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories={ AnnotationType.label: label_cat, AnnotationType.mask: mask_cat @@ -59,7 +60,7 @@ def test_can_import_v1_2(self): 'mapillary_vistas') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_with_original_config(self): @@ -68,7 +69,7 @@ def test_can_import_with_original_config(self): Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), label=0), Mask(image=np.array([[0, 0, 1, 1, 0]] * 5), label=1), Mask(image=np.array([[0, 0, 0, 0, 1]] * 5), label=2) - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories=make_mapillary_instance_categories( MapillaryVistasLabelMaps['v1.2'])) @@ -78,7 +79,7 @@ def test_can_import_with_original_config(self): ) compare_datasets(self, exptected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_v1_2_wo_images(self): @@ -100,7 +101,7 @@ def test_can_import_v1_2_wo_images(self): 'mapillary_vistas', use_original_config=True) compare_datasets(self, exptected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_v2_0_instances(self): @@ -119,7 +120,7 @@ def test_can_import_v2_0_instances(self): Mask(image=np.array([[0, 0, 0, 1, 1]] * 5), id=0, label=1), Polygon(points=[0, 0, 1, 0, 2, 0, 2, 4, 0, 4], label=0), Polygon(points=[3, 0, 4, 0, 4, 1, 4, 4, 3, 4], label=1), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='1', subset='val', annotations=[ Mask(image=np.array([[0, 0, 1, 0, 0]] * 5), id=0, label=1), Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), id=0, label=2), @@ -127,7 +128,7 @@ def test_can_import_v2_0_instances(self): Polygon(points=[2, 0, 2, 1, 2, 2, 2, 3, 2, 4], label=1), Polygon(points=[0, 0, 1, 0, 1, 4, 4, 0, 0, 0], label=2), Polygon(points=[3, 0, 4, 0, 4, 4, 3, 4, 3, 0], label=2), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='2', subset='train', annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]] * 5), id=0, label=0), Mask(image=np.array([[0, 0, 1, 0, 0]] * 5), id=1, label=0), @@ -139,7 +140,7 @@ def test_can_import_v2_0_instances(self): Polygon(points=[4, 0, 4, 1, 4, 2, 4, 3, 4, 4], label=0), Polygon(points=[1, 0, 1, 1, 1, 2, 1, 3, 1, 4], label=1), Polygon(points=[3, 0, 3, 1, 3, 2, 3, 3, 3, 4], label=1), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories={ AnnotationType.label: label_cat, AnnotationType.mask: mask_cat @@ -149,7 +150,7 @@ def test_can_import_v2_0_instances(self): 'mapillary_vistas_instances') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_v2_0_panoptic(self): @@ -173,7 +174,7 @@ def test_can_import_v2_0_panoptic(self): label=1, attributes={'is_crowd': False}), Polygon(points=[0, 0, 1, 0, 2, 0, 2, 4, 0, 4], label=0), Polygon(points=[3, 0, 4, 0, 4, 1, 4, 4, 3, 4], label=1), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='1', subset='val', annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), id=1, group=1, label=2, attributes={'is_crowd': False}), @@ -184,7 +185,7 @@ def test_can_import_v2_0_panoptic(self): Polygon(points=[2, 0, 2, 1, 2, 2, 2, 3, 2, 4], label=1), Polygon(points=[0, 0, 1, 0, 1, 4, 4, 0, 0, 0], label=2), Polygon(points=[3, 0, 4, 0, 4, 4, 3, 4, 3, 0], label=2), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='2', subset='train', annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]] * 5), id=1, group=1, label=0, attributes={'is_crowd': False}), @@ -201,7 +202,7 @@ def test_can_import_v2_0_panoptic(self): Polygon(points=[4, 0, 4, 1, 4, 2, 4, 3, 4, 4], label=0), Polygon(points=[1, 0, 1, 1, 1, 2, 1, 3, 1, 4], label=1), Polygon(points=[3, 0, 3, 1, 3, 2, 3, 3, 3, 4], label=1), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories={ AnnotationType.label: label_cat, AnnotationType.mask: mask_cat @@ -211,7 +212,7 @@ def test_can_import_v2_0_panoptic(self): 'mapillary_vistas_panoptic') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_v2_0_panoptic_with_keeping_category_ids(self): @@ -235,7 +236,7 @@ def test_can_import_v2_0_panoptic_with_keeping_category_ids(self): label=10, attributes={'is_crowd': False}), Polygon(points=[0, 0, 1, 0, 2, 0, 2, 4, 0, 4], label=1), Polygon(points=[3, 0, 4, 0, 4, 1, 4, 4, 3, 4], label=10), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='1', subset='val', annotations=[ Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), id=1, group=1, label=100, attributes={'is_crowd': False}), @@ -246,7 +247,7 @@ def test_can_import_v2_0_panoptic_with_keeping_category_ids(self): Polygon(points=[2, 0, 2, 1, 2, 2, 2, 3, 2, 4], label=10), Polygon(points=[0, 0, 1, 0, 1, 4, 4, 0, 0, 0], label=100), Polygon(points=[3, 0, 4, 0, 4, 4, 3, 4, 3, 0], label=100), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='2', subset='train', annotations=[ Mask(image=np.array([[1, 0, 0, 0, 0]] * 5), id=1, group=1, label=1, attributes={'is_crowd': False}), @@ -263,7 +264,7 @@ def test_can_import_v2_0_panoptic_with_keeping_category_ids(self): Polygon(points=[4, 0, 4, 1, 4, 2, 4, 3, 4, 4], label=1), Polygon(points=[1, 0, 1, 1, 1, 2, 1, 3, 1, 4], label=10), Polygon(points=[3, 0, 3, 1, 3, 2, 3, 3, 3, 4], label=10), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories={ AnnotationType.label: label_cat, AnnotationType.mask: mask_cat @@ -273,7 +274,7 @@ def test_can_import_v2_0_panoptic_with_keeping_category_ids(self): 'mapillary_vistas_panoptic', keep_original_category_ids=True) compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_v2_0_panoptic_wo_images(self): @@ -321,7 +322,7 @@ def test_can_import_v2_0_panoptic_wo_images(self): 'mapillary_vistas_panoptic') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_with_meta_file(self): @@ -338,11 +339,11 @@ def test_can_import_with_meta_file(self): Mask(image=np.array([[1, 1, 0, 0, 0]] * 5), label=0, id=0), Mask(image=np.array([[0, 0, 0, 0, 1]] * 5), label=0, id=1), Mask(image=np.array([[0, 0, 1, 1, 0]] * 5), label=1, id=0), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), DatasetItem(id='2', subset='train', annotations=[ Mask(image=np.array([[1, 1, 0, 1, 1]] * 5), label=1), Mask(image=np.array([[0, 0, 1, 0, 0]] * 5), label=2), - ], image=np.ones((5, 5, 3))), + ], media=Image(data=np.ones((5, 5, 3)))), ], categories={ AnnotationType.label: label_cat, AnnotationType.mask: mask_cat @@ -353,4 +354,4 @@ def test_can_import_with_meta_file(self): 'mapillary_vistas') compare_datasets(self, expected_dataset, imported_dataset, - require_images=True) + require_media=True) diff --git a/tests/test_market1501_format.py b/tests/test_market1501_format.py index d2751d54a1..b3cd2594a1 100644 --- a/tests/test_market1501_format.py +++ b/tests/test_market1501_format.py @@ -20,24 +20,24 @@ class Market1501FormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='0001_c2s3_000001_00', - subset='query', image=np.ones((2, 5, 3)), + subset='query', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 1, 'person_id': '0001', 'track_id': 3, 'frame_id': 1, 'bbox_id': 0, 'query': True} ), DatasetItem(id='0002_c4s2_000002_00', - subset='test', image=np.ones((2, 5, 3)), + subset='test', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 3, 'person_id': '0002', 'track_id': 2, 'frame_id': 2, 'bbox_id': 0, 'query': False} ), DatasetItem(id='0001_c1s1_000003_00', - subset='test', image=np.ones((2, 5, 3)), + subset='test', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 0, 'person_id': '0001', 'track_id': 1, 'frame_id': 3, 'bbox_id': 0, 'query': False} ), ]) with TestDir() as test_dir: - Market1501Converter.convert(source_dataset, test_dir, save_images=True) + Market1501Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, source_dataset, parsed_dataset) @@ -46,14 +46,14 @@ def test_can_save_and_load(self): def test_can_save_dataset_with_no_subsets(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='0001_c2s3_000001_00', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 1, 'person_id': '0001', 'track_id': 3, 'frame_id': 1, 'bbox_id': 0, 'query': False} ), ]) with TestDir() as test_dir: - Market1501Converter.convert(source_dataset, test_dir, save_images=True) + Market1501Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, source_dataset, parsed_dataset) @@ -62,38 +62,38 @@ def test_can_save_dataset_with_no_subsets(self): def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 0, 'person_id': '0001', 'query': False} ), ]) expected_dataset = Dataset.from_iterable([ DatasetItem(id='0001_c1s1_000000_00', - image=np.ones((2, 5, 3)), + media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 0, 'person_id': '0001', 'track_id': 1, 'frame_id': 0, 'bbox_id': 0, 'query': False} ), ]) with TestDir() as test_dir: - Market1501Converter.convert(source_dataset, test_dir, save_images=True) + Market1501Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, expected_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_dataset_with_no_save_images(self): + def test_can_save_dataset_with_no_save_media(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='0001_c2s3_000001_00', - subset='query', image=np.ones((2, 5, 3)), + subset='query', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 1, 'person_id': '0001', 'track_id': 3, 'frame_id': 1, 'bbox_id': 0, 'query': True} ), ]) with TestDir() as test_dir: - Market1501Converter.convert(source_dataset, test_dir, save_images=False) + Market1501Converter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, source_dataset, parsed_dataset) @@ -101,12 +101,12 @@ def test_can_save_dataset_with_no_save_images(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem(id='c/0001_c1s1_000000_00', image=Image( + DatasetItem(id='c/0001_c1s1_000000_00', media=Image( path='c/0001_c1s1_0000_00.JPEG', data=np.zeros((4, 3, 3))), attributes={'camera_id': 0, 'person_id': '0001', 'track_id': 1, 'frame_id': 0, 'bbox_id': 0, 'query': False} ), - DatasetItem(id='a/b/0002_c2s2_000001_00', image=Image( + DatasetItem(id='a/b/0002_c2s2_000001_00', media=Image( path='a/b/0002_c2s2_0001_00.bmp', data=np.zeros((3, 4, 3))), attributes={'camera_id': 1, 'person_id': '0002', 'track_id': 2, 'frame_id': 1, 'bbox_id': 0, 'query': False} @@ -114,22 +114,22 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): ]) with TestDir() as test_dir: - Market1501Converter.convert(expected, test_dir, save_images=True) + Market1501Converter.convert(expected, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, expected, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_attributes(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='test1', - subset='test', image=np.ones((2, 5, 3)), + subset='test', media=Image(data=np.ones((2, 5, 3))), ), ]) with TestDir() as test_dir: - Market1501Converter.convert(source_dataset, test_dir, save_images=False) + Market1501Converter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'market1501') compare_datasets(self, source_dataset, parsed_dataset) @@ -146,17 +146,17 @@ def test_can_detect(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='0001_c2s3_000111_00', - subset='query', image=np.ones((2, 5, 3)), + subset='query', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 1, 'person_id': '0001', 'track_id': 3, 'frame_id': 111, 'bbox_id': 0, 'query': True} ), DatasetItem(id='0001_c1s1_001051_00', - subset='test', image=np.ones((2, 5, 3)), + subset='test', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 0, 'person_id': '0001', 'track_id': 1, 'frame_id': 1051, 'bbox_id': 0, 'query': False} ), DatasetItem(id='0002_c1s3_000151_00', - subset='train', image=np.ones((2, 5, 3)), + subset='train', media=Image(data=np.ones((2, 5, 3))), attributes = {'camera_id': 0, 'person_id': '0002', 'track_id': 3, 'frame_id': 151, 'bbox_id': 0, 'query': False} ), diff --git a/tests/test_mars_format.py b/tests/test_mars_format.py index 8f04dff843..9e358cdecf 100644 --- a/tests/test_mars_format.py +++ b/tests/test_mars_format.py @@ -10,6 +10,7 @@ from datumaro.components.annotation import Label from datumaro.components.dataset import Dataset, DatasetItem from datumaro.components.environment import Environment +from datumaro.components.media import Image from datumaro.plugins.mars_format import MarsImporter from datumaro.util.test_utils import compare_datasets @@ -22,17 +23,20 @@ class MarsImporterTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='0001C1T0001F001', image=np.ones((10, 10, 3)), + DatasetItem(id='0001C1T0001F001', + media=Image(data=np.ones((10, 10, 3))), subset='train', annotations=[Label(label=2)], attributes={'person_id': '0001', 'camera_id': 1, 'track_id': 1, 'frame_id': 1} ), - DatasetItem(id='0000C6T0101F001', image=np.ones((10, 10, 3)), + DatasetItem(id='0000C6T0101F001', + media=Image(data=np.ones((10, 10, 3))), subset='train', annotations=[Label(label=1)], attributes={'person_id': '0000', 'camera_id': 6, 'track_id': 101, 'frame_id': 1} ), - DatasetItem(id='00-1C2T0081F201', image=np.ones((10, 10, 3)), + DatasetItem(id='00-1C2T0081F201', + media=Image(data=np.ones((10, 10, 3))), subset='test', annotations=[Label(label=0)], attributes={'person_id': '00-1', 'camera_id': 2, 'track_id': 81, 'frame_id': 201} @@ -40,7 +44,7 @@ def test_can_import(self): ], categories=['00-1', '0000', '0001']) imported_dataset = Dataset.import_from(DUMMY_MARS_DATASET, 'mars') - compare_datasets(self, expected_dataset, imported_dataset, require_images=True) + compare_datasets(self, expected_dataset, imported_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect(self): diff --git a/tests/test_mnist_csv_format.py b/tests/test_mnist_csv_format.py index f660763db8..04a8e1bdd2 100644 --- a/tests/test_mnist_csv_format.py +++ b/tests/test_mnist_csv_format.py @@ -23,14 +23,14 @@ class MnistCsvFormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)) + media=Image(data=np.ones((28, 28))) ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ) ], categories={ @@ -39,11 +39,11 @@ def test_can_save_and_load(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(source_dataset, test_dir, save_images=True) + MnistCsvConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_without_saving_images(self): @@ -60,19 +60,19 @@ def test_can_save_and_load_without_saving_images(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(source_dataset, test_dir, save_images=False) + MnistCsvConverter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_different_image_size(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=0, image=np.ones((10, 8)), + DatasetItem(id=0, media=Image(data=np.ones((10, 8))), annotations=[Label(0)] ), - DatasetItem(id=1, image=np.ones((4, 3)), + DatasetItem(id=1, media=Image(data=np.ones((4, 3))), annotations=[Label(1)] ), ], categories={ @@ -81,17 +81,17 @@ def test_can_save_and_load_with_different_image_size(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(source_dataset, test_dir, save_images=True) + MnistCsvConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id="кириллица с пробелом", - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), ], categories={ @@ -100,18 +100,18 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(source_dataset, test_dir, save_images=True) + MnistCsvConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((28, 28)))), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((28, 28)))), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -119,11 +119,11 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(dataset, test_dir, save_images=True) + MnistCsvConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_empty_image(self): @@ -136,18 +136,18 @@ def test_can_save_and_load_empty_image(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(dataset, test_dir, save_images=True) + MnistCsvConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_other_labels(self): dataset = Dataset.from_iterable([ - DatasetItem(id=0, image=np.ones((28, 28)), + DatasetItem(id=0, media=Image(data=np.ones((28, 28))), annotations=[Label(0)]), - DatasetItem(id=1, image=np.ones((28, 28)), + DatasetItem(id=1, media=Image(data=np.ones((28, 28))), annotations=[Label(1)]) ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -155,24 +155,24 @@ def test_can_save_and_load_with_other_labels(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(dataset, test_dir, save_images=True) + MnistCsvConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)) + media=Image(data=np.ones((28, 28))) ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ) ], categories={ @@ -181,13 +181,13 @@ def test_can_save_and_load_with_meta_file(self): }) with TestDir() as test_dir: - MnistCsvConverter.convert(source_dataset, test_dir, save_images=True, + MnistCsvConverter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist_csv') self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'mnist_csv_dataset') @@ -196,23 +196,23 @@ class MnistCsvImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(2)] ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ), DatasetItem(id=0, subset='train', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(5)] ), DatasetItem(id=1, subset='train', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(7)] ) ], categories={ diff --git a/tests/test_mnist_format.py b/tests/test_mnist_format.py index 61860a1d07..cd937114c1 100644 --- a/tests/test_mnist_format.py +++ b/tests/test_mnist_format.py @@ -21,14 +21,14 @@ class MnistFormatTest(TestCase): def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)) + media=Image(data=np.ones((28, 28))) ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ) ], categories={ @@ -37,11 +37,11 @@ def test_can_save_and_load(self): }) with TestDir() as test_dir: - MnistConverter.convert(source_dataset, test_dir, save_images=True) + MnistConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_without_saving_images(self): @@ -58,19 +58,19 @@ def test_can_save_and_load_without_saving_images(self): }) with TestDir() as test_dir: - MnistConverter.convert(source_dataset, test_dir, save_images=False) + MnistConverter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_different_image_size(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=0, image=np.ones((3, 4)), + DatasetItem(id=0, media=Image(data=np.ones((3, 4))), annotations=[Label(0)] ), - DatasetItem(id=1, image=np.ones((2, 2)), + DatasetItem(id=1, media=Image(data=np.ones((2, 2))), annotations=[Label(1)] ), ], categories={ @@ -79,17 +79,17 @@ def test_can_save_and_load_with_different_image_size(self): }) with TestDir() as test_dir: - MnistConverter.convert(source_dataset, test_dir, save_images=True) + MnistConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id="кириллица с пробелом", - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), ], categories={ @@ -98,18 +98,18 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): }) with TestDir() as test_dir: - MnistConverter.convert(source_dataset, test_dir, save_images=True) + MnistConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((28, 28)))), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((28, 28)))), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -117,11 +117,11 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): }) with TestDir() as test_dir: - MnistConverter.convert(dataset, test_dir, save_images=True) + MnistConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_empty_image(self): @@ -134,18 +134,18 @@ def test_can_save_and_load_empty_image(self): }) with TestDir() as test_dir: - MnistConverter.convert(dataset, test_dir, save_images=True) + MnistConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_other_labels(self): dataset = Dataset.from_iterable([ - DatasetItem(id=0, image=np.ones((28, 28)), + DatasetItem(id=0, media=Image(data=np.ones((28, 28))), annotations=[Label(0)]), - DatasetItem(id=1, image=np.ones((28, 28)), + DatasetItem(id=1, media=Image(data=np.ones((28, 28))), annotations=[Label(1)]) ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -153,24 +153,24 @@ def test_can_save_and_load_with_other_labels(self): }) with TestDir() as test_dir: - MnistConverter.convert(dataset, test_dir, save_images=True) + MnistConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)) + media=Image(data=np.ones((28, 28))) ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ) ], categories={ @@ -179,13 +179,13 @@ def test_can_save_and_load_with_meta_file(self): }) with TestDir() as test_dir: - MnistConverter.convert(source_dataset, test_dir, save_images=True, + MnistConverter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'mnist') self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'mnist_dataset') @@ -194,23 +194,23 @@ class MnistImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=0, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(0)] ), DatasetItem(id=1, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(2)] ), DatasetItem(id=2, subset='test', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(1)] ), DatasetItem(id=0, subset='train', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(5)] ), DatasetItem(id=1, subset='train', - image=np.ones((28, 28)), + media=Image(data=np.ones((28, 28))), annotations=[Label(7)] ) ], categories={ diff --git a/tests/test_mot_format.py b/tests/test_mot_format.py index 6dc952a80c..a281600101 100644 --- a/tests/test_mot_format.py +++ b/tests/test_mot_format.py @@ -28,7 +28,7 @@ def _test_save_and_load(self, source_dataset, converter, test_dir, def test_can_save_bboxes(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2, attributes={ 'occluded': True, @@ -43,14 +43,14 @@ def test_can_save_bboxes(self): ), DatasetItem(id=2, subset='val', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(1, 2, 4, 2, label=3), ] ), DatasetItem(id=3, subset='test', - image=np.ones((5, 4, 3)) * 3, + media=Image(data=np.ones((5, 4, 3)) * 3), ), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -59,7 +59,7 @@ def test_can_save_bboxes(self): target_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2, attributes={ 'occluded': True, @@ -80,7 +80,7 @@ def test_can_save_bboxes(self): ), DatasetItem(id=2, - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(1, 2, 4, 2, label=3, attributes={ 'occluded': False, @@ -91,7 +91,7 @@ def test_can_save_bboxes(self): ), DatasetItem(id=3, - image=np.ones((5, 4, 3)) * 3, + media=Image(data=np.ones((5, 4, 3)) * 3), ), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -100,14 +100,14 @@ def test_can_save_bboxes(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(MotSeqGtConverter.convert, save_images=True), - test_dir, target_dataset=target_dataset, require_images=True) + partial(MotSeqGtConverter.convert, save_media=True), + test_dir, target_dataset=target_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=0, attributes={ 'occluded': True, @@ -118,7 +118,7 @@ def test_can_save_and_load_with_no_save_images(self): ), DatasetItem(id=2, - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(1, 2, 4, 2, label=1, attributes={ 'occluded': False, @@ -131,13 +131,13 @@ def test_can_save_and_load_with_no_save_images(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(MotSeqGtConverter.convert, save_images=False), + partial(MotSeqGtConverter.convert, save_media=False), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem('1', image=Image( + DatasetItem('1', media=Image( path='1.JPEG', data=np.zeros((4, 3, 3))), annotations=[ Bbox(0, 4, 4, 8, label=0, attributes={ @@ -147,21 +147,21 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): }), ] ), - DatasetItem('2', image=Image( + DatasetItem('2', media=Image( path='2.bmp', data=np.zeros((3, 4, 3))), ), ], categories=['a']) with TestDir() as test_dir: self._test_save_and_load(expected, - partial(MotSeqGtConverter.convert, save_images=True), - test_dir, require_images=True) + partial(MotSeqGtConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=0, attributes={ 'occluded': True, @@ -172,7 +172,7 @@ def test_can_save_and_load_with_meta_file(self): ), DatasetItem(id=2, - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(1, 2, 4, 2, label=1, attributes={ 'occluded': False, @@ -185,9 +185,9 @@ def test_can_save_and_load_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(MotSeqGtConverter.convert, save_images=True, + partial(MotSeqGtConverter.convert, save_media=True, save_dataset_meta=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', @@ -199,7 +199,7 @@ class MotImporterTest(TestCase): def _define_expected_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2, attributes={ 'occluded': False, diff --git a/tests/test_mots_format.py b/tests/test_mots_format.py index fbc659ca78..eea3674eb9 100644 --- a/tests/test_mots_format.py +++ b/tests/test_mots_format.py @@ -29,71 +29,85 @@ def _test_save_and_load(self, source_dataset, converter, test_dir, @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_masks(self): source = Dataset.from_iterable([ - DatasetItem(id=1, subset='a', image=np.ones((5, 1)), annotations=[ - # overlapping masks, the first should be truncated - # the first and third are different instances - Mask(np.array([[0, 0, 0, 1, 0]]), label=3, z_order=3, - attributes={'track_id': 1}), - Mask(np.array([[0, 1, 1, 1, 0]]), label=2, z_order=1, - attributes={'track_id': 2}), - Mask(np.array([[1, 1, 0, 0, 0]]), label=3, z_order=2, - attributes={'track_id': 3}), - ]), - DatasetItem(id=2, subset='a', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[1, 0, 0, 0, 0]]), label=3, - attributes={'track_id': 2}), - ]), - DatasetItem(id=3, subset='b', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[0, 1, 0, 0, 0]]), label=0, - attributes={'track_id': 1}), - ]), + DatasetItem(id=1, subset='a', media=Image(data=np.ones((5, 1))), + annotations=[ + # overlapping masks, the first should be truncated + # the first and third are different instances + Mask(np.array([[0, 0, 0, 1, 0]]), label=3, z_order=3, + attributes={'track_id': 1}), + Mask(np.array([[0, 1, 1, 1, 0]]), label=2, z_order=1, + attributes={'track_id': 2}), + Mask(np.array([[1, 1, 0, 0, 0]]), label=3, z_order=2, + attributes={'track_id': 3}), + ] + ), + DatasetItem(id=2, subset='a', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[1, 0, 0, 0, 0]]), label=3, + attributes={'track_id': 2}), + ] + ), + DatasetItem(id=3, subset='b', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[0, 1, 0, 0, 0]]), label=0, + attributes={'track_id': 1}), + ] + ), ], categories=['a', 'b', 'c', 'd']) target = Dataset.from_iterable([ - DatasetItem(id=1, subset='a', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[0, 0, 0, 1, 0]]), label=3, - attributes={'track_id': 1}), - Mask(np.array([[0, 0, 1, 0, 0]]), label=2, - attributes={'track_id': 2}), - Mask(np.array([[1, 1, 0, 0, 0]]), label=3, - attributes={'track_id': 3}), - ]), - DatasetItem(id=2, subset='a', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[1, 0, 0, 0, 0]]), label=3, - attributes={'track_id': 2}), - ]), - DatasetItem(id=3, subset='b', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[0, 1, 0, 0, 0]]), label=0, - attributes={'track_id': 1}), - ]), + DatasetItem(id=1, subset='a', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[0, 0, 0, 1, 0]]), label=3, + attributes={'track_id': 1}), + Mask(np.array([[0, 0, 1, 0, 0]]), label=2, + attributes={'track_id': 2}), + Mask(np.array([[1, 1, 0, 0, 0]]), label=3, + attributes={'track_id': 3}), + ] + ), + DatasetItem(id=2, subset='a', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[1, 0, 0, 0, 0]]), label=3, + attributes={'track_id': 2}), + ] + ), + DatasetItem(id=3, subset='b', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[0, 1, 0, 0, 0]]), label=0, + attributes={'track_id': 1}), + ] + ), ], categories=['a', 'b', 'c', 'd']) with TestDir() as test_dir: self._test_save_and_load(source, - partial(MotsPngConverter.convert, save_images=True), + partial(MotsPngConverter.convert, save_media=True), test_dir, target_dataset=target) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='a', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[1, 1, 0, 0, 0]]), label=0, - attributes={'track_id': 3}), - Mask(np.array([[0, 0, 1, 1, 1]]), label=1, - attributes={'track_id': 3}), - ]), + DatasetItem(id=1, subset='a', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[1, 1, 0, 0, 0]]), label=0, + attributes={'track_id': 3}), + Mask(np.array([[0, 0, 1, 1, 1]]), label=1, + attributes={'track_id': 3}), + ] + ), ], categories=['label_0', 'label_1']) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(MotsPngConverter.convert, save_images=False), + partial(MotsPngConverter.convert, save_media=False), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', subset='a', - image=np.ones((5, 1)), annotations=[ + media=Image(data=np.ones((5, 1))), annotations=[ Mask(np.array([[1, 0, 0, 0, 0]]), label=0, attributes={'track_id': 2}), ]), @@ -101,20 +115,20 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): with TestDir() as test_dir: self._test_save_and_load(source, - partial(MotsPngConverter.convert, save_images=True), - test_dir, require_images=True) + partial(MotsPngConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): expected = Dataset.from_iterable([ - DatasetItem('q/1', image=Image( + DatasetItem('q/1', media=Image( path='q/1.JPEG', data=np.zeros((4, 3, 3))), annotations=[ Mask(np.array([[0, 1, 0, 0, 0]]), label=0, attributes={'track_id': 1}), ] ), - DatasetItem('a/b/c/2', image=Image( + DatasetItem('a/b/c/2', media=Image( path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), annotations=[ Mask(np.array([[0, 1, 0, 0, 0]]), label=0, @@ -125,13 +139,14 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): with TestDir() as test_dir: self._test_save_and_load(expected, - partial(MotsPngConverter.convert, save_images=True), - test_dir, require_images=True) + partial(MotsPngConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='a', image=np.ones((5, 1)), annotations=[ + DatasetItem(id=1, subset='a', + media=Image(data=np.ones((5, 1))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=0, attributes={'track_id': 3}), Mask(np.array([[0, 0, 1, 1, 1]]), label=1, @@ -141,9 +156,9 @@ def test_can_save_and_load_with_meta_file(self): with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(MotsPngConverter.convert, save_images=True, + partial(MotsPngConverter.convert, save_media=True, save_dataset_meta=True), - test_dir, require_images=True) + test_dir, require_media=True) self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) class MotsImporterTest(TestCase): @@ -155,22 +170,28 @@ def test_can_detect(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import(self): target = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[0, 0, 0, 1, 0]]), label=3, - attributes={'track_id': 1}), - Mask(np.array([[0, 0, 1, 0, 0]]), label=2, - attributes={'track_id': 2}), - Mask(np.array([[1, 1, 0, 0, 0]]), label=3, - attributes={'track_id': 3}), - ]), - DatasetItem(id=2, subset='train', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[1, 0, 0, 0, 0]]), label=3, - attributes={'track_id': 2}), - ]), - DatasetItem(id=3, subset='val', image=np.ones((5, 1)), annotations=[ - Mask(np.array([[0, 1, 0, 0, 0]]), label=0, - attributes={'track_id': 1}), - ]), + DatasetItem(id=1, subset='train', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[0, 0, 0, 1, 0]]), label=3, + attributes={'track_id': 1}), + Mask(np.array([[0, 0, 1, 0, 0]]), label=2, + attributes={'track_id': 2}), + Mask(np.array([[1, 1, 0, 0, 0]]), label=3, + attributes={'track_id': 3}), + ] + ), + DatasetItem(id=2, subset='train', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[1, 0, 0, 0, 0]]), label=3, + attributes={'track_id': 2}), + ] + ), + DatasetItem(id=3, subset='val', media=Image(data=np.ones((5, 1))), + annotations=[ + Mask(np.array([[0, 1, 0, 0, 0]]), label=0, + attributes={'track_id': 1}), + ] + ), ], categories=['a', 'b', 'c', 'd']) parsed = Dataset.import_from(DUMMY_DATASET_DIR, 'mots') diff --git a/tests/test_mpii_format.py b/tests/test_mpii_format.py index 71b1ae6f51..aa73cd3c89 100644 --- a/tests/test_mpii_format.py +++ b/tests/test_mpii_format.py @@ -9,6 +9,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import AnnotationType, DatasetItem +from datumaro.components.media import Image from datumaro.plugins.mpii_format.mpii_mat import ( MPII_POINTS_JOINTS, MPII_POINTS_LABELS, MpiiImporter, ) @@ -22,7 +23,7 @@ class MpiiImporterTest(TestCase): @mark_requirement(Requirements.DATUM_580) def test_can_import(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000001', image=np.ones((5, 5, 3)), + DatasetItem(id='000000001', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([620.0, 394.0, 616.0, 269.0, 573.0, 185.0, 647.0, 188.0, 661.0, 221.0, 656.0, 231.0, 610.0, 187.0, @@ -35,7 +36,7 @@ def test_can_import(self): Bbox(615, 218.65, 288.4, 286.95, label=0, group=1) ] ), - DatasetItem(id='000000002', image=np.ones((5, 5, 3)), + DatasetItem(id='000000002', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([650.0, 424.0, 646.0, 309.0, 603.0, 215.0, 677.0, 218.0, 691.0, 251.0, 686.0, 261.0, 640.0, 217.0, @@ -48,7 +49,7 @@ def test_can_import(self): Bbox(101.1, 33.3, 113.9, 81.4, label=0, group=1) ] ), - DatasetItem(id='000000003', image=np.ones((5, 5, 3)), + DatasetItem(id='000000003', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([590.0, 364.0, 586.0, 239.0, 533.0, 155.0, 617.0, 158.0, 631.0, 191.0, 626.0, 201.0, 580.0, 157.0, @@ -79,7 +80,7 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'mpii') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_580) def test_can_detect(self): diff --git a/tests/test_mpii_json_format.py b/tests/test_mpii_json_format.py index 629c644632..51be0f42db 100644 --- a/tests/test_mpii_json_format.py +++ b/tests/test_mpii_json_format.py @@ -9,6 +9,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import AnnotationType, DatasetItem +from datumaro.components.media import Image from datumaro.plugins.mpii_format.mpii_json import ( MPII_POINTS_JOINTS, MPII_POINTS_LABELS, MpiiJsonImporter, ) @@ -25,7 +26,7 @@ class MpiiJsonImporterTest(TestCase): @mark_requirement(Requirements.DATUM_580) def test_can_import_dataset_witn_numpy_files(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000001', image=np.ones((5, 5, 3)), + DatasetItem(id='000000001', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([620.0, 394.0, 616.0, 269.0, 573.0, 185.0, 647.0, 188.0, 661.0, 221.0, 656.0, 231.0, 610.0, 187.0, @@ -38,7 +39,7 @@ def test_can_import_dataset_witn_numpy_files(self): Bbox(615, 218.65, 288.4, 286.95, label=0, group=1) ] ), - DatasetItem(id='000000002', image=np.ones((5, 5, 3)), + DatasetItem(id='000000002', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([650.0, 424.0, 646.0, 309.0, 603.0, 215.0, 677.0, 218.0, 691.0, 251.0, 686.0, 261.0, 640.0, 217.0, @@ -51,7 +52,7 @@ def test_can_import_dataset_witn_numpy_files(self): Bbox(101.1, 33.3, 113.9, 81.4, label=0, group=1) ] ), - DatasetItem(id='000000003', image=np.ones((5, 5, 3)), + DatasetItem(id='000000003', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([590.0, 364.0, 586.0, 239.0, 533.0, 155.0, 617.0, 158.0, 631.0, 191.0, 626.0, 201.0, 580.0, 157.0, @@ -90,12 +91,12 @@ def test_can_import_dataset_witn_numpy_files(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_WITH_NUMPY_FILES, 'mpii_json') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_580) def test_can_import_dataset_wo_numpy_files(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='000000001', image=np.ones((5, 5, 3)), + DatasetItem(id='000000001', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([620.0, 394.0, 616.0, 269.0, 573.0, 185.0, 647.0, 188.0, 661.0, 221.0, 656.0, 231.0, 610.0, 187.0, @@ -107,7 +108,7 @@ def test_can_import_dataset_wo_numpy_files(self): label=0, group=1) ] ), - DatasetItem(id='000000002', image=np.ones((5, 5, 3)), + DatasetItem(id='000000002', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([650.0, 424.0, 646.0, 309.0, 603.0, 215.0, 677.0, 218.0, 691.0, 251.0, 686.0, 261.0, 640.0, 217.0, @@ -119,7 +120,7 @@ def test_can_import_dataset_wo_numpy_files(self): label=0, group=1) ] ), - DatasetItem(id='000000003', image=np.ones((5, 5, 3)), + DatasetItem(id='000000003', media=Image(data=np.ones((5, 5, 3))), annotations=[ Points([590.0, 364.0, 586.0, 239.0, 533.0, 155.0, 617.0, 158.0, 631.0, 191.0, 626.0, 201.0, 580.0, 157.0, @@ -139,7 +140,7 @@ def test_can_import_dataset_wo_numpy_files(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_WO_NUMPY_FILES, 'mpii_json') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_580) def test_can_detect_dataset_with_numpy_files(self): diff --git a/tests/test_ndr.py b/tests/test_ndr.py index 5104f5b47b..14518ef381 100644 --- a/tests/test_ndr.py +++ b/tests/test_ndr.py @@ -6,6 +6,7 @@ AnnotationType, Label, LabelCategories, ) from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.components.project import Dataset import datumaro.plugins.ndr as ndr @@ -36,7 +37,7 @@ def _generate_dataset(self, config, num_duplicate, dataset='classification'): iterable.append( DatasetItem(idx, subset=subset, annotations=[Label(label_id)], - image=dummy_images[idx % num_duplicate], + media=Image(data=dummy_images[idx % num_duplicate]), ) ) categories = {AnnotationType.label: label_cat} diff --git a/tests/test_open_images_format.py b/tests/test_open_images_format.py index f4dab9d1e4..4b143b98a6 100644 --- a/tests/test_open_images_format.py +++ b/tests/test_open_images_format.py @@ -31,7 +31,8 @@ def test_can_save_and_load(self): DatasetItem(id='a', subset='train', annotations=[Label(0, attributes={'score': 0.7})] ), - DatasetItem(id='b', subset='train', image=np.zeros((8, 8, 3)), + DatasetItem(id='b', subset='train', + media=Image(data=np.zeros((8, 8, 3))), annotations=[ Label(1), Label(2, attributes={'score': 0}), @@ -60,7 +61,8 @@ def test_can_save_and_load(self): expected_dataset = Dataset.from_extractors(source_dataset) expected_dataset.put( - DatasetItem(id='b', subset='train', image=np.zeros((8, 8, 3)), + DatasetItem(id='b', subset='train', + media=Image(data=np.zeros((8, 8, 3))), annotations=[ # the converter assumes that annotations without a score # have a score of 100% @@ -90,12 +92,12 @@ def test_can_save_and_load(self): with TestDir() as test_dir: OpenImagesConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'open_images') compare_datasets(self, expected_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_274) def test_can_save_and_load_with_no_subsets(self): @@ -107,7 +109,7 @@ def test_can_save_and_load_with_no_subsets(self): with TestDir() as test_dir: OpenImagesConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'open_images') @@ -116,46 +118,50 @@ def test_can_save_and_load_with_no_subsets(self): @mark_requirement(Requirements.DATUM_274) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a/1', image=Image(path='a/1.JPEG', + DatasetItem(id='a/1', media=Image(path='a/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='b/c/d/2', image=Image(path='b/c/d/2.bmp', + DatasetItem(id='b/c/d/2', media=Image(path='b/c/d/2.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: - OpenImagesConverter.convert(dataset, test_dir, save_images=True) + OpenImagesConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'open_images') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_274) def test_inplace_save_writes_only_updated_data(self): dataset = Dataset.from_iterable([ - DatasetItem('a', subset='modified', image=np.ones((2, 1, 3)), + DatasetItem('a', subset='modified', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Label(0, attributes={'score': 1}), Bbox(0, 0, 1, 2, label=0), Mask(label=0, image=np.ones((2, 1))), ]), - DatasetItem('b', subset='modified', image=np.ones((2, 1, 3)), + DatasetItem('b', subset='modified', + media=Image(data=np.ones((2, 1, 3))), annotations=[ Label(1, attributes={'score': 1}), ]), - DatasetItem('c', subset='removed', image=np.ones((3, 2, 3)), + DatasetItem('c', subset='removed', + media=Image(data=np.ones((3, 2, 3))), annotations=[Label(2, attributes={'score': 1})]), - DatasetItem('d', subset='unmodified', image=np.ones((4, 3, 3)), + DatasetItem('d', subset='unmodified', + media=Image(data=np.ones((4, 3, 3))), annotations=[Label(3, attributes={'score': 1})]), ], categories=['/m/0', '/m/1', '/m/2', '/m/3']) with TestDir() as path: - dataset.export(path, 'open_images', save_images=True) + dataset.export(path, 'open_images', save_media=True) - dataset.put(DatasetItem('e', subset='new', image=np.ones((5, 4, 3)), + dataset.put(DatasetItem('e', subset='new', media=Image(data=np.ones((5, 4, 3))), annotations=[Label(1, attributes={'score': 1})])) dataset.remove('c', subset='removed') del dataset.get('a', subset='modified').annotations[1:3] - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual( { @@ -181,12 +187,12 @@ def test_inplace_save_writes_only_updated_data(self): self.assertEqual(actual_images, expected_images) dataset_reloaded = Dataset.import_from(path, 'open_images') - compare_datasets(self, dataset, dataset_reloaded, require_images=True) + compare_datasets(self, dataset, dataset_reloaded, require_media=True) @mark_requirement(Requirements.DATUM_BUG_466) def test_can_save_and_load_without_saving_images(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a', image=np.ones((5, 5, 3)), + DatasetItem(id='a', media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0, group=1, attributes={'score': 1.0}), Mask(label=1, group=0, image=np.ones((5, 5)), @@ -205,7 +211,7 @@ def test_can_save_and_load_without_saving_images(self): @mark_requirement(Requirements.DATUM_274) def test_can_save_and_load_with_meta_file(self): dataset = Dataset.from_iterable([ - DatasetItem(id='a', image=np.ones((5, 5, 3)), + DatasetItem(id='a', media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0, group=1, attributes={'score': 1.0}), Mask(label=1, group=0, image=np.ones((5, 5)), @@ -216,13 +222,13 @@ def test_can_save_and_load_with_meta_file(self): with TestDir() as test_dir: OpenImagesConverter.convert(dataset, test_dir, - save_images=True, save_dataset_meta=True) + save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'open_images') self.assertTrue(osp.isfile(osp.join(test_dir, 'dataset_meta.json'))) compare_datasets(self, dataset, parsed_dataset, - require_images=True) + require_media=True) ASSETS_DIR = osp.join(osp.dirname(__file__), 'assets') @@ -234,9 +240,11 @@ class OpenImagesImporterTest(TestCase): @mark_requirement(Requirements.DATUM_274) def test_can_import_v6(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.zeros((8, 6, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.zeros((8, 6, 3))), annotations=[Label(label=0, attributes={'score': 1})]), - DatasetItem(id='b', subset='train', image=np.zeros((2, 8, 3)), + DatasetItem(id='b', subset='train', + media=Image(data=np.zeros((2, 8, 3))), annotations=[ Label(label=0, attributes={'score': 0}), Bbox(label=0, x=1.6, y=0.6, w=6.4, h=0.4, @@ -249,7 +257,8 @@ def test_can_import_v6(self): } ), ]), - DatasetItem(id='c', subset='test', image=np.ones((10, 5, 3)), + DatasetItem(id='c', subset='test', + media=Image(data=np.ones((10, 5, 3))), annotations=[ Label(label=1, attributes={'score': 1}), Label(label=3, attributes={'score': 1}), @@ -260,7 +269,8 @@ def test_can_import_v6(self): 'is_inside': False, }), ]), - DatasetItem(id='d', subset='validation', image=np.ones((1, 5, 3)), + DatasetItem(id='d', subset='validation', + media=Image(data=np.ones((1, 5, 3))), annotations=[]), ], categories={ @@ -278,25 +288,28 @@ def test_can_import_v6(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_V6, 'open_images') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_274) def test_can_import_v5(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='aa', subset='train', image=np.zeros((8, 6, 3))), - DatasetItem(id='cc', subset='test', image=np.ones((10, 5, 3))), + DatasetItem(id='aa', subset='train', + media=Image(data=np.zeros((8, 6, 3)))), + DatasetItem(id='cc', subset='test', + media=Image(data=np.ones((10, 5, 3)))), ], categories=[ '/m/0', '/m/1', ]) dataset = Dataset.import_from(DUMMY_DATASET_DIR_V5, 'open_images') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_274) def test_can_import_without_image_ids_file(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='a', subset='train', image=np.zeros((8, 6, 3)), + DatasetItem(id='a', subset='train', + media=Image(data=np.zeros((8, 6, 3))), annotations=[Label(label=0, attributes={'score': 1})]), - DatasetItem(id='b', subset='train', image=np.zeros((2, 8, 3)), + DatasetItem(id='b', subset='train', media=Image(data=np.zeros((2, 8, 3))), annotations=[ Label(label=0, attributes={'score': 0}), Bbox(label=0, x=1.6, y=0.6, w=6.4, h=0.4, @@ -309,7 +322,7 @@ def test_can_import_without_image_ids_file(self): } ), ]), - DatasetItem(id='c', subset='test', image=np.ones((10, 5, 3)), + DatasetItem(id='c', subset='test', media=Image(data=np.ones((10, 5, 3))), annotations=[ Label(label=1, attributes={'score': 1}), Label(label=3, attributes={'score': 1}), @@ -338,7 +351,7 @@ def test_can_import_without_image_ids_file(self): dataset = Dataset.import_from(dataset_path, 'open_images') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_274) def test_can_detect(self): diff --git a/tests/test_ops.py b/tests/test_ops.py index 6821ce2ea2..2dd3204770 100644 --- a/tests/test_ops.py +++ b/tests/test_ops.py @@ -1,4 +1,5 @@ from unittest import TestCase +import os.path as osp import numpy as np @@ -8,6 +9,7 @@ ) from datumaro.components.dataset import Dataset from datumaro.components.extractor import DEFAULT_SUBSET_NAME, DatasetItem +from datumaro.components.media import Image, PointCloud from datumaro.components.operations import ( FailedAttrVotingError, IntersectMerge, NoMatchingAnnError, NoMatchingItemError, WrongGroupError, compute_ann_statistics, @@ -25,9 +27,9 @@ def test_mean_std(self): expected_std = [20, 50, 10] dataset = Dataset.from_iterable([ - DatasetItem(id=i, image=np.random.normal( + DatasetItem(id=i, media=Image(data=np.random.normal( expected_mean, expected_std, size=(h, w, 3)) - ) + )) for i, (w, h) in enumerate([ (3000, 100), (800, 600), (400, 200), (700, 300) ]) @@ -46,8 +48,8 @@ def test_image_stats(self): expected_std = [20, 50, 10] dataset = Dataset.from_iterable([ - DatasetItem(id=i, image=np.random.normal( - expected_mean, expected_std, size=(h, w, 3)) + DatasetItem(id=i, media=Image(data=np.random.normal( + expected_mean, expected_std, size=(h, w, 3))) ) for i, (w, h) in enumerate([ (3000, 100), (800, 600), (400, 200), (700, 300) @@ -76,32 +78,36 @@ def test_image_stats(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_stats(self): dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((5, 5, 3)), annotations=[ - Caption('hello'), - Caption('world'), - Label(2, attributes={ 'x': 1, 'y': '2', }), - Bbox(1, 2, 2, 2, label=2, attributes={ 'score': 0.5, }), - Bbox(5, 6, 2, 2, attributes={ - 'x': 1, 'y': '3', 'occluded': True, - }), - Points([1, 2, 2, 0, 1, 1], label=0), - Mask(label=3, image=np.array([ - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ])), - ]), - DatasetItem(id=2, image=np.ones((2, 4, 3)), annotations=[ - Label(2, attributes={ 'x': 2, 'y': '2', }), - Bbox(1, 2, 2, 2, label=3, attributes={ 'score': 0.5, }), - Bbox(5, 6, 2, 2, attributes={ - 'x': 2, 'y': '3', 'occluded': False, - }), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), + annotations=[ + Caption('hello'), + Caption('world'), + Label(2, attributes={ 'x': 1, 'y': '2', }), + Bbox(1, 2, 2, 2, label=2, attributes={ 'score': 0.5, }), + Bbox(5, 6, 2, 2, attributes={ + 'x': 1, 'y': '3', 'occluded': True, + }), + Points([1, 2, 2, 0, 1, 1], label=0), + Mask(label=3, image=np.array([ + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + ])), + ] + ), + DatasetItem(id=2, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(2, attributes={ 'x': 2, 'y': '2', }), + Bbox(1, 2, 2, 2, label=3, attributes={ 'score': 0.5, }), + Bbox(5, 6, 2, 2, attributes={ + 'x': 2, 'y': '3', 'occluded': False, + } + ), ]), DatasetItem(id=3), - DatasetItem(id='2.2', image=np.ones((2, 4, 3))), + DatasetItem(id='2.2', media=Image(data=np.ones((2, 4, 3)))), ], categories=['label_%s' % i for i in range(4)]) expected = { @@ -237,12 +243,12 @@ def test_unique_image_count(self): dataset = Dataset.from_iterable([ # no image data, but the same path - DatasetItem(1, subset='a', image='1.jpg'), - DatasetItem(1, subset='b', image='1.jpg'), + DatasetItem(1, subset='a', media=Image(path='1.jpg')), + DatasetItem(1, subset='b', media=Image(path='1.jpg')), # same images - DatasetItem(2, image=np.array([1])), - DatasetItem(3, image=np.array([1])), + DatasetItem(2, media=Image(data=np.array([1]))), + DatasetItem(3, media=Image(data=np.array([1]))), # no image is always a unique image DatasetItem(4), @@ -599,3 +605,44 @@ def test_can_merge_categories(self): merged = merger([source0, source1]) compare_datasets(self, expected, merged, ignored_attrs={'score'}) + + @mark_requirement(Requirements.DATUM_GENERAL_REQ) + def test_can_merge_point_clouds(self): + dataset_dir = osp.join(osp.dirname(__file__), + 'assets', 'sly_pointcloud_dataset') + pcd1 = osp.join(dataset_dir, 'ds0', 'pointcloud', 'frame1.pcd') + pcd2 = osp.join(dataset_dir, 'ds0', 'pointcloud', 'frame2.pcd') + + image1 = Image(path=osp.join(dataset_dir, + 'ds0', 'related_images', 'frame1_pcd', 'img2.png')) + image2 = Image(path=osp.join(dataset_dir, + 'ds0', 'related_images', 'frame2_pcd', 'img1.png')) + + source0 = Dataset.from_iterable([ + DatasetItem(1, media=PointCloud(path=pcd1, extra_images=[image1])), + DatasetItem(2, media=PointCloud(path=pcd1, extra_images=[image1])), + DatasetItem(3, media=PointCloud(path=pcd2)), + DatasetItem(4), + DatasetItem(5, media=PointCloud(path=pcd2)), + ], categories=[], media_type=PointCloud) + + source1 = Dataset.from_iterable([ + DatasetItem(1, media=PointCloud(path=pcd1, extra_images=[image1])), + DatasetItem(2, media=PointCloud(path=pcd1, extra_images=[image2])), + DatasetItem(3), + DatasetItem(4, media=PointCloud(path=pcd2)), + DatasetItem(5, media=PointCloud(path=pcd2, extra_images=[image2])), + ], categories=[], media_type=PointCloud) + + expected = Dataset.from_iterable([ + DatasetItem(1, media=PointCloud(path=pcd1, extra_images=[image1])), + DatasetItem(2, media=PointCloud(path=pcd1, extra_images=[image1, image2])), + DatasetItem(3, media=PointCloud(path=pcd2)), + DatasetItem(4, media=PointCloud(path=pcd2)), + DatasetItem(5, media=PointCloud(path=pcd2, extra_images=[image2])), + ], categories=[], media_type=PointCloud) + + merger = IntersectMerge() + merged = merger([source0, source1]) + + compare_datasets(self, expected, merged) diff --git a/tests/test_project.py b/tests/test_project.py index 496030a78b..1a4b929490 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -18,6 +18,7 @@ ) from datumaro.components.extractor import DatasetItem, Extractor, ItemTransform from datumaro.components.launcher import Launcher +from datumaro.components.media import Image from datumaro.components.project import DiffStatus, Project from datumaro.util.scope import scope_add, scoped from datumaro.util.test_utils import TestDir, compare_datasets, compare_dirs @@ -85,8 +86,10 @@ def launch(self, inputs): yield [ Label(inp[0, 0, 0]) ] expected = Dataset.from_iterable([ - DatasetItem(0, image=np.zeros([2, 2, 3]), annotations=[Label(0)]), - DatasetItem(1, image=np.ones([2, 2, 3]), annotations=[Label(1)]) + DatasetItem(0, media=Image(data=np.zeros([2, 2, 3])), + annotations=[Label(0)]), + DatasetItem(1, media=Image(data=np.ones([2, 2, 3])), + annotations=[Label(1)]) ], categories=['a', 'b']) launcher_name = 'custom_launcher' @@ -95,10 +98,10 @@ def launch(self, inputs): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones([2, 2, 3]) * 0), - DatasetItem(1, image=np.ones([2, 2, 3]) * 1), + DatasetItem(0, media=Image(data=np.zeros([2, 2, 3]) * 0)), + DatasetItem(1, media=Image(data=np.ones([2, 2, 3]) * 1)), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.env.launchers.register(launcher_name, TestLauncher) @@ -163,15 +166,18 @@ def test_can_import_local_source_with_relpath(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, subset='a', image=np.ones((2, 3, 3)), + DatasetItem(0, subset='a', + media=Image(data=np.zeros([2, 2, 3])), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='b', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='b', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) expected_dataset = Dataset.from_iterable([ - DatasetItem(1, subset='b', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='b', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) @@ -186,7 +192,7 @@ def test_can_import_local_source_with_relpath(self): compare_dirs(self, source_url, project.source_data_dir('s1')) read_dataset = project.working_tree.make_dataset('s1') compare_datasets(self, expected_dataset, read_dataset, - require_images=True) + require_media=True) with open(osp.join(test_dir, 'proj', '.gitignore')) as f: self.assertTrue('/s1' in [line.strip() for line in f]) @@ -388,12 +394,13 @@ def test_can_redownload_source_rev_noncached(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.ones((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -416,12 +423,13 @@ def test_can_redownload_source_and_check_data_hash(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.zeros((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -445,12 +453,13 @@ def test_can_use_source_from_cache_with_working_copy(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.zeros((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -469,12 +478,13 @@ def test_raises_an_error_if_local_data_unknown(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.zeros((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -498,12 +508,13 @@ def test_can_read_working_copy_of_source(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.zeros((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.ones((1, 2, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((1, 2, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -519,12 +530,13 @@ def test_can_read_current_revision_of_source(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, image=np.ones((2, 3, 3)), + DatasetItem(0, media=Image(data=np.zeros((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='s', image=np.ones((1, 2, 3)), + DatasetItem(1, subset='s', + media=Image(data=np.zeros((1, 2, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT) @@ -1007,7 +1019,7 @@ def __iter__(self): def test_can_transform_by_name(self): class CustomExtractor(Extractor): def __init__(self, *args, **kwargs): - pass + super().__init__() def __iter__(self): return iter([ @@ -1168,12 +1180,14 @@ def test_can_save_local_source_with_relpath(self): test_dir = scope_add(TestDir()) source_url = osp.join(test_dir, 'source') source_dataset = Dataset.from_iterable([ - DatasetItem(0, subset='a', image=np.ones((2, 3, 3)), + DatasetItem(0, subset='a', + media=Image(data=np.ones((2, 3, 3))), annotations=[ Bbox(1, 2, 3, 4, label=0) ]), - DatasetItem(1, subset='b', image=np.zeros((10, 20, 3)), + DatasetItem(1, subset='b', + media=Image(data=np.zeros((10, 20, 3))), annotations=[ Bbox(1, 2, 3, 4, label=1) ]), ], categories=['a', 'b']) - source_dataset.save(source_url, save_images=True) + source_dataset.save(source_url, save_media=True) project = scope_add(Project.init(osp.join(test_dir, 'proj'))) project.import_source('s1', url=source_url, format=DEFAULT_FORMAT, diff --git a/tests/test_sampler.py b/tests/test_sampler.py index 2696bbfed0..ee49375ac0 100644 --- a/tests/test_sampler.py +++ b/tests/test_sampler.py @@ -85,7 +85,7 @@ def _generate_classification_dataset(self, config, subset=None, attributes=attr, ) ], - image=img, + media=img, ) ) categories = {AnnotationType.label: label_cat} @@ -346,10 +346,10 @@ def test_sampler_gives_error(self): infer_df = defaultdict(list) for data in sub: - width, height = data.image.size + width, height = data.media.size data_df["Width"].append(width) data_df["Height"].append(height) - data_df["ImagePath"].append(data.image.path) + data_df["ImagePath"].append(data.media.path) for annotation in data.annotations: probs = annotation.attributes["scores"] @@ -372,11 +372,11 @@ def test_sampler_gives_error(self): infer_df = defaultdict(list) for data in sub: - width, height = data.image.size + width, height = data.media.size data_df["ImageID"].append(data.id) data_df["Width"].append(width) data_df["Height"].append(height) - data_df["ImagePath"].append(data.image.path) + data_df["ImagePath"].append(data.media.path) for annotation in data.annotations: probs = annotation.attributes["scores"] diff --git a/tests/test_sly_pointcloud_format.py b/tests/test_sly_pointcloud_format.py index 19060456e7..a0bb850e50 100644 --- a/tests/test_sly_pointcloud_format.py +++ b/tests/test_sly_pointcloud_format.py @@ -8,6 +8,7 @@ ) from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image, PointCloud from datumaro.components.project import Dataset from datumaro.plugins.sly_pointcloud_format.converter import ( SuperviselyPointCloudConverter, @@ -36,10 +37,10 @@ def test_can_load(self): pcd1 = osp.join(DUMMY_DATASET_DIR, 'ds0', 'pointcloud', 'frame1.pcd') pcd2 = osp.join(DUMMY_DATASET_DIR, 'ds0', 'pointcloud', 'frame2.pcd') - image1 = osp.join(DUMMY_DATASET_DIR, - 'ds0', 'related_images', 'frame1_pcd', 'img2.png') - image2 = osp.join(DUMMY_DATASET_DIR, - 'ds0', 'related_images', 'frame2_pcd', 'img1.png') + image1 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'ds0', 'related_images', 'frame1_pcd', 'img2.png')) + image2 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'ds0', 'related_images', 'frame2_pcd', 'img1.png')) label_cat = LabelCategories(attributes={'tag1', 'tag3'}) label_cat.add('car') @@ -58,7 +59,7 @@ def test_can_load(self): attributes={'track_id': 231831, 'tag1': 'v12', 'tag3': ''}), ], - point_cloud=pcd1, related_images=[image1], + media=PointCloud(pcd1, extra_images=[image1]), attributes={'frame': 0, 'description': '', 'tag1': '25dsd', 'tag2': 65} ), @@ -69,10 +70,10 @@ def test_can_load(self): position=[0.59, 14.41, -0.61], attributes={'track_id': 36, 'tag1': '', 'tag3': ''}) ], - point_cloud=pcd2, related_images=[image2], + media=PointCloud(pcd2, extra_images=[image2]), attributes={'frame': 1, 'description': ''} ), - ], categories={AnnotationType.label: label_cat}) + ], categories={AnnotationType.label: label_cat}, media_type=PointCloud) parsed_dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'sly_pointcloud') @@ -84,10 +85,10 @@ class PointCloudConverterTest(TestCase): pcd1 = osp.join(DUMMY_DATASET_DIR, 'ds0', 'pointcloud', 'frame1.pcd') pcd2 = osp.join(DUMMY_DATASET_DIR, 'ds0', 'pointcloud', 'frame2.pcd') - image1 = osp.join(DUMMY_DATASET_DIR, - 'ds0', 'related_images', 'frame1_pcd', 'img2.png') - image2 = osp.join(DUMMY_DATASET_DIR, - 'ds0', 'related_images', 'frame2_pcd', 'img1.png') + image1 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'ds0', 'related_images', 'frame1_pcd', 'img2.png')) + image2 = Image(path=osp.join(DUMMY_DATASET_DIR, + 'ds0', 'related_images', 'frame2_pcd', 'img1.png')) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def _test_save_and_load(self, source_dataset, converter, test_dir, @@ -114,7 +115,7 @@ def test_can_save_and_load(self): position=[318.19, 974.65, 1.29], attributes={'occluded': True, 'track_id': 2}), ], - point_cloud=self.pcd1, + media=PointCloud(self.pcd1), attributes={'frame': 0, 'description': 'zzz'} ), @@ -124,10 +125,10 @@ def test_can_save_and_load(self): position=[23.04, 8.75, -0.78], attributes={'occluded': False, 'track_id': 2}) ], - point_cloud=self.pcd2, related_images=[self.image2], + media=PointCloud(self.pcd2, extra_images=[self.image2]), attributes={'frame': 1} ), - ], categories={ AnnotationType.label: src_label_cat }) + ], categories={ AnnotationType.label: src_label_cat }, media_type=PointCloud) with TestDir() as test_dir: target_label_cat = LabelCategories(attributes={'occluded'}) @@ -146,8 +147,8 @@ def test_can_save_and_load(self): position=[318.19, 974.65, 1.29], attributes={'occluded': True, 'track_id': 2}), ], - point_cloud=osp.join(test_dir, - 'ds0', 'pointcloud', 'frame_1.pcd'), + media=PointCloud(osp.join(test_dir, + 'ds0', 'pointcloud', 'frame_1.pcd')), attributes={'frame': 0, 'description': 'zzz'}), DatasetItem(id='frm2', @@ -156,16 +157,16 @@ def test_can_save_and_load(self): position=[23.04, 8.75, -0.78], attributes={'occluded': False, 'track_id': 2}), ], - point_cloud=osp.join(test_dir, - 'ds0', 'pointcloud', 'frm2.pcd'), - related_images=[osp.join(test_dir, - 'ds0', 'related_images', 'frm2_pcd', 'img1.png') - ], + media=PointCloud(osp.join(test_dir, + 'ds0', 'pointcloud', 'frm2.pcd'), + extra_images=[Image(path=osp.join(test_dir, + 'ds0', 'related_images', 'frm2_pcd', 'img1.png')) + ]), attributes={'frame': 1, 'description': ''}) - ], categories={ AnnotationType.label: target_label_cat }) + ], categories={ AnnotationType.label: target_label_cat }, media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(SuperviselyPointCloudConverter.convert, save_images=True), + partial(SuperviselyPointCloudConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, require_point_cloud=True) @@ -173,7 +174,7 @@ def test_can_save_and_load(self): def test_preserve_frame_ids(self): dataset = Dataset.from_iterable([ DatasetItem(id='abc', attributes={'frame': 20}), - ], categories=[]) + ], categories=[], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(dataset, @@ -184,11 +185,11 @@ def test_preserve_frame_ids(self): def test_reindex(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='somename', attributes={'frame': 1234}) - ]) + ], media_type=PointCloud) expected_dataset = Dataset.from_iterable([ DatasetItem(id='somename', attributes={'frame': 1}) - ], categories=[]) + ], categories=[], media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, @@ -209,11 +210,11 @@ def test_can_keep_undeclared_attributes(self): 'a': 5, 'undeclared': 'y'}), ], attributes={'frame': 0}), - ], categories={AnnotationType.label: src_label_cat}) + ], categories={AnnotationType.label: src_label_cat}, media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(SuperviselyPointCloudConverter.convert, save_images=True, + partial(SuperviselyPointCloudConverter.convert, save_media=True, allow_undeclared_attrs=True), test_dir, ignored_attrs=['description']) @@ -230,7 +231,7 @@ def test_can_drop_undeclared_attributes(self): 'a': 5, 'undeclared': 'y'}), ], attributes={'frame': 0}), - ], categories={AnnotationType.label: src_label_cat}) + ], categories={AnnotationType.label: src_label_cat}, media_type=PointCloud) target_dataset = Dataset.from_iterable([ DatasetItem(id='frame_000000', @@ -239,11 +240,11 @@ def test_can_drop_undeclared_attributes(self): attributes={'track_id': 206, 'occluded': False, 'a': 5}), ], attributes={'frame': 0}), - ], categories={AnnotationType.label: src_label_cat}) + ], categories={AnnotationType.label: src_label_cat}, media_type=PointCloud) with TestDir() as test_dir: self._test_save_and_load(source_dataset, - partial(SuperviselyPointCloudConverter.convert, save_images=True), + partial(SuperviselyPointCloudConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, ignored_attrs=['description']) @@ -251,9 +252,9 @@ def test_can_drop_undeclared_attributes(self): def test_have_arbitrary_item_ids(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/c235', - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 20}), - ]) + ], media_type=PointCloud) with TestDir() as test_dir: pcd_path = osp.join(test_dir, 'ds0', 'pointcloud', @@ -262,12 +263,12 @@ def test_have_arbitrary_item_ids(self): 'a', 'b', 'c235_pcd', 'img2.png') target_dataset = Dataset.from_iterable([ DatasetItem(id='a/b/c235', - point_cloud=pcd_path, related_images=[img_path], + media=PointCloud(pcd_path, extra_images=[Image(path=img_path)]), attributes={'frame': 20}), - ], categories=[]) + ], categories=[], media_type=PointCloud) self._test_save_and_load(source_dataset, - partial(SuperviselyPointCloudConverter.convert, save_images=True), + partial(SuperviselyPointCloudConverter.convert, save_media=True), test_dir, target_dataset=target_dataset, ignored_attrs={'description'}, require_point_cloud=True) @@ -287,21 +288,21 @@ def test_inplace_save_writes_only_updated_data(self): Cuboid3d(id=215, position=[320.59, 979.48, 1.03], label=0) ], - point_cloud=self.pcd1, related_images=[self.image1], + media=PointCloud(self.pcd1, extra_images=[self.image1]), attributes={'frame': 0}) - ], categories=['car', 'bus']) - dataset.export(path, 'sly_pointcloud', save_images=True) + ], categories=['car', 'bus'], media_type=PointCloud) + dataset.export(path, 'sly_pointcloud', save_media=True) dataset.put(DatasetItem(id='frame2', annotations=[ Cuboid3d(id=216, position=[0.59, 14.41, -0.61], label=1) ], - point_cloud=self.pcd2, related_images=[self.image2], + media=PointCloud(self.pcd2, extra_images=[self.image2]), attributes={'frame': 1}) ) dataset.remove('frame1') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'frame2.pcd.json'}, set(os.listdir(osp.join(path, 'ds0', 'ann')))) diff --git a/tests/test_splitter.py b/tests/test_splitter.py index 8a3c19eead..7a29c0d0fa 100644 --- a/tests/test_splitter.py +++ b/tests/test_splitter.py @@ -6,6 +6,7 @@ AnnotationType, Bbox, Label, LabelCategories, Mask, Polygon, ) from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.components.operations import compute_ann_statistics from datumaro.components.project import Dataset import datumaro.plugins.splitter as splitter @@ -47,7 +48,7 @@ def _generate_dataset(self, config): idx, subset=self._get_subset(idx), annotations=[Label(label_id, attributes=attributes)], - image=np.ones((1, 1, 3)), + media=Image(data=np.ones((1, 1, 3))), ) ) else: @@ -58,7 +59,7 @@ def _generate_dataset(self, config): idx, subset=self._get_subset(idx), annotations=[Label(label_id)], - image=np.ones((1, 1, 3)), + media=Image(data=np.ones((1, 1, 3))), ) ) categories = {AnnotationType.label: label_cat} diff --git a/tests/test_synthia_format.py b/tests/test_synthia_format.py index f28396c847..ef90fbb012 100644 --- a/tests/test_synthia_format.py +++ b/tests/test_synthia_format.py @@ -10,6 +10,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.util.test_utils import compare_datasets import datumaro.plugins.synthia_format as Synthia @@ -47,7 +48,7 @@ def test_can_detect_with_custom_labelmap(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='Stereo_Left/Omni_B/000000', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=1, attributes={'dynamic_object': False}), @@ -56,7 +57,7 @@ def test_can_import(self): ], ), DatasetItem(id='Stereo_Left/Omni_B/000001', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 0, 0]]), label=8, attributes={'dynamic_object': True}), @@ -67,7 +68,7 @@ def test_can_import(self): ], ), DatasetItem(id='Stereo_Left/Omni_F/000000', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=1, attributes={'dynamic_object': False}), @@ -78,7 +79,7 @@ def test_can_import(self): ], ), DatasetItem(id='Stereo_Left/Omni_F/000001', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 0, 0]]), label=1, attributes={'dynamic_object': False}), @@ -94,14 +95,14 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_LABELS_SEGM_DATASET_DIR, 'synthia') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_497) def test_can_import_with_colored_masks(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='Stereo_Left/Omni_F/000000', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=1), Mask(np.array([[0, 0, 1, 1, 0]]), label=2), @@ -109,7 +110,7 @@ def test_can_import_with_colored_masks(self): ], ), DatasetItem(id='Stereo_Left/Omni_F/000001', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 0, 0, 0, 0]]), label=1), Mask(np.array([[0, 1, 0, 0, 0]]), label=2), @@ -121,20 +122,20 @@ def test_can_import_with_colored_masks(self): dataset = Dataset.import_from(DUMMY_COLOR_SEGM_DATASET_DIR, 'synthia') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_497) def test_can_import_with_custom_labelmap(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='Stereo_Left/Omni_F/000000', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 1, 0, 0]]), label=1), Mask(np.array([[0, 0, 0, 1, 1]]), label=4), ], ), DatasetItem(id='Stereo_Left/Omni_F/000001', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=2), Mask(np.array([[0, 0, 1, 1, 0]]), label=3), @@ -150,20 +151,20 @@ def test_can_import_with_custom_labelmap(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_CUSTOM_LABELMAP, 'synthia') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_497) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='Stereo_Left/Omni_F/000000', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 1, 0, 0]]), label=1), Mask(np.array([[0, 0, 0, 1, 1]]), label=4), ], ), DatasetItem(id='Stereo_Left/Omni_F/000001', - image=np.ones((1, 5, 3)), + media=Image(data=np.ones((1, 5, 3))), annotations=[ Mask(np.array([[1, 1, 0, 0, 0]]), label=2), Mask(np.array([[0, 0, 1, 1, 0]]), label=3), @@ -179,4 +180,4 @@ def test_can_import_with_meta_file(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_META_FILE, 'synthia') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) diff --git a/tests/test_tfrecord_format.py b/tests/test_tfrecord_format.py index 8235c5ed87..fe35965632 100644 --- a/tests/test_tfrecord_format.py +++ b/tests/test_tfrecord_format.py @@ -55,7 +55,7 @@ def _test_save_and_load(self, source_dataset, converter, test_dir, def test_can_save_bboxes(self): test_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2), Bbox(0, 4, 4, 4, label=3), @@ -70,13 +70,14 @@ def test_can_save_bboxes(self): with TestDir() as test_dir: self._test_save_and_load( test_dataset, - partial(TfDetectionApiConverter.convert, save_images=True), + partial(TfDetectionApiConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_masks(self): test_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((4, 5, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((4, 5, 3))), annotations=[ Mask(image=np.array([ [1, 0, 0, 1], @@ -102,7 +103,7 @@ def test_can_save_masks(self): def test_can_save_dataset_with_no_subsets(self): test_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(2, 1, 4, 4, label=2), Bbox(4, 2, 8, 4, label=3), @@ -111,7 +112,7 @@ def test_can_save_dataset_with_no_subsets(self): ), DatasetItem(id=2, - image=np.ones((8, 8, 3)) * 2, + media=Image(data=np.ones((8, 8, 3)) * 2), annotations=[ Bbox(4, 4, 4, 4, label=3), ], @@ -119,7 +120,7 @@ def test_can_save_dataset_with_no_subsets(self): ), DatasetItem(id=3, - image=np.ones((8, 4, 3)) * 3, + media=Image(data=np.ones((8, 4, 3)) * 3), attributes={'source_id': ''} ), ], categories={ @@ -130,14 +131,14 @@ def test_can_save_dataset_with_no_subsets(self): with TestDir() as test_dir: self._test_save_and_load( test_dataset, - partial(TfDetectionApiConverter.convert, save_images=True), + partial(TfDetectionApiConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): test_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(2, 1, 4, 4, label=2), Bbox(4, 2, 8, 4, label=3), @@ -152,14 +153,14 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): with TestDir() as test_dir: self._test_save_and_load( test_dataset, - partial(TfDetectionApiConverter.convert, save_images=True), + partial(TfDetectionApiConverter.convert, save_media=True), test_dir) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_image_info(self): test_dataset = Dataset.from_iterable([ DatasetItem(id='1/q.e', - image=Image(path='1/q.e', size=(10, 15)), + media=Image(path='1/q.e', size=(10, 15)), attributes={'source_id': ''} ) ], categories=[]) @@ -172,12 +173,12 @@ def test_can_save_dataset_with_image_info(self): def test_can_save_dataset_with_unknown_image_formats(self): test_dataset = Dataset.from_iterable([ DatasetItem(id=1, - image=ByteImage(data=encode_image(np.ones((5, 4, 3)), 'png'), + media=ByteImage(data=encode_image(np.ones((5, 4, 3)), 'png'), path='1/q.e'), attributes={'source_id': ''} ), DatasetItem(id=2, - image=ByteImage(data=encode_image(np.ones((6, 4, 3)), 'png'), + media=ByteImage(data=encode_image(np.ones((6, 4, 3)), 'png'), ext='qwe'), attributes={'source_id': ''} ) @@ -185,42 +186,46 @@ def test_can_save_dataset_with_unknown_image_formats(self): with TestDir() as test_dir: self._test_save_and_load(test_dataset, - partial(TfDetectionApiConverter.convert, save_images=True), - test_dir, require_images=True) + partial(TfDetectionApiConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ DatasetItem('q/1', subset='train', - image=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3))), + media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3))), attributes={'source_id': ''}), DatasetItem('a/b/c/2', subset='valid', - image=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), + media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), attributes={'source_id': ''}), ], categories=[]) with TestDir() as test_dir: self._test_save_and_load(dataset, - partial(TfDetectionApiConverter.convert, save_images=True), - test_dir, require_images=True) + partial(TfDetectionApiConverter.convert, save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data(self): with TestDir() as path: # generate initial dataset dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 3, 3))), - DatasetItem(2, subset='b', image=np.ones((2, 4, 3))), - DatasetItem(3, subset='c', image=np.ones((2, 5, 3))), + DatasetItem(1, subset='a', + media=Image(data=np.ones((2, 3, 3)))), + DatasetItem(2, subset='b', + media=Image(data=np.ones((2, 4, 3)))), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 5, 3)))), ]) - dataset.export(path, 'tf_detection_api', save_images=True) + dataset.export(path, 'tf_detection_api', save_media=True) os.unlink(osp.join(path, 'a.tfrecord')) os.unlink(osp.join(path, 'b.tfrecord')) os.unlink(osp.join(path, 'c.tfrecord')) - dataset.put(DatasetItem(2, subset='a', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='a', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertTrue(osp.isfile(osp.join(path, 'a.tfrecord'))) self.assertFalse(osp.isfile(osp.join(path, 'b.tfrecord'))) @@ -268,7 +273,7 @@ def test_can_detect(self): def test_can_import(self): target_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=np.ones((16, 16, 3)), + media=Image(data=np.ones((16, 16, 3))), annotations=[ Bbox(0, 4, 4, 8, label=2), Bbox(0, 4, 4, 4, label=3), @@ -278,7 +283,7 @@ def test_can_import(self): ), DatasetItem(id=2, subset='val', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(1, 2, 4, 2, label=3), ], @@ -286,7 +291,7 @@ def test_can_import(self): ), DatasetItem(id=3, subset='test', - image=np.ones((5, 4, 3)) * 3, + media=Image(data=np.ones((5, 4, 3)) * 3), attributes={'source_id': '3'} ), ], categories={ diff --git a/tests/test_transforms.py b/tests/test_transforms.py index 625dab52ea..f37eac2237 100644 --- a/tests/test_transforms.py +++ b/tests/test_transforms.py @@ -40,23 +40,27 @@ def test_reindex(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_mask_to_polygons(self): source = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), annotations=[ - Mask(np.array([ - [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], - [0, 0, 1, 1, 0, 1, 1, 1, 0, 0], - [0, 0, 0, 1, 0, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ]), - ), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), + annotations=[ + Mask(np.array([ + [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 0, 1, 1, 1, 0, 0], + [0, 0, 0, 1, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ]), + ), + ] + ), ]) expected = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), annotations=[ - Polygon([1, 0, 3, 2, 3, 0, 1, 0]), - Polygon([5, 0, 5, 3, 8, 0, 5, 0]), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), + annotations=[ + Polygon([1, 0, 3, 2, 3, 0, 1, 0]), + Polygon([5, 0, 5, 3, 8, 0, 5, 0]), + ] + ), ]) actual = transforms.MasksToPolygons(source) @@ -65,18 +69,20 @@ def test_mask_to_polygons(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_mask_to_polygons_small_polygons_message(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), annotations=[ - Mask(np.array([ - [0, 0, 0], - [0, 1, 0], - [0, 0, 0], - ]), - ), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), + annotations=[ + Mask(np.array([ + [0, 0, 0], + [0, 1, 0], + [0, 0, 0], + ]), + ), + ] + ), ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3))), ]) + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3)))), ]) with self.assertLogs(level=log.DEBUG) as logs: actual = transforms.MasksToPolygons(source_dataset) @@ -87,31 +93,35 @@ def test_mask_to_polygons_small_polygons_message(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_polygons_to_masks(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), annotations=[ - Polygon([0, 0, 4, 0, 4, 4]), - Polygon([5, 0, 9, 0, 5, 5]), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), + annotations=[ + Polygon([0, 0, 4, 0, 4, 4]), + Polygon([5, 0, 9, 0, 5, 5]), + ] + ), ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 10, 3)), annotations=[ - Mask(np.array([ - [0, 0, 0, 0, 0, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ]), - ), - Mask(np.array([ - [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ]), - ), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 10, 3))), + annotations=[ + Mask(np.array([ + [0, 0, 0, 0, 0, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ]), + ), + Mask(np.array([ + [0, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ]), + ), + ] + ), ]) actual = transforms.PolygonsToMasks(source_dataset) @@ -120,30 +130,34 @@ def test_polygons_to_masks(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_crop_covered_segments(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), annotations=[ - # The mask is partially covered by the polygon - Mask(np.array([ - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - [1, 1, 1, 1, 1], - [1, 1, 1, 0, 0], - [1, 1, 1, 0, 0]], - ), z_order=0), - Polygon([1, 1, 4, 1, 4, 4, 1, 4], z_order=1), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), + annotations=[ + # The mask is partially covered by the polygon + Mask(np.array([ + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + [1, 1, 1, 1, 1], + [1, 1, 1, 0, 0], + [1, 1, 1, 0, 0]], + ), z_order=0), + Polygon([1, 1, 4, 1, 4, 4, 1, 4], z_order=1), + ] + ), ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), annotations=[ - Mask(np.array([ - [0, 0, 1, 1, 1], - [0, 0, 0, 0, 1], - [1, 0, 0, 0, 1], - [1, 0, 0, 0, 0], - [1, 1, 1, 0, 0]], - ), z_order=0), - Polygon([1, 1, 4, 1, 4, 4, 1, 4], z_order=1), - ]), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), + annotations=[ + Mask(np.array([ + [0, 0, 1, 1, 1], + [0, 0, 0, 0, 1], + [1, 0, 0, 0, 1], + [1, 0, 0, 0, 0], + [1, 1, 1, 0, 0]], + ), z_order=0), + Polygon([1, 1, 4, 1, 4, 4, 1, 4], z_order=1), + ] + ), ]) actual = transforms.CropCoveredSegments(source_dataset) @@ -152,7 +166,7 @@ def test_crop_covered_segments(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_merge_instance_segments(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 1, 1, 1], @@ -171,7 +185,7 @@ def test_merge_instance_segments(self): ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 1, 1, 1], @@ -218,7 +232,7 @@ def test_map_subsets(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_shapes_to_boxes(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Mask(np.array([ [0, 0, 1, 1, 1], @@ -235,7 +249,7 @@ def test_shapes_to_boxes(self): ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Bbox(0, 0, 4, 4, id=1), Bbox(1, 1, 3, 3, id=2), @@ -251,11 +265,11 @@ def test_shapes_to_boxes(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_id_from_image(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image='path.jpg'), + DatasetItem(id=1, media=Image(path='path.jpg')), DatasetItem(id=2), ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id='path', image='path.jpg'), + DatasetItem(id='path', media=Image(path='path.jpg')), DatasetItem(id=2), ]) @@ -265,7 +279,7 @@ def test_id_from_image(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_boxes_to_masks(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Bbox(0, 0, 3, 3, z_order=1), Bbox(0, 0, 3, 1, z_order=2), @@ -275,7 +289,7 @@ def test_boxes_to_masks(self): ]) target_dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.zeros((5, 5, 3)), + DatasetItem(id=1, media=Image(data=np.zeros((5, 5, 3))), annotations=[ Mask(np.array([ [1, 1, 1, 0, 0], @@ -574,7 +588,7 @@ def test_bboxes_values_decrement_transform(self): @mark_bug(Requirements.DATUM_BUG_618) def test_can_resize(self): small_dataset = Dataset.from_iterable([ - DatasetItem(id=i, image=np.ones((4, 4)) * i, annotations=[ + DatasetItem(id=i, media=Image(data=np.ones((4, 4)) * i), annotations=[ Label(1), Bbox(1, 1, 2, 2, label=2), Polygon([1, 1, 1, 2, 2, 2, 2, 1], label=1), @@ -590,7 +604,7 @@ def test_can_resize(self): ], categories=['a', 'b', 'c']) big_dataset = Dataset.from_iterable([ - DatasetItem(id=i, image=np.ones((8, 8)) * i, annotations=[ + DatasetItem(id=i, media=Image(data=np.ones((8, 8)) * i), annotations=[ Label(1), Bbox(2, 2, 4, 4, label=2), Polygon([2, 2, 2, 4, 4, 4, 4, 2], label=1), @@ -622,12 +636,12 @@ def test_can_keep_image_ext_on_resize(self): expected = Image(np.ones((8, 4)), ext='jpg') dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=Image(np.ones((4, 2)), ext='jpg')) + DatasetItem(id=1, media=Image(np.ones((4, 2)), ext='jpg')) ]) dataset.transform('resize', width=4, height=8) - actual = dataset.get('1').image + actual = dataset.get('1').media self.assertEqual(actual.ext, expected.ext) self.assertTrue(np.array_equal(actual.data, expected.data)) diff --git a/tests/test_validator.py b/tests/test_validator.py index 0b8af1b1eb..ddaaf47a79 100644 --- a/tests/test_validator.py +++ b/tests/test_validator.py @@ -18,6 +18,7 @@ MissingLabelCategories, MultiLabelAnnotations, NegativeLength, OnlyOneAttributeValue, OnlyOneLabel, UndefinedAttribute, UndefinedLabel, ) +from datumaro.components.media import Image from datumaro.components.validator import TaskType from datumaro.plugins.validators import ( ClassificationValidator, DetectionValidator, SegmentationValidator, @@ -31,87 +32,101 @@ class _TestValidatorBase(TestCase): @classmethod def setUpClass(cls): cls.dataset = Dataset.from_iterable([ - DatasetItem(id=1, image=np.ones((5, 5, 3)), annotations=[ - Label(1, id=0, attributes={'a': 1, 'b': 7, }), - Bbox(1, 2, 3, 4, id=1, label=0, attributes={ - 'a': 1, 'b': 2, - }), - Mask(id=2, label=0, attributes={'a': 1, 'b': 2}, - image=np.array([[0, 0, 0, 0, 0], - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - [0, 0, 1, 1, 1], - ])), - ]), - DatasetItem(id=2, image=np.ones((2, 4, 3)), annotations=[ - Label(2, id=0, attributes={'a': 2, 'b': 2, }), - Bbox(2, 3, 1, 4, id=1, label=0, attributes={ - 'a': 1, 'b': 1, - }), - Mask(id=2, label=0, attributes={'a': 1, 'b': 1}, - image=np.array([[1, 1, 1, 1], [0, 0, 0, 0]]) - ), - ]), + DatasetItem(id=1, media=Image(data=np.ones((5, 5, 3))), + annotations=[ + Label(1, id=0, attributes={'a': 1, 'b': 7, }), + Bbox(1, 2, 3, 4, id=1, label=0, attributes={ + 'a': 1, 'b': 2, + }), + Mask(id=2, label=0, attributes={'a': 1, 'b': 2}, + image=np.array([[0, 0, 0, 0, 0], + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + [0, 0, 1, 1, 1], + ])), + ] + ), + DatasetItem(id=2, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(2, id=0, attributes={'a': 2, 'b': 2, }), + Bbox(2, 3, 1, 4, id=1, label=0, attributes={ + 'a': 1, 'b': 1, + }), + Mask(id=2, label=0, attributes={'a': 1, 'b': 1}, + image=np.array([[1, 1, 1, 1], [0, 0, 0, 0]]) + ), + ] + ), DatasetItem(id=3), - DatasetItem(id=4, image=np.ones((2, 4, 3)), annotations=[ - Label(0, id=0, attributes={'b': 4, }), - Label(1, id=1, attributes={'a': 11, 'b': 7, }), - Bbox(1, 3, 2, 4, id=2, label=0, attributes={ - 'a': 2, 'b': 1, - }), - Bbox(3, 1, 4, 2, id=3, label=0, attributes={ - 'a': 2, 'b': 2, - }), - Polygon([1, 3, 1, 5, 5, 5, 5, 3], label=0, id=4, - attributes={'a': 2, 'b': 2, - }), - Polygon([3, 1, 3, 5, 5, 5, 5, 1], label=1, id=5, - attributes={'a': 2, 'b': 1, - }), - ]), - DatasetItem(id=5, image=np.ones((2, 4, 3)), annotations=[ - Label(0, id=0, attributes={'a': 20, 'b': 10, }), - Bbox(1, 2, 3, 4, id=1, label=1, attributes={ - 'a': 1, 'b': 1, - }), - Polygon([1, 2, 1, 5, 5, 5, 5, 2], label=1, id=2, - attributes={'a': 1, 'b': 1, - }), - ]), - DatasetItem(id=6, image=np.ones((2, 4, 3)), annotations=[ - Label(1, id=0, attributes={'a': 11, 'b': 2, 'c': 3, }), - Bbox(2, 3, 4, 1, id=1, label=1, attributes={ - 'a': 2, 'b': 2, - }), - Mask(id=2, label=1, attributes={'a': 2, 'b': 2}, - image=np.array([[1, 0, 0], - [1, 0, 0], - [1, 0, 0], - [1, 0, 0], - ])), - ]), - DatasetItem(id=7, image=np.ones((2, 4, 3)), annotations=[ - Label(1, id=0, attributes={'a': 1, 'b': 2, 'c': 5, }), - Bbox(1, 2, 3, 4, id=1, label=2, attributes={ - 'a': 1, 'b': 2, - }), - Polygon([1, 2, 1, 5, 5, 5, 5, 2], label=2, id=2, - attributes={'a': 1, 'b': 2, - }), - ]), - DatasetItem(id=8, image=np.ones((2, 4, 3)), annotations=[ - Label(2, id=0, attributes={'a': 7, 'b': 9, 'c': 5, }), - Bbox(2, 1, 3, 4, id=1, label=2, attributes={ - 'a': 2, 'b': 1, - }), - Mask(id=2, label=2, attributes={'a': 2, 'b': 1}, - image=np.array([[1, 1, 1], - [1, 1, 1], - [1, 1, 1], - [1, 1, 1], - ])), - ]), + DatasetItem(id=4, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(0, id=0, attributes={'b': 4, }), + Label(1, id=1, attributes={'a': 11, 'b': 7, }), + Bbox(1, 3, 2, 4, id=2, label=0, attributes={ + 'a': 2, 'b': 1, + }), + Bbox(3, 1, 4, 2, id=3, label=0, attributes={ + 'a': 2, 'b': 2, + }), + Polygon([1, 3, 1, 5, 5, 5, 5, 3], label=0, id=4, + attributes={'a': 2, 'b': 2, + }), + Polygon([3, 1, 3, 5, 5, 5, 5, 1], label=1, id=5, + attributes={'a': 2, 'b': 1, + }), + ] + ), + DatasetItem(id=5, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(0, id=0, attributes={'a': 20, 'b': 10, }), + Bbox(1, 2, 3, 4, id=1, label=1, attributes={ + 'a': 1, 'b': 1, + }), + Polygon([1, 2, 1, 5, 5, 5, 5, 2], label=1, id=2, + attributes={'a': 1, 'b': 1, + }), + ] + ), + DatasetItem(id=6, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(1, id=0, attributes={'a': 11, 'b': 2, 'c': 3, }), + Bbox(2, 3, 4, 1, id=1, label=1, attributes={ + 'a': 2, 'b': 2, + }), + Mask(id=2, label=1, attributes={'a': 2, 'b': 2}, + image=np.array([[1, 0, 0], + [1, 0, 0], + [1, 0, 0], + [1, 0, 0], + ])), + ] + ), + DatasetItem(id=7, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(1, id=0, attributes={'a': 1, 'b': 2, 'c': 5, }), + Bbox(1, 2, 3, 4, id=1, label=2, attributes={ + 'a': 1, 'b': 2, + }), + Polygon([1, 2, 1, 5, 5, 5, 5, 2], label=2, id=2, + attributes={'a': 1, 'b': 2, + }), + ] + ), + DatasetItem(id=8, media=Image(data=np.ones((2, 4, 3))), + annotations=[ + Label(2, id=0, attributes={'a': 7, 'b': 9, 'c': 5, }), + Bbox(2, 1, 3, 4, id=1, label=2, attributes={ + 'a': 2, 'b': 1, + }), + Mask(id=2, label=2, attributes={'a': 2, 'b': 1}, + image=np.array([[1, 1, 1], + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + ])), + ] + ), ], categories=[[f'label_{i}', None, {'a', 'b', }] for i in range(2)]) diff --git a/tests/test_vgg_face2_format.py b/tests/test_vgg_face2_format.py index e589056d8d..735a3b0dfc 100644 --- a/tests/test_vgg_face2_format.py +++ b/tests/test_vgg_face2_format.py @@ -22,35 +22,41 @@ class VggFace2FormatTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='label_0/1', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='label_0/1', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Points([3.2, 3.12, 4.11, 3.2, 2.11, 2.5, 3.5, 2.11, 3.8, 2.13], label=0), ] ), - DatasetItem(id='label_1/2', subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id='label_1/2', subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Points([4.23, 4.32, 5.34, 4.45, 3.54, 3.56, 4.52, 3.51, 4.78, 3.34], label=1), ] ), - DatasetItem(id='label_2/3', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='label_2/3', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[Label(2)] ), - DatasetItem(id='label_3/4', subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id='label_3/4', subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 2, 4, 2, label=3), Points([3.2, 3.12, 4.11, 3.2, 2.11, 2.5, 3.5, 2.11, 3.8, 2.13], label=3), ] ), - DatasetItem(id='no_label/a/5', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/a/5', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(2, 2, 2, 2), ] ), - DatasetItem(id='no_label/label_0', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/label_0', subset='train', + media=Image(data=np.ones((8, 8, 3))), ), ], categories={ AnnotationType.label: LabelCategories.from_iterable( @@ -58,7 +64,7 @@ def test_can_save_and_load(self): }) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=True) + VggFace2Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset) @@ -66,7 +72,7 @@ def test_can_save_and_load(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_subsets(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)), + DatasetItem(id='a/b/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Points([4.23, 4.32, 5.34, 4.45, 3.54, @@ -76,7 +82,7 @@ def test_can_save_dataset_with_no_subsets(self): ], categories=['a']) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=True) + VggFace2Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset) @@ -84,7 +90,8 @@ def test_can_save_dataset_with_no_subsets(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/кириллица с пробелом', image=np.ones((8, 8, 3)), + DatasetItem(id='a/кириллица с пробелом', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Points([4.23, 4.32, 5.34, 4.45, 3.54, 3.56, 4.52, 3.51, 4.78, 3.34], label=0), @@ -93,16 +100,16 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): ], categories=['a']) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=True) + VggFace2Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_dataset_with_no_save_images(self): + def test_can_save_dataset_with_no_save_media(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='label_0/1', image=np.ones((8, 8, 3)), + DatasetItem(id='label_0/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Points([4.23, 4.32, 5.34, 4.45, 3.54, @@ -112,7 +119,7 @@ def test_can_save_dataset_with_no_save_images(self): ], categories=['label_0']) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=False) + VggFace2Converter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset) @@ -120,14 +127,14 @@ def test_can_save_dataset_with_no_save_images(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_labels(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='no_label/1', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2), Points([4.23, 4.32, 5.34, 4.45, 3.54, 3.56, 4.52, 3.51, 4.78, 3.34]), ] ), - DatasetItem(id='no_label/2', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/2', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(2, 2, 4, 2), ] @@ -135,7 +142,7 @@ def test_can_save_dataset_with_no_labels(self): ], categories=[]) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=False) + VggFace2Converter.convert(source_dataset, test_dir, save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, source_dataset, parsed_dataset) @@ -143,7 +150,7 @@ def test_can_save_dataset_with_no_labels(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_wrong_number_of_points(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='no_label/1', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Points([4.23, 4.32, 5.34, 3.51, 4.78, 3.34]), ] @@ -151,13 +158,13 @@ def test_can_save_dataset_with_wrong_number_of_points(self): ], categories=[]) target_dataset = Dataset.from_iterable([ - DatasetItem(id='no_label/1', image=np.ones((8, 8, 3)), + DatasetItem(id='no_label/1', media=Image(data=np.ones((8, 8, 3))), annotations=[] ), ], categories=[]) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=True) + VggFace2Converter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') compare_datasets(self, target_dataset, parsed_dataset) @@ -165,9 +172,9 @@ def test_can_save_dataset_with_wrong_number_of_points(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem('no_label/q/1', image=Image(path='q/1.JPEG', + DatasetItem('no_label/q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem('a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem('a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), @@ -178,22 +185,24 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): ], categories=['a']) with TestDir() as test_dir: - VggFace2Converter.convert(dataset, test_dir, save_images=True) + VggFace2Converter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='class_0/1', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='class_0/1', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Points([3.2, 3.12, 4.11, 3.2, 2.11, 2.5, 3.5, 2.11, 3.8, 2.13], label=0), ] ), - DatasetItem(id='class_1/2', subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id='class_1/2', subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Points([4.23, 4.32, 5.34, 4.45, 3.54, 3.56, 4.52, 3.51, 4.78, 3.34], label=1), @@ -205,7 +214,7 @@ def test_can_save_and_load_with_meta_file(self): }) with TestDir() as test_dir: - VggFace2Converter.convert(source_dataset, test_dir, save_images=True, + VggFace2Converter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'vgg_face2') @@ -224,7 +233,7 @@ def test_can_detect(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='n000001/0001_01', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(2, 2, 1, 2, label=0), Points([2.787, 2.898, 2.965, 2.79, 2.8, @@ -232,7 +241,7 @@ def test_can_import(self): ] ), DatasetItem(id='n000002/0001_01', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(2, 4, 2, 2, label=1), Points([2.3, 4.9, 2.9, 4.93, 2.62, @@ -240,7 +249,7 @@ def test_can_import(self): ] ), DatasetItem(id='n000002/0002_01', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 3, 1, 1, label=1), Points([1.2, 3.8, 1.8, 3.82, 1.51, @@ -248,7 +257,7 @@ def test_can_import(self): ] ), DatasetItem(id='n000003/0003_01', subset='test', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 1, 1, 1, label=2), Points([0.2, 2.8, 0.8, 2.9, 0.5, @@ -268,7 +277,7 @@ def test_can_import(self): def test_can_import_specific_subset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='n000003/0003_01', subset='test', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 1, 1, 1, label=2), Points([0.2, 2.8, 0.8, 2.9, 0.5, diff --git a/tests/test_video.py b/tests/test_video.py index e2d2e65ca9..c8770d2699 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -7,7 +7,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.extractor import DatasetItem -from datumaro.components.media import Video +from datumaro.components.media import Image, Video from datumaro.components.media_manager import MediaManager from datumaro.components.project import Project from datumaro.util.scope import Scope, on_exit_do, scope_add, scoped @@ -135,7 +135,7 @@ def test_can_read_frames(self, fxt_sample_video): expected = Dataset.from_iterable([ DatasetItem('frame_%03d' % i, subset='train', - image=np.ones((4, 6, 3)) * i) + media=Image(data=np.ones((4, 6, 3)) * i)) for i in range(4) ]) @@ -151,7 +151,8 @@ def test_can_split_and_load(self, fxt_sample_video): on_exit_do(MediaManager.get_instance().clear) expected = Dataset.from_iterable([ - DatasetItem('frame_%06d' % i, image=np.ones((4, 6, 3)) * i) + DatasetItem('frame_%06d' % i, + media=Image(data=np.ones((4, 6, 3)) * i)) for i in range(4) ]) diff --git a/tests/test_voc_format.py b/tests/test_voc_format.py index 83eccdc0e7..07852da50a 100644 --- a/tests/test_voc_format.py +++ b/tests/test_voc_format.py @@ -106,7 +106,7 @@ class DstExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Label(self._label(l.name)) for l in VOC.VocLabel if l.value % 2 == 1 @@ -147,7 +147,7 @@ def __iter__(self): ), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))) ]) dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'voc') @@ -160,14 +160,14 @@ class DstExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=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))), + media=Image(data=np.ones((10, 20, 3)))) ]) expected_dataset = DstExtractor() @@ -186,13 +186,13 @@ def __iter__(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_voc_layout_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, attributes={ @@ -209,7 +209,7 @@ def test_can_import_voc_layout_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) rpath = osp.join('ImageSets', 'Layout', 'train.txt') @@ -228,13 +228,13 @@ def test_can_import_voc_layout_dataset(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_voc_detection_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(1.0, 2.0, 2.0, 2.0, label=8, id=1, group=1, attributes={ @@ -258,7 +258,7 @@ def test_can_import_voc_detection_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) rpath = osp.join('ImageSets', 'Main', 'train.txt') @@ -276,19 +276,19 @@ def test_can_import_voc_detection_dataset(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_voc_segmentation_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=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))), + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) rpath = osp.join('ImageSets', 'Segmentation', 'train.txt') @@ -307,13 +307,13 @@ def test_can_import_voc_segmentation_dataset(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_import_voc_action_dataset(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(4.0, 5.0, 2.0, 2.0, label=15, id=2, group=2, attributes={ @@ -329,7 +329,7 @@ def test_can_import_voc_action_dataset(self): ]), DatasetItem(id='2007_000002', subset='test', - image=np.ones((10, 20, 3))), + media=Image(data=np.ones((10, 20, 3)))) ], categories=VOC.make_voc_categories()) rpath = osp.join('ImageSets', 'Action', 'train.txt') @@ -348,7 +348,7 @@ def test_can_import_voc_action_dataset(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_detect_voc(self): @@ -363,7 +363,7 @@ def test_can_detect_voc(self): def test_can_import_voc_dataset_with_empty_lines_in_subset_lists(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='2007_000001', subset='train', - image=np.ones((10, 20, 3)), + media=Image(data=np.ones((10, 20, 3))), annotations=[ Bbox(1.0, 2.0, 2.0, 2.0, label=8, id=1, group=1, attributes={ @@ -391,7 +391,7 @@ def test_can_import_voc_dataset_with_empty_lines_in_subset_lists(self): actual = Dataset.import_from(osp.join(DUMMY_DATASET3_DIR, path), format) - compare_datasets(self, expected, actual, require_images=True) + compare_datasets(self, expected, actual, require_media=True) @mark_requirement(Requirements.DATUM_673) def test_can_pickle(self): @@ -708,33 +708,36 @@ def __iter__(self): return iter([ DatasetItem(id='кириллица с пробелом 1'), DatasetItem(id='кириллица с пробелом 2', - image=np.ones([4, 5, 3])), + media=Image(data=np.ones([4, 5, 3]))), ]) for task in [None] + list(VOC.VocTask): with self.subTest(subformat=task), TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(VocConverter.convert, label_map='voc', tasks=task, - save_images=True), - test_dir, require_images=True) + save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_images(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id=1, subset='a', image=np.ones([4, 5, 3])), - DatasetItem(id=2, subset='a', image=np.ones([5, 4, 3])), + DatasetItem(id=1, subset='a', + media=Image(data=np.ones([4, 5, 3]))), + DatasetItem(id=2, subset='a', + media=Image(data=np.ones([4, 5, 3]))), - DatasetItem(id=3, subset='b', image=np.ones([2, 6, 3])), + DatasetItem(id=3, subset='b', + media=Image(data=np.ones([2, 6, 3]))), ]) for task in [None] + list(VOC.VocTask): with self.subTest(subformat=task), TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(VocConverter.convert, label_map='voc', - save_images=True, tasks=task), - test_dir, require_images=True) + save_media=True, tasks=task), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_dataset_with_voc_labelmap(self): @@ -968,7 +971,7 @@ def categories(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_background_masks_dont_introduce_instances_but_cover_others(self): dataset = Dataset.from_iterable([ - DatasetItem(1, image=np.zeros((4, 1, 1)), annotations=[ + DatasetItem(1, media=Image(data=np.zeros((4, 1, 1))), annotations=[ Mask([1, 1, 1, 1], label=1, attributes={'z_order': 1}), Mask([0, 0, 1, 1], label=2, attributes={'z_order': 2}), Mask([0, 0, 1, 1], label=0, attributes={'z_order': 3}), @@ -990,7 +993,7 @@ def test_can_save_dataset_with_image_info(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id=1, image=Image(path='1.jpg', size=(10, 15))), + DatasetItem(id=1, media=Image(path='1.jpg', size=(10, 15))), ]) for task in [None] + list(VOC.VocTask): @@ -1004,9 +1007,9 @@ def test_can_save_and_load_image_with_arbitrary_extension(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='q/1', image=Image(path='q/1.JPEG', + DatasetItem(id='q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem(id='a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem(id='a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), ]) @@ -1014,25 +1017,27 @@ def __iter__(self): with self.subTest(subformat=task), TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(VocConverter.convert, label_map='voc', tasks=task, - save_images=True), - test_dir, require_images=True) + save_media=True), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ - DatasetItem(id='1', image=np.ones((4, 2, 3))), - DatasetItem(id='subdir1/1', image=np.ones((2, 6, 3))), - DatasetItem(id='subdir2/1', image=np.ones((5, 4, 3))), + DatasetItem(id='1', media=Image(data=np.ones((4, 2, 3)))), + DatasetItem(id='subdir1/1', + media=Image(data=np.ones((2, 6, 3)))), + DatasetItem(id='subdir2/1', + media=Image(data=np.ones((5, 4, 3)))), ]) for task in [None] + list(VOC.VocTask): with self.subTest(subformat=task), TestDir() as test_dir: self._test_save_and_load(TestExtractor(), partial(VocConverter.convert, - label_map='voc', save_images=True, tasks=task), - test_dir, require_images=True) + label_map='voc', save_media=True, tasks=task), + test_dir, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_attributes(self): @@ -1069,12 +1074,14 @@ def __iter__(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data_with_direct_changes(self): expected = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((1, 2, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((1, 2, 3))), annotations=[ # Bbox(0, 0, 0, 0, label=1) # won't find removed anns ]), - DatasetItem(2, subset='b', image=np.ones((3, 2, 3)), + DatasetItem(2, subset='b', + media=Image(data=np.ones((3, 2, 3))), annotations=[ Bbox(0, 0, 0, 0, label=4, id=1, group=1, attributes={ 'truncated': False, @@ -1090,11 +1097,13 @@ def test_inplace_save_writes_only_updated_data_with_direct_changes(self): }) dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((1, 2, 3)), + DatasetItem(1, subset='a', + media=Image(data=np.ones((1, 2, 3))), annotations=[Bbox(0, 0, 0, 0, label=1)]), DatasetItem(2, subset='b', annotations=[Bbox(0, 0, 0, 0, label=2)]), - DatasetItem(3, subset='c', image=np.ones((2, 2, 3)), + DatasetItem(3, subset='c', + media=Image(data=np.ones((2, 2, 3))), annotations=[ Bbox(0, 0, 0, 0, label=3), Mask(np.ones((2, 2)), label=1) @@ -1102,15 +1111,16 @@ def test_inplace_save_writes_only_updated_data_with_direct_changes(self): ], categories=['a', 'b', 'c', 'd']) with TestDir() as path: - dataset.export(path, 'voc', save_images=True) + dataset.export(path, 'voc', save_media=True) os.unlink(osp.join(path, 'Annotations', '1.xml')) os.unlink(osp.join(path, 'Annotations', '2.xml')) os.unlink(osp.join(path, 'Annotations', '3.xml')) - dataset.put(DatasetItem(2, subset='b', image=np.ones((3, 2, 3)), + dataset.put(DatasetItem(2, subset='b', + media=Image(data=np.ones((3, 2, 3))), annotations=[Bbox(0, 0, 0, 0, label=3)])) dataset.remove(3, 'c') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'2.xml'}, # '1.xml' won't be touched set(os.listdir(osp.join(path, 'Annotations')))) @@ -1119,12 +1129,12 @@ def test_inplace_save_writes_only_updated_data_with_direct_changes(self): self.assertEqual({'a.txt', 'b.txt'}, set(os.listdir(osp.join(path, 'ImageSets', 'Main')))) compare_datasets(self, expected, Dataset.import_from(path, 'voc'), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data_with_transforms(self): expected = Dataset.from_iterable([ - DatasetItem(3, subset='test', image=np.ones((2, 3, 3)), + DatasetItem(3, subset='test', media=Image(data=np.ones((2, 3, 3))), annotations=[ Bbox(0, 1, 0, 0, label=4, id=1, group=1, attributes={ 'truncated': False, @@ -1132,7 +1142,7 @@ def test_inplace_save_writes_only_updated_data_with_transforms(self): 'occluded': False, }) ]), - DatasetItem(4, subset='train', image=np.ones((2, 4, 3)), + DatasetItem(4, subset='train', media=Image(data=np.ones((2, 4, 3))), annotations=[ Bbox(1, 0, 0, 0, label=4, id=1, group=1, attributes={ 'truncated': False, @@ -1149,16 +1159,16 @@ def test_inplace_save_writes_only_updated_data_with_transforms(self): }) dataset = Dataset.from_iterable([ - DatasetItem(1, subset='a', image=np.ones((2, 1, 3)), + DatasetItem(1, subset='a', media=Image(data=np.ones((2, 1, 3))), annotations=[ Bbox(0, 0, 0, 1, label=1) ]), - DatasetItem(2, subset='b', image=np.ones((2, 2, 3)), + DatasetItem(2, subset='b', media=Image(data=np.ones((2, 2, 3))), annotations=[ Bbox(0, 0, 1, 0, label=2), Mask(np.ones((2, 2)), label=1), ]), - DatasetItem(3, subset='b', image=np.ones((2, 3, 3)), + DatasetItem(3, subset='b', media=Image(data=np.ones((2, 3, 3))), annotations=[ Bbox(0, 1, 0, 0, label=3) ]), - DatasetItem(4, subset='c', image=np.ones((2, 4, 3)), + DatasetItem(4, subset='c', media=Image(data=np.ones((2, 4, 3))), annotations=[ Bbox(1, 0, 0, 0, label=3), Mask(np.ones((2, 2)), label=1) @@ -1166,12 +1176,12 @@ def test_inplace_save_writes_only_updated_data_with_transforms(self): ], categories=['a', 'b', 'c', 'd']) with TestDir() as path: - dataset.export(path, 'voc', save_images=True) + dataset.export(path, 'voc', save_media=True) dataset.filter('/item[id >= 3]') dataset.transform('random_split', splits=(('train', 0.5), ('test', 0.5)), seed=42) - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'3.xml', '4.xml'}, set(os.listdir(osp.join(path, 'Annotations')))) @@ -1186,7 +1196,7 @@ def test_inplace_save_writes_only_updated_data_with_transforms(self): self.assertEqual({'train.txt'}, set(os.listdir(osp.join(path, 'ImageSets', 'Segmentation')))) compare_datasets(self, expected, Dataset.import_from(path, 'voc'), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_data_images(self): @@ -1194,7 +1204,7 @@ class TestExtractor(TestExtractorBase): def __iter__(self): return iter([ DatasetItem(id='frame1', subset='test', - image=Image(path='frame1.jpg'), + media=Image(path='frame1.jpg'), annotations=[ Bbox(1.0, 2.0, 3.0, 4.0, attributes={ diff --git a/tests/test_vott_csv_format.py b/tests/test_vott_csv_format.py index b71d0f57f1..0a6d276f15 100644 --- a/tests/test_vott_csv_format.py +++ b/tests/test_vott_csv_format.py @@ -7,6 +7,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.plugins.vott_csv_format import VottCsvImporter from datumaro.util.test_utils import compare_datasets @@ -22,26 +23,26 @@ class VottCsvImporterTest(TestCase): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='img0001', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(10, 5, 10, 2, label=0) ] ), DatasetItem(id='img0002', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(11.5, 12, 10.2, 20.5, label=1), ] ), DatasetItem(id='img0003', subset='train', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(6.7, 10.3, 3.3, 4.7, label=0), Bbox(13.7, 20.2, 31.9, 43.4, label=1), ] ), DatasetItem(id='img0004', subset='train', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(1, 2, 1, 2, label=0), ] @@ -50,19 +51,19 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'vott_csv') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='img0001', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(10, 5, 10, 2, label=0) ] ), DatasetItem(id='img0002', subset='test', - image=np.ones((5, 5, 3)), + media=Image(data=np.ones((5, 5, 3))), annotations=[ Bbox(11.5, 12, 10.2, 20.5, label=1), ] @@ -72,7 +73,7 @@ def test_can_import_with_meta_file(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_WITH_META_FILE, 'vott_csv') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_detect(self): diff --git a/tests/test_vott_json_format.py b/tests/test_vott_json_format.py index e283fcb995..6ce8659db9 100644 --- a/tests/test_vott_json_format.py +++ b/tests/test_vott_json_format.py @@ -7,6 +7,7 @@ from datumaro.components.dataset import Dataset from datumaro.components.environment import Environment from datumaro.components.extractor import DatasetItem +from datumaro.components.media import Image from datumaro.plugins.vott_json_format import VottJsonImporter from datumaro.util.test_utils import compare_datasets @@ -21,16 +22,16 @@ class VottJsonImporterTest(TestCase): @mark_requirement(Requirements.DATUM_475) def test_can_import(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='img0001', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0001', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': '0d3de147f'}, annotations=[ Bbox(5, 10, 10, 2, label=0, attributes={'id': 'BsO3zj9bn'}) ] ), - DatasetItem(id='img0002', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0002', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': 'b482849bc'}, annotations=[ Bbox(11.5, 12, 10.2, 20.5, label=0, @@ -39,8 +40,8 @@ def test_can_import(self): attributes={'id': 'mosw0b97K'}) ] ), - DatasetItem(id='img0003', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0003', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': '50fef05a8'}, annotations=[ Bbox(6.7, 10.3, 3.3, 4.7, @@ -53,29 +54,29 @@ def test_can_import(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR, 'vott_json') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_import_with_meta_file(self): expected_dataset = Dataset.from_iterable([ - DatasetItem(id='img0001', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0001', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': '0d3de147f'}, annotations=[ Bbox(5, 10, 10, 2, label=0, attributes={'id': 'BsO3zj9bn'}) ] ), - DatasetItem(id='img0002', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0002', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': 'b482849bc'}, annotations=[ Bbox(11.5, 12, 10.2, 20.5, label=1, attributes={'id': 'mosw0b97K'}) ] ), - DatasetItem(id='img0003', - subset='train', image=np.ones((5, 5, 3)), + DatasetItem(id='img0003', subset='train', + media=Image(data=np.ones((5, 5, 3))), attributes={'id': '50fef05a8'}, annotations=[ Bbox(6.7, 10.3, 3.3, 4.7, @@ -88,7 +89,7 @@ def test_can_import_with_meta_file(self): dataset = Dataset.import_from(DUMMY_DATASET_DIR_WITH_META_FILE, 'vott_json') - compare_datasets(self, expected_dataset, dataset, require_images=True) + compare_datasets(self, expected_dataset, dataset, require_media=True) @mark_requirement(Requirements.DATUM_475) def test_can_detect(self): diff --git a/tests/test_widerface_format.py b/tests/test_widerface_format.py index df9b9439fa..18b4afc5ee 100644 --- a/tests/test_widerface_format.py +++ b/tests/test_widerface_format.py @@ -21,7 +21,8 @@ class WiderFaceFormatTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='1', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Bbox(0, 1, 2, 3, label=0, attributes={ @@ -30,7 +31,8 @@ def test_can_save_and_load(self): Label(1), ] ), - DatasetItem(id='2', subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id='2', subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0, attributes={ 'blur': '2', 'expression': '0', 'illumination': '1', @@ -45,7 +47,8 @@ def test_can_save_and_load(self): ] ), - DatasetItem(id='3', subset='val', image=np.ones((8, 8, 3)), + DatasetItem(id='3', subset='val', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 1.1, 5.3, 2.1, label=0, attributes={ 'blur': '2', 'expression': '1', 'illumination': '0', @@ -61,21 +64,23 @@ def test_can_save_and_load(self): ] ), - DatasetItem(id='4', subset='val', image=np.ones((8, 8, 3))), + DatasetItem(id='4', subset='val', + media=Image(data=np.ones((8, 8, 3)))) ], categories=['face', 'label_0', 'label_1']) with TestDir() as test_dir: WiderFaceConverter.convert(source_dataset, test_dir, - save_images=True) + save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) - def test_can_save_and_load_with_no_save_images(self): + def test_can_save_and_load_with_no_save_media(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='1', subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id='1', subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=1), Bbox(0, 1, 2, 3, label=0, attributes={ @@ -88,7 +93,7 @@ def test_can_save_and_load_with_no_save_images(self): with TestDir() as test_dir: WiderFaceConverter.convert(source_dataset, test_dir, - save_images=False) + save_media=False) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') compare_datasets(self, source_dataset, parsed_dataset) @@ -97,7 +102,7 @@ def test_can_save_and_load_with_no_save_images(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_no_subsets(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)), + DatasetItem(id='a/b/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(0, 1, 2, 3, label=1, attributes={ @@ -108,7 +113,7 @@ def test_can_save_dataset_with_no_subsets(self): ], categories=['face', 'label_0', 'label_1']) with TestDir() as test_dir: - WiderFaceConverter.convert(source_dataset, test_dir, save_images=True) + WiderFaceConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') compare_datasets(self, source_dataset, parsed_dataset) @@ -116,8 +121,9 @@ def test_can_save_dataset_with_no_subsets(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_dataset_with_save_dataset_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)), - subset='train', annotations=[ + DatasetItem(id='a/b/1', subset='train', + media=Image(data=np.ones((8, 8, 3))), + annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(0, 1, 2, 3, label=1, attributes={ 'blur': '2', 'expression': '0', 'illumination': '0', @@ -127,7 +133,7 @@ def test_dataset_with_save_dataset_meta_file(self): ], categories=['face', 'label_0', 'label_1']) with TestDir() as test_dir: - WiderFaceConverter.convert(source_dataset, test_dir, save_images=True, + WiderFaceConverter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') @@ -137,7 +143,8 @@ def test_dataset_with_save_dataset_meta_file(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='кириллица с пробелом', image=np.ones((8, 8, 3)), + DatasetItem(id='кириллица с пробелом', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 1, 2, 3, label=0, attributes = { 'blur': '2', 'expression': '0', 'illumination': '0', @@ -147,16 +154,16 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): ], categories=['face']) with TestDir() as test_dir: - WiderFaceConverter.convert(source_dataset, test_dir, save_images=True) + WiderFaceConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_dataset_with_non_widerface_attributes(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)), + DatasetItem(id='a/b/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Bbox(0, 1, 2, 3, label=0, attributes={ @@ -169,7 +176,7 @@ def test_can_save_dataset_with_non_widerface_attributes(self): ], categories=['face']) target_dataset = Dataset.from_iterable([ - DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)), + DatasetItem(id='a/b/1', media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=0), Bbox(0, 1, 2, 3, label=0, attributes={ @@ -180,7 +187,7 @@ def test_can_save_dataset_with_non_widerface_attributes(self): ], categories=['face']) with TestDir() as test_dir: - WiderFaceConverter.convert(source_dataset, test_dir, save_images=True) + WiderFaceConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') compare_datasets(self, target_dataset, parsed_dataset) @@ -188,37 +195,38 @@ def test_can_save_dataset_with_non_widerface_attributes(self): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ - DatasetItem('q/1', image=Image(path='q/1.JPEG', + DatasetItem('q/1', media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), - DatasetItem('a/b/c/2', image=Image(path='a/b/c/2.bmp', + DatasetItem('a/b/c/2', media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: - WiderFaceConverter.convert(dataset, test_dir, save_images=True) + WiderFaceConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'wider_face') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data(self): expected = Dataset.from_iterable([ - DatasetItem(1, subset='train', image=np.ones((2, 4, 3))), - DatasetItem(2, subset='train', image=np.ones((3, 2, 3))), + DatasetItem(1, subset='train', media=Image(data=np.ones((2, 4, 3)))), + DatasetItem(2, subset='train', media=Image(data=np.ones((3, 2, 3)))), ], categories=[]) with TestDir() as path: dataset = Dataset.from_iterable([ - DatasetItem(1, subset='train', image=np.ones((2, 4, 3))), + DatasetItem(1, subset='train', media=Image(data=np.ones((2, 4, 3)))), DatasetItem(2, subset='train', - image=Image(path='2.jpg', size=(3, 2))), - DatasetItem(3, subset='valid', image=np.ones((2, 2, 3))), + media=Image(path='2.jpg', size=(3, 2))), + DatasetItem(3, subset='valid', media=Image(data=np.ones((2, 2, 3)))), ], categories=[]) - dataset.export(path, 'wider_face', save_images=True) + dataset.export(path, 'wider_face', save_media=True) - dataset.put(DatasetItem(2, subset='train', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='train', + media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'valid') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'1.jpg', '2.jpg'}, set(os.listdir(osp.join(path, @@ -227,7 +235,7 @@ def test_inplace_save_writes_only_updated_data(self): set(os.listdir(osp.join(path, 'wider_face_split')))) compare_datasets(self, expected, Dataset.import_from(path, 'wider_face'), - require_images=True, ignored_attrs=IGNORE_ALL) + require_media=True, ignored_attrs=IGNORE_ALL) DUMMY_DATASET_DIR = osp.join(osp.dirname(__file__), 'assets', 'widerface_dataset') @@ -241,7 +249,7 @@ def test_can_detect(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id='0_Parade_image_01', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 2, 2, 2, attributes={ 'blur': '0', 'expression': '0', 'illumination': '0', @@ -250,7 +258,7 @@ def test_can_import(self): ] ), DatasetItem(id='1_Handshaking_image_02', subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(1, 1, 2, 2, attributes={ 'blur': '0', 'expression': '0', 'illumination': '1', @@ -262,7 +270,7 @@ def test_can_import(self): ] ), DatasetItem(id='0_Parade_image_03', subset='val', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(0, 0, 1, 1, attributes={ 'blur': '2', 'expression': '0', 'illumination': '0', diff --git a/tests/test_yolo_format.py b/tests/test_yolo_format.py index 3661ffed49..79db3aaf58 100644 --- a/tests/test_yolo_format.py +++ b/tests/test_yolo_format.py @@ -24,19 +24,22 @@ class YoloFormatTest(TestCase): @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(0, 1, 2, 3, label=4), ]), - DatasetItem(id=2, subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(3, 3, 2, 3, label=4), Bbox(2, 1, 2, 3, label=4), ]), - DatasetItem(id=3, subset='valid', image=np.ones((8, 8, 3)), + DatasetItem(id=3, subset='valid', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 1, 5, 2, label=2), Bbox(0, 2, 3, 2, label=5), @@ -49,7 +52,7 @@ def test_can_save_and_load(self): }) with TestDir() as test_dir: - YoloConverter.convert(source_dataset, test_dir, save_images=True) + YoloConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'yolo') compare_datasets(self, source_dataset, parsed_dataset) @@ -58,7 +61,7 @@ def test_can_save_and_load(self): def test_can_save_dataset_with_image_info(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=Image(path='1.jpg', size=(10, 15)), + media=Image(path='1.jpg', size=(10, 15)), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(3, 3, 2, 3, label=4), @@ -81,7 +84,7 @@ def test_can_save_dataset_with_image_info(self): def test_can_load_dataset_with_exact_image_info(self): source_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=Image(path='1.jpg', size=(10, 15)), + media=Image(path='1.jpg', size=(10, 15)), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(3, 3, 2, 3, label=4), @@ -103,7 +106,7 @@ def test_can_load_dataset_with_exact_image_info(self): def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='кириллица с пробелом', subset='train', - image=np.ones((8, 8, 3)), + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(0, 1, 2, 3, label=4), @@ -114,28 +117,28 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self): }) with TestDir() as test_dir: - YoloConverter.convert(source_dataset, test_dir, save_images=True) + YoloConverter.convert(source_dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'yolo') compare_datasets(self, source_dataset, parsed_dataset, - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_relative_paths(self): source_dataset = Dataset.from_iterable([ DatasetItem(id='1', subset='train', - image=np.ones((4, 2, 3))), + media=Image(data=np.ones((4, 2, 3)))), DatasetItem(id='subdir1/1', subset='train', - image=np.ones((2, 6, 3))), + media=Image(data=np.ones((2, 6, 3)))), DatasetItem(id='subdir2/1', subset='train', - image=np.ones((5, 4, 3))), + media=Image(data=np.ones((5, 4, 3)))), ], categories=[]) - for save_images in {True, False}: - with self.subTest(save_images=save_images): + for save_media in {True, False}: + with self.subTest(save_media=save_media): with TestDir() as test_dir: YoloConverter.convert(source_dataset, test_dir, - save_images=save_images) + save_media=save_media) parsed_dataset = Dataset.import_from(test_dir, 'yolo') compare_datasets(self, source_dataset, parsed_dataset) @@ -144,60 +147,63 @@ def test_relative_paths(self): def test_can_save_and_load_image_with_arbitrary_extension(self): dataset = Dataset.from_iterable([ DatasetItem('q/1', subset='train', - image=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), + media=Image(path='q/1.JPEG', data=np.zeros((4, 3, 3)))), DatasetItem('a/b/c/2', subset='valid', - image=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), + media=Image(path='a/b/c/2.bmp', data=np.zeros((3, 4, 3)))), ], categories=[]) with TestDir() as test_dir: - YoloConverter.convert(dataset, test_dir, save_images=True) + YoloConverter.convert(dataset, test_dir, save_media=True) parsed_dataset = Dataset.import_from(test_dir, 'yolo') - compare_datasets(self, dataset, parsed_dataset, require_images=True) + compare_datasets(self, dataset, parsed_dataset, require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_inplace_save_writes_only_updated_data(self): expected = Dataset.from_iterable([ - DatasetItem(1, subset='train', image=np.ones((2, 4, 3))), - DatasetItem(2, subset='train', image=np.ones((3, 2, 3))), + DatasetItem(1, subset='train', media=Image(data=np.ones((2, 4, 3)))), + DatasetItem(2, subset='train', media=Image(data=np.ones((3, 2, 3)))), ], categories=[]) with TestDir() as path: dataset = Dataset.from_iterable([ - DatasetItem(1, subset='train', image=np.ones((2, 4, 3))), + DatasetItem(1, subset='train', media=Image(data=np.ones((2, 4, 3)))), DatasetItem(2, subset='train', - image=Image(path='2.jpg', size=(3, 2))), - DatasetItem(3, subset='valid', image=np.ones((2, 2, 3))), + media=Image(path='2.jpg', size=(3, 2))), + DatasetItem(3, subset='valid', media=Image(data=np.ones((2, 2, 3)))), ], categories=[]) - dataset.export(path, 'yolo', save_images=True) + dataset.export(path, 'yolo', save_media=True) - dataset.put(DatasetItem(2, subset='train', image=np.ones((3, 2, 3)))) + dataset.put(DatasetItem(2, subset='train', media=Image(data=np.ones((3, 2, 3))))) dataset.remove(3, 'valid') - dataset.save(save_images=True) + dataset.save(save_media=True) self.assertEqual({'1.txt', '2.txt', '1.jpg', '2.jpg'}, set(os.listdir(osp.join(path, 'obj_train_data')))) self.assertEqual(set(), set(os.listdir(osp.join(path, 'obj_valid_data')))) compare_datasets(self, expected, Dataset.import_from(path, 'yolo'), - require_images=True) + require_media=True) @mark_requirement(Requirements.DATUM_GENERAL_REQ) def test_can_save_and_load_with_meta_file(self): source_dataset = Dataset.from_iterable([ - DatasetItem(id=1, subset='train', image=np.ones((8, 8, 3)), + DatasetItem(id=1, subset='train', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(0, 1, 2, 3, label=4), ]), - DatasetItem(id=2, subset='train', image=np.ones((10, 10, 3)), + DatasetItem(id=2, subset='train', + media=Image(data=np.ones((10, 10, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(3, 3, 2, 3, label=4), Bbox(2, 1, 2, 3, label=4), ]), - DatasetItem(id=3, subset='valid', image=np.ones((8, 8, 3)), + DatasetItem(id=3, subset='valid', + media=Image(data=np.ones((8, 8, 3))), annotations=[ Bbox(0, 1, 5, 2, label=2), Bbox(0, 2, 3, 2, label=5), @@ -210,7 +216,7 @@ def test_can_save_and_load_with_meta_file(self): }) with TestDir() as test_dir: - YoloConverter.convert(source_dataset, test_dir, save_images=True, + YoloConverter.convert(source_dataset, test_dir, save_media=True, save_dataset_meta=True) parsed_dataset = Dataset.import_from(test_dir, 'yolo') @@ -229,7 +235,7 @@ def test_can_detect(self): def test_can_import(self): expected_dataset = Dataset.from_iterable([ DatasetItem(id=1, subset='train', - image=np.ones((10, 15, 3)), + media=Image(data=np.ones((10, 15, 3))), annotations=[ Bbox(0, 2, 4, 2, label=2), Bbox(3, 3, 2, 3, label=4),