Skip to content

Commit

Permalink
refactoring tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzocerrone committed Sep 19, 2024
1 parent 20d3f41 commit d94a773
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 85 deletions.
67 changes: 54 additions & 13 deletions src/ngio/core/image_handler.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
"""A module to handle OME-NGFF images stored in Zarr format."""

from ngio.core.image_like_handler import ImageLikeHandler
from ngio.core.image_like_handler import ImageLike
from ngio.io import StoreOrGroup
from ngio.ngff_meta.fractal_image_meta import ImageMeta, PixelSize


class ImageHandler(ImageLikeHandler):
class Image(ImageLike):
"""A class to handle OME-NGFF images stored in Zarr format.
This class provides methods to access image data and ROI tables.
"""

@property
def channel_names(self) -> list[str]:
"""Return the names of the channels in the image."""
return self.metadata.channel_names
def __init__(
self,
store: StoreOrGroup,
*,
path: str | None = None,
idx: int | None = None,
pixel_size: PixelSize | None = None,
highest_resolution: bool = False,
strict: bool = True,
cache: bool = True,
) -> None:
"""Initialize the MultiscaleHandler in read mode.
def get_channel_idx_by_label(self, label: str) -> int:
"""Return the index of the channel with the given label."""
return self.metadata.get_channel_idx_by_label(label=label)
Note: Only one of `path`, `idx`, 'pixel_size' or 'highest_resolution'
should be provided.
def get_channel_idx_by_wavelength_id(self, wavelength_id: int) -> int:
"""Return the index of the channel with the given wavelength id."""
return self.metadata.get_channel_idx_by_wavelength_id(
wavelength_id=wavelength_id
store (StoreOrGroup): The Zarr store or group containing the image data.
path (str | None): The path to the level.
idx (int | None): The index of the level.
pixel_size (PixelSize | None): The pixel size of the level.
highest_resolution (bool): Whether to get the highest resolution level.
strict (bool): Whether to raise an error where a pixel size is not found
to match the requested "pixel_size".
cache (bool): Whether to cache the metadata.
"""
super().__init__(
store=store,
path=path,
idx=idx,
pixel_size=pixel_size,
highest_resolution=highest_resolution,
strict=strict,
meta_mode="image",
cache=cache,
)

@property
def metadata(self) -> ImageMeta:
"""Return the metadata of the image."""
return super().metadata

@property
def channel_labels(self) -> list[str]:
"""Return the names of the channels in the image."""
return self.metadata.channel_labels

def get_channel_idx(
self,
label: str | None = None,
wavelength_id: str | None = None,
) -> int:
"""Return the index of the channel."""
return self.metadata.get_channel_idx(label=label, wavelength_id=wavelength_id)
96 changes: 55 additions & 41 deletions src/ngio/core/image_like_handler.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
"""Generic class to handle Image-like data in a OME-NGFF file."""

from typing import Literal

import zarr

from ngio.io import StoreOrGroup, open_group
from ngio.ngff_meta import (
ImageMeta,
Dataset,
ImageLabelMeta,
PixelSize,
SpaceUnits,
get_ngff_image_meta_handler,
)


class ImageLikeHandler:
class ImageLike:
"""A class to handle OME-NGFF images stored in Zarr format.
This class provides methods to access image data and ROI tables.
Expand All @@ -20,77 +23,88 @@ class ImageLikeHandler:
def __init__(
self,
store: StoreOrGroup,
*,
level_path: str | int | None = None,
pixel_size: tuple[float, ...] | list[float] | None = None,
path: str | None = None,
idx: int | None = None,
pixel_size: PixelSize | None = None,
highest_resolution: bool = False,
strict: bool = True,
meta_mode: Literal["image", "label"] = "image",
cache: bool = True,
) -> None:
"""Initialize the MultiscaleHandler in read mode."""
"""Initialize the MultiscaleHandler in read mode.
Note: Only one of `path`, `idx`, 'pixel_size' or 'highest_resolution'
should be provided.
store (StoreOrGroup): The Zarr store or group containing the image data.
path (str | None): The path to the level.
idx (int | None): The index of the level.
pixel_size (PixelSize | None): The pixel size of the level.
highest_resolution (bool): Whether to get the highest resolution level.
strict (bool): Whether to raise an error where a pixel size is not found
to match the requested "pixel_size".
meta_mode (str): The mode of the metadata handler.
cache (bool): Whether to cache the metadata.
"""
if not isinstance(store, zarr.Group):
store = open_group(store=store, mode="r")

self._metadata_handler = get_ngff_image_meta_handler(
store=store, meta_mode="image", cache=True
store=store, meta_mode=meta_mode, cache=cache
)

# Find the level / resolution index
self.level_path = self._find_level(level_path, pixel_size, highest_resolution)
metadata = self._metadata_handler.load_meta()
self._dataset = metadata.get_dataset(
path=path,
idx=idx,
pixel_size=pixel_size,
highest_resolution=highest_resolution,
strict=strict,
)
self._group = store

def _find_level(
self,
level_path: int | str | None,
pixel_size: tuple[float, ...] | list[float] | None,
highest_resolution: bool,
) -> str:
"""Find the index of the level."""
args_valid = [
level_path is not None,
pixel_size is not None,
highest_resolution,
]

if sum(args_valid) != 1:
raise ValueError(
"One and only one of level_path, pixel_size, "
"or highest_resolution=True can be used. "
f"Received: {level_path=}, {pixel_size=}, {highest_resolution=}"
)
meta = self._metadata_handler.load_meta()
if level_path is not None:
return meta.get_dataset(level_path).path

if pixel_size is not None:
return meta.get_dataset_from_pixel_size(pixel_size, strict=True).path

return meta.get_highest_resolution_dataset().path

@property
def group(self) -> zarr.Group:
"""Return the Zarr group containing the image data."""
return self._group

@property
def metadata(self) -> ImageMeta:
def metadata(self) -> ImageLabelMeta:
"""Return the metadata of the image."""
return self._metadata_handler.load_meta()

@property
def dataset(self) -> Dataset:
"""Return the dataset of the image."""
return self._dataset

@property
def path(self) -> str:
"""Return the path of the dataset (relative to the root group)."""
return self.dataset.path

@property
def channel_labels(self) -> list[str]:
"""Return the names of the channels in the image."""
return self.dataset.path

@property
def axes_names(self) -> list[str]:
"""Return the names of the axes in the image."""
return self.metadata.axes_names
return self.dataset.axes_names

@property
def space_axes_names(self) -> list[str]:
"""Return the names of the space axes in the image."""
return self.metadata.space_axes_names
return self.dataset.space_axes_names

@property
def space_axes_unit(self) -> SpaceUnits:
"""Return the units of the space axes in the image."""
return self.metadata.space_axes_unit
return self.dataset.space_axes_unit

@property
def pixel_size(self) -> PixelSize:
"""Return the pixel resolution of the image."""
return self.metadata.pixel_size(level_path=self.level_path)
return self.dataset.pixel_size
59 changes: 51 additions & 8 deletions src/ngio/core/label_handler.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,78 @@
"""A module to handle OME-NGFF images stored in Zarr format."""

import zarr
from zarr.store.common import StoreLike

from ngio.core.image_like_handler import ImageLikeHandler
from ngio.core.image_like_handler import ImageLike
from ngio.io import StoreOrGroup
from ngio.ngff_meta.fractal_image_meta import LabelMeta, PixelSize


class LabelHandler(ImageLikeHandler):
class Label(ImageLike):
"""A class to handle OME-NGFF images stored in Zarr format.
This class provides methods to access image data and ROI tables.
"""

pass
def __init__(
store: StoreOrGroup,
*,
path: str | None = None,
idx: int | None = None,
pixel_size: PixelSize | None = None,
highest_resolution: bool = False,
strict: bool = True,
cache: bool = True,
) -> None:
"""Initialize the MultiscaleHandler in read mode.
Note: Only one of `path`, `idx`, 'pixel_size' or 'highest_resolution'
should be provided.
class LabelGroupHandler:
store (StoreOrGroup): The Zarr store or group containing the image data.
path (str | None): The path to the level.
idx (int | None): The index of the level.
pixel_size (PixelSize | None): The pixel size of the level.
highest_resolution (bool): Whether to get the highest resolution level.
strict (bool): Whether to raise an error where a pixel size is not found
to match the requested "pixel_size".
cache (bool): Whether to cache the metadata.
"""
super().__init__(
store,
path=path,
idx=idx,
pixel_size=pixel_size,
highest_resolution=highest_resolution,
strict=strict,
meta_mode="label",
cache=cache,
)

def metadata(self) -> LabelMeta:
"""Return the metadata of the image."""
return super().metadata


class LabelGroup:
"""A class to handle the /labels group in an OME-NGFF file."""

def __init__(self, group: zarr.Group, group_name: str = "labels") -> None:
def __init__(self, group: StoreLike) -> None:
"""Initialize the LabelGroupHandler."""
self._group = group

@property
def group_name(self) -> str:
"""Return the name of the group."""
return "labels"

def list(self) -> list[str]:
"""List all labels in the group."""
return list(self._group.array_keys())

def get(self, name: str) -> LabelHandler:
def get(self, name: str) -> Label:
"""Get a label from the group."""
raise NotImplementedError("Not yet implemented.")

def write(self, name: str, data: LabelHandler) -> None:
def write(self, name: str, data: Label) -> None:
"""Create a label in the group."""
raise NotImplementedError("Not yet implemented.")
6 changes: 3 additions & 3 deletions src/ngio/core/ngff_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from zarr.store.common import StoreLike

from ngio.core.image_handler import ImageHandler
from ngio.core.image_handler import Image
from ngio.io import open_group
from ngio.ngff_meta import FractalImageLabelMeta, get_ngff_image_meta_handler

Expand Down Expand Up @@ -93,7 +93,7 @@ def get_image(
level_path: str | int | None = None,
pixel_size: tuple[float, ...] | list[float] | None = None,
highest_resolution: bool = True,
) -> ImageHandler:
) -> Image:
"""Get an image handler for the given level.
Args:
Expand All @@ -106,7 +106,7 @@ def get_image(
Returns:
ImageHandler: The image handler.
"""
return ImageHandler(
return Image(
store=self.group,
level_path=level_path,
pixel_size=pixel_size,
Expand Down
19 changes: 17 additions & 2 deletions src/ngio/ngff_meta/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
"""IO and validation of NGFF metadata."""

from ngio.ngff_meta.fractal_image_meta import ImageMeta, PixelSize, SpaceUnits
from ngio.ngff_meta.fractal_image_meta import (
Dataset,
ImageLabelMeta,
ImageMeta,
LabelMeta,
PixelSize,
SpaceUnits,
)
from ngio.ngff_meta.meta_handler import get_ngff_image_meta_handler

__all__ = ["get_ngff_image_meta_handler", "ImageMeta", "PixelSize", "SpaceUnits"]
__all__ = [
"Dataset",
"ImageMeta",
"LabelMeta",
"ImageLabelMeta",
"PixelSize",
"SpaceUnits",
"get_ngff_image_meta_handler",
]
Loading

0 comments on commit d94a773

Please sign in to comment.