ngio 0.2.0a2__py3-none-any.whl → 0.5.0b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ngio/__init__.py +40 -12
- ngio/common/__init__.py +16 -32
- ngio/common/_dimensions.py +270 -48
- ngio/common/_masking_roi.py +153 -0
- ngio/common/_pyramid.py +267 -73
- ngio/common/_roi.py +290 -66
- ngio/common/_synt_images_utils.py +101 -0
- ngio/common/_zoom.py +54 -22
- ngio/experimental/__init__.py +5 -0
- ngio/experimental/iterators/__init__.py +15 -0
- ngio/experimental/iterators/_abstract_iterator.py +390 -0
- ngio/experimental/iterators/_feature.py +189 -0
- ngio/experimental/iterators/_image_processing.py +130 -0
- ngio/experimental/iterators/_mappers.py +48 -0
- ngio/experimental/iterators/_rois_utils.py +126 -0
- ngio/experimental/iterators/_segmentation.py +235 -0
- ngio/hcs/__init__.py +17 -58
- ngio/hcs/_plate.py +1354 -0
- ngio/images/__init__.py +30 -9
- ngio/images/_abstract_image.py +968 -0
- ngio/images/_create_synt_container.py +132 -0
- ngio/images/_create_utils.py +423 -0
- ngio/images/_image.py +926 -0
- ngio/images/_label.py +417 -0
- ngio/images/_masked_image.py +531 -0
- ngio/images/_ome_zarr_container.py +1235 -0
- ngio/images/_table_ops.py +471 -0
- ngio/io_pipes/__init__.py +75 -0
- ngio/io_pipes/_io_pipes.py +361 -0
- ngio/io_pipes/_io_pipes_masked.py +488 -0
- ngio/io_pipes/_io_pipes_roi.py +146 -0
- ngio/io_pipes/_io_pipes_types.py +56 -0
- ngio/io_pipes/_match_shape.py +377 -0
- ngio/io_pipes/_ops_axes.py +344 -0
- ngio/io_pipes/_ops_slices.py +411 -0
- ngio/io_pipes/_ops_slices_utils.py +199 -0
- ngio/io_pipes/_ops_transforms.py +104 -0
- ngio/io_pipes/_zoom_transform.py +180 -0
- ngio/ome_zarr_meta/__init__.py +39 -15
- ngio/ome_zarr_meta/_meta_handlers.py +490 -96
- ngio/ome_zarr_meta/ngio_specs/__init__.py +24 -10
- ngio/ome_zarr_meta/ngio_specs/_axes.py +268 -234
- ngio/ome_zarr_meta/ngio_specs/_channels.py +125 -41
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +42 -87
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +536 -2
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +202 -198
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +72 -34
- ngio/ome_zarr_meta/v04/__init__.py +21 -5
- ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v04/{_v04_spec_utils.py → _v04_spec.py} +151 -90
- ngio/ome_zarr_meta/v05/__init__.py +27 -0
- ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
- ngio/resources/__init__.py +55 -0
- ngio/resources/resource_model.py +36 -0
- ngio/tables/__init__.py +20 -4
- ngio/tables/_abstract_table.py +270 -0
- ngio/tables/_tables_container.py +449 -0
- ngio/tables/backends/__init__.py +50 -1
- ngio/tables/backends/_abstract_backend.py +200 -31
- ngio/tables/backends/_anndata.py +139 -0
- ngio/tables/backends/_anndata_utils.py +10 -114
- ngio/tables/backends/_csv.py +19 -0
- ngio/tables/backends/_json.py +92 -0
- ngio/tables/backends/_parquet.py +19 -0
- ngio/tables/backends/_py_arrow_backends.py +222 -0
- ngio/tables/backends/_table_backends.py +162 -38
- ngio/tables/backends/_utils.py +608 -0
- ngio/tables/v1/__init__.py +19 -4
- ngio/tables/v1/_condition_table.py +71 -0
- ngio/tables/v1/_feature_table.py +79 -115
- ngio/tables/v1/_generic_table.py +21 -90
- ngio/tables/v1/_roi_table.py +486 -137
- ngio/transforms/__init__.py +5 -0
- ngio/transforms/_zoom.py +19 -0
- ngio/utils/__init__.py +16 -14
- ngio/utils/_cache.py +48 -0
- ngio/utils/_datasets.py +121 -13
- ngio/utils/_fractal_fsspec_store.py +42 -0
- ngio/utils/_zarr_utils.py +374 -218
- ngio-0.5.0b4.dist-info/METADATA +147 -0
- ngio-0.5.0b4.dist-info/RECORD +88 -0
- {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/WHEEL +1 -1
- ngio/common/_array_pipe.py +0 -160
- ngio/common/_axes_transforms.py +0 -63
- ngio/common/_common_types.py +0 -5
- ngio/common/_slicer.py +0 -97
- ngio/images/abstract_image.py +0 -240
- ngio/images/create.py +0 -251
- ngio/images/image.py +0 -389
- ngio/images/label.py +0 -236
- ngio/images/omezarr_container.py +0 -535
- ngio/ome_zarr_meta/_generic_handlers.py +0 -320
- ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
- ngio/tables/_validators.py +0 -192
- ngio/tables/backends/_anndata_v1.py +0 -75
- ngio/tables/backends/_json_v1.py +0 -56
- ngio/tables/tables_container.py +0 -300
- ngio/tables/v1/_masking_roi_table.py +0 -175
- ngio/utils/_logger.py +0 -29
- ngio-0.2.0a2.dist-info/METADATA +0 -95
- ngio-0.2.0a2.dist-info/RECORD +0 -53
- {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
|
|
3
|
+
import dask.array as da
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from ngio.common import Roi
|
|
7
|
+
from ngio.experimental.iterators._abstract_iterator import AbstractIteratorBuilder
|
|
8
|
+
from ngio.images import Image
|
|
9
|
+
from ngio.images._image import (
|
|
10
|
+
ChannelSlicingInputType,
|
|
11
|
+
add_channel_selection_to_slicing_dict,
|
|
12
|
+
)
|
|
13
|
+
from ngio.io_pipes import (
|
|
14
|
+
DaskRoiGetter,
|
|
15
|
+
DaskRoiSetter,
|
|
16
|
+
NumpyRoiGetter,
|
|
17
|
+
NumpyRoiSetter,
|
|
18
|
+
TransformProtocol,
|
|
19
|
+
)
|
|
20
|
+
from ngio.io_pipes._io_pipes_types import DataGetterProtocol, DataSetterProtocol
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ImageProcessingIterator(AbstractIteratorBuilder[np.ndarray, da.Array]):
|
|
24
|
+
"""Base class for iterators over ROIs."""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
input_image: Image,
|
|
29
|
+
output_image: Image,
|
|
30
|
+
input_channel_selection: ChannelSlicingInputType = None,
|
|
31
|
+
output_channel_selection: ChannelSlicingInputType = None,
|
|
32
|
+
axes_order: Sequence[str] | None = None,
|
|
33
|
+
input_transforms: Sequence[TransformProtocol] | None = None,
|
|
34
|
+
output_transforms: Sequence[TransformProtocol] | None = None,
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Initialize the iterator with a ROI table and input/output images.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
input_image (Image): The input image to be used as input for the
|
|
40
|
+
segmentation.
|
|
41
|
+
output_image (Image): The image where the ROIs will be written.
|
|
42
|
+
input_channel_selection (ChannelSlicingInputType): Optional
|
|
43
|
+
selection of channels to use for the input image.
|
|
44
|
+
output_channel_selection (ChannelSlicingInputType): Optional
|
|
45
|
+
selection of channels to use for the output image.
|
|
46
|
+
axes_order (Sequence[str] | None): Optional axes order for the
|
|
47
|
+
segmentation.
|
|
48
|
+
input_transforms (Sequence[TransformProtocol] | None): Optional
|
|
49
|
+
transforms to apply to the input image.
|
|
50
|
+
output_transforms (Sequence[TransformProtocol] | None): Optional
|
|
51
|
+
transforms to apply to the output label.
|
|
52
|
+
"""
|
|
53
|
+
self._input = input_image
|
|
54
|
+
self._output = output_image
|
|
55
|
+
self._ref_image = input_image
|
|
56
|
+
self._rois = input_image.build_image_roi_table(name=None).rois()
|
|
57
|
+
|
|
58
|
+
# Set iteration parameters
|
|
59
|
+
self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
|
|
60
|
+
image=self._input,
|
|
61
|
+
channel_selection=input_channel_selection,
|
|
62
|
+
slicing_dict={},
|
|
63
|
+
)
|
|
64
|
+
self._output_slicing_kwargs = add_channel_selection_to_slicing_dict(
|
|
65
|
+
image=self._output,
|
|
66
|
+
channel_selection=output_channel_selection,
|
|
67
|
+
slicing_dict={},
|
|
68
|
+
)
|
|
69
|
+
self._input_channel_selection = input_channel_selection
|
|
70
|
+
self._output_channel_selection = output_channel_selection
|
|
71
|
+
self._axes_order = axes_order
|
|
72
|
+
self._input_transforms = input_transforms
|
|
73
|
+
self._output_transforms = output_transforms
|
|
74
|
+
|
|
75
|
+
self._input.require_dimensions_match(self._output, allow_singleton=True)
|
|
76
|
+
|
|
77
|
+
def get_init_kwargs(self) -> dict:
|
|
78
|
+
"""Return the initialization arguments for the iterator."""
|
|
79
|
+
return {
|
|
80
|
+
"input_image": self._input,
|
|
81
|
+
"output_image": self._output,
|
|
82
|
+
"input_channel_selection": self._input_channel_selection,
|
|
83
|
+
"output_channel_selection": self._output_channel_selection,
|
|
84
|
+
"axes_order": self._axes_order,
|
|
85
|
+
"input_transforms": self._input_transforms,
|
|
86
|
+
"output_transforms": self._output_transforms,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def build_numpy_getter(self, roi: Roi) -> DataGetterProtocol[np.ndarray]:
|
|
90
|
+
return NumpyRoiGetter(
|
|
91
|
+
zarr_array=self._input.zarr_array,
|
|
92
|
+
dimensions=self._input.dimensions,
|
|
93
|
+
roi=roi,
|
|
94
|
+
axes_order=self._axes_order,
|
|
95
|
+
transforms=self._input_transforms,
|
|
96
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def build_numpy_setter(self, roi: Roi) -> DataSetterProtocol[np.ndarray]:
|
|
100
|
+
return NumpyRoiSetter(
|
|
101
|
+
zarr_array=self._output.zarr_array,
|
|
102
|
+
dimensions=self._output.dimensions,
|
|
103
|
+
roi=roi,
|
|
104
|
+
axes_order=self._axes_order,
|
|
105
|
+
transforms=self._output_transforms,
|
|
106
|
+
slicing_dict=self._output_slicing_kwargs,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def build_dask_getter(self, roi: Roi) -> DataGetterProtocol[da.Array]:
|
|
110
|
+
return DaskRoiGetter(
|
|
111
|
+
zarr_array=self._input.zarr_array,
|
|
112
|
+
dimensions=self._input.dimensions,
|
|
113
|
+
roi=roi,
|
|
114
|
+
axes_order=self._axes_order,
|
|
115
|
+
transforms=self._input_transforms,
|
|
116
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def build_dask_setter(self, roi: Roi) -> DataSetterProtocol[da.Array]:
|
|
120
|
+
return DaskRoiSetter(
|
|
121
|
+
zarr_array=self._output.zarr_array,
|
|
122
|
+
dimensions=self._output.dimensions,
|
|
123
|
+
roi=roi,
|
|
124
|
+
axes_order=self._axes_order,
|
|
125
|
+
transforms=self._output_transforms,
|
|
126
|
+
slicing_dict=self._output_slicing_kwargs,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def post_consolidate(self):
|
|
130
|
+
self._output.consolidate()
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Mappers for iterators.
|
|
2
|
+
|
|
3
|
+
Mappers are classes that can be passed to the `map` method of iterators to
|
|
4
|
+
transform the items yielded by the iterator.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from collections.abc import Callable, Iterable
|
|
9
|
+
from typing import Generic, Protocol, TypeVar
|
|
10
|
+
|
|
11
|
+
from ngio.io_pipes._io_pipes_types import DataGetterProtocol, DataSetterProtocol
|
|
12
|
+
from ngio.utils import NgioValueError
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MapperProtocol(Protocol[T]):
|
|
18
|
+
"""Protocol for mappers."""
|
|
19
|
+
|
|
20
|
+
def __call__(
|
|
21
|
+
self,
|
|
22
|
+
func: Callable[[T], T],
|
|
23
|
+
getters: Iterable[DataGetterProtocol[T]],
|
|
24
|
+
setters: Iterable[DataSetterProtocol[T] | None],
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Map an item to another item."""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BasicMapper(Generic[T]):
|
|
31
|
+
"""A basic mapper that simply applies a function to the data."""
|
|
32
|
+
|
|
33
|
+
def __call__(
|
|
34
|
+
self,
|
|
35
|
+
func: Callable[[T], T],
|
|
36
|
+
getters: Iterable[DataGetterProtocol[T]],
|
|
37
|
+
setters: Iterable[DataSetterProtocol[T] | None],
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Map an item to another item."""
|
|
40
|
+
for getter, setter in zip(getters, setters, strict=True):
|
|
41
|
+
data = getter()
|
|
42
|
+
data = func(data)
|
|
43
|
+
if setter is None:
|
|
44
|
+
raise NgioValueError(
|
|
45
|
+
"Error in BasicMapper: setter is None, "
|
|
46
|
+
"this iterator is read-only, mapping is not possible."
|
|
47
|
+
)
|
|
48
|
+
setter(data)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from ngio import Roi
|
|
2
|
+
from ngio.images._abstract_image import AbstractImage
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def rois_product(rois_a: list[Roi], rois_b: list[Roi]) -> list[Roi]:
|
|
6
|
+
"""Compute the product of two sets of ROIs."""
|
|
7
|
+
rois_product = []
|
|
8
|
+
for roi_a in rois_a:
|
|
9
|
+
for roi_b in rois_b:
|
|
10
|
+
intersection = roi_a.intersection(roi_b)
|
|
11
|
+
if intersection:
|
|
12
|
+
rois_product.append(intersection)
|
|
13
|
+
return rois_product
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def grid(
|
|
17
|
+
rois: list[Roi],
|
|
18
|
+
ref_image: AbstractImage,
|
|
19
|
+
size_x: int | None = None,
|
|
20
|
+
size_y: int | None = None,
|
|
21
|
+
size_z: int | None = None,
|
|
22
|
+
size_t: int | None = None,
|
|
23
|
+
stride_x: int | None = None,
|
|
24
|
+
stride_y: int | None = None,
|
|
25
|
+
stride_z: int | None = None,
|
|
26
|
+
stride_t: int | None = None,
|
|
27
|
+
base_name: str | None = None,
|
|
28
|
+
) -> list[Roi]:
|
|
29
|
+
"""This method is a placeholder for creating a regular grid of ROIs."""
|
|
30
|
+
t_dim = ref_image.dimensions.get("t", default=1)
|
|
31
|
+
z_dim = ref_image.dimensions.get("z", default=1)
|
|
32
|
+
y_dim = ref_image.dimensions.get("y", default=1)
|
|
33
|
+
x_dim = ref_image.dimensions.get("x", default=1)
|
|
34
|
+
|
|
35
|
+
size_t = size_t if size_t is not None else t_dim
|
|
36
|
+
size_z = size_z if size_z is not None else z_dim
|
|
37
|
+
size_y = size_y if size_y is not None else y_dim
|
|
38
|
+
size_x = size_x if size_x is not None else x_dim
|
|
39
|
+
|
|
40
|
+
stride_t = stride_t if stride_t is not None else size_t
|
|
41
|
+
stride_z = stride_z if stride_z is not None else size_z
|
|
42
|
+
stride_y = stride_y if stride_y is not None else size_y
|
|
43
|
+
stride_x = stride_x if stride_x is not None else size_x
|
|
44
|
+
|
|
45
|
+
# Here we would create a grid of ROIs based on the specified parameters.
|
|
46
|
+
new_rois = []
|
|
47
|
+
for t in range(0, t_dim, stride_t):
|
|
48
|
+
for z in range(0, z_dim, stride_z):
|
|
49
|
+
for y in range(0, y_dim, stride_y):
|
|
50
|
+
for x in range(0, x_dim, stride_x):
|
|
51
|
+
roi = Roi.from_values(
|
|
52
|
+
name=base_name,
|
|
53
|
+
slices={
|
|
54
|
+
"x": (x, size_x),
|
|
55
|
+
"y": (y, size_y),
|
|
56
|
+
"z": (z, size_z),
|
|
57
|
+
"t": (t, size_t),
|
|
58
|
+
},
|
|
59
|
+
space="pixel",
|
|
60
|
+
)
|
|
61
|
+
new_rois.append(roi.to_world(pixel_size=ref_image.pixel_size))
|
|
62
|
+
|
|
63
|
+
return rois_product(rois, new_rois)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def by_yx(rois: list[Roi], ref_image: AbstractImage) -> list[Roi]:
|
|
67
|
+
"""Return a new iterator that iterates over ROIs by YX coordinates."""
|
|
68
|
+
return grid(
|
|
69
|
+
rois=rois,
|
|
70
|
+
ref_image=ref_image,
|
|
71
|
+
size_z=1,
|
|
72
|
+
stride_z=1,
|
|
73
|
+
size_t=1,
|
|
74
|
+
stride_t=1,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def by_zyx(rois: list[Roi], ref_image: AbstractImage, strict: bool = True) -> list[Roi]:
|
|
79
|
+
"""Return a new iterator that iterates over ROIs by ZYX coordinates."""
|
|
80
|
+
if strict and not ref_image.is_3d:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"Reference Input image must be 3D to iterate by ZXY coordinates. "
|
|
83
|
+
f"Current dimensions: {ref_image.dimensions}"
|
|
84
|
+
)
|
|
85
|
+
return grid(
|
|
86
|
+
rois=rois,
|
|
87
|
+
ref_image=ref_image,
|
|
88
|
+
size_t=1,
|
|
89
|
+
stride_t=1,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def by_chunks(
|
|
94
|
+
rois: list[Roi],
|
|
95
|
+
ref_image: AbstractImage,
|
|
96
|
+
overlap_xy: int = 0,
|
|
97
|
+
overlap_z: int = 0,
|
|
98
|
+
overlap_t: int = 0,
|
|
99
|
+
) -> list[Roi]:
|
|
100
|
+
"""This method is a placeholder for chunked processing."""
|
|
101
|
+
chunk_size = ref_image.chunks
|
|
102
|
+
t_axis = ref_image.axes_handler.get_index("t")
|
|
103
|
+
z_axis = ref_image.axes_handler.get_index("z")
|
|
104
|
+
y_axis = ref_image.axes_handler.get_index("y")
|
|
105
|
+
x_axis = ref_image.axes_handler.get_index("x")
|
|
106
|
+
|
|
107
|
+
size_x = chunk_size[x_axis] if x_axis is not None else None
|
|
108
|
+
size_y = chunk_size[y_axis] if y_axis is not None else None
|
|
109
|
+
size_z = chunk_size[z_axis] if z_axis is not None else None
|
|
110
|
+
size_t = chunk_size[t_axis] if t_axis is not None else None
|
|
111
|
+
stride_x = size_x - overlap_xy if size_x is not None else None
|
|
112
|
+
stride_y = size_y - overlap_xy if size_y is not None else None
|
|
113
|
+
stride_z = size_z - overlap_z if size_z is not None else None
|
|
114
|
+
stride_t = size_t - overlap_t if size_t is not None else None
|
|
115
|
+
return grid(
|
|
116
|
+
rois=rois,
|
|
117
|
+
ref_image=ref_image,
|
|
118
|
+
size_x=size_x,
|
|
119
|
+
size_y=size_y,
|
|
120
|
+
size_z=size_z,
|
|
121
|
+
size_t=size_t,
|
|
122
|
+
stride_x=stride_x,
|
|
123
|
+
stride_y=stride_y,
|
|
124
|
+
stride_z=stride_z,
|
|
125
|
+
stride_t=stride_t,
|
|
126
|
+
)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
|
|
3
|
+
import dask.array as da
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from ngio.common import Roi
|
|
7
|
+
from ngio.experimental.iterators._abstract_iterator import AbstractIteratorBuilder
|
|
8
|
+
from ngio.images import Image, Label
|
|
9
|
+
from ngio.images._image import (
|
|
10
|
+
ChannelSlicingInputType,
|
|
11
|
+
add_channel_selection_to_slicing_dict,
|
|
12
|
+
)
|
|
13
|
+
from ngio.images._masked_image import MaskedImage
|
|
14
|
+
from ngio.io_pipes import (
|
|
15
|
+
DaskGetterMasked,
|
|
16
|
+
DaskRoiGetter,
|
|
17
|
+
DaskRoiSetter,
|
|
18
|
+
DaskSetterMasked,
|
|
19
|
+
NumpyGetterMasked,
|
|
20
|
+
NumpyRoiGetter,
|
|
21
|
+
NumpyRoiSetter,
|
|
22
|
+
NumpySetterMasked,
|
|
23
|
+
TransformProtocol,
|
|
24
|
+
)
|
|
25
|
+
from ngio.io_pipes._io_pipes_types import DataGetterProtocol, DataSetterProtocol
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SegmentationIterator(AbstractIteratorBuilder[np.ndarray, da.Array]):
|
|
29
|
+
"""Base class for iterators over ROIs."""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
input_image: Image,
|
|
34
|
+
output_label: Label,
|
|
35
|
+
channel_selection: ChannelSlicingInputType = None,
|
|
36
|
+
axes_order: Sequence[str] | None = None,
|
|
37
|
+
input_transforms: Sequence[TransformProtocol] | None = None,
|
|
38
|
+
output_transforms: Sequence[TransformProtocol] | None = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Initialize the iterator with a ROI table and input/output images.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
input_image (Image): The input image to be used as input for the
|
|
44
|
+
segmentation.
|
|
45
|
+
output_label (Label): The label image where the ROIs will be written.
|
|
46
|
+
channel_selection (ChannelSlicingInputType): Optional
|
|
47
|
+
selection of channels to use for the segmentation.
|
|
48
|
+
axes_order (Sequence[str] | None): Optional axes order for the
|
|
49
|
+
segmentation.
|
|
50
|
+
input_transforms (Sequence[TransformProtocol] | None): Optional
|
|
51
|
+
transforms to apply to the input image.
|
|
52
|
+
output_transforms (Sequence[TransformProtocol] | None): Optional
|
|
53
|
+
transforms to apply to the output label.
|
|
54
|
+
"""
|
|
55
|
+
self._input = input_image
|
|
56
|
+
self._output = output_label
|
|
57
|
+
self._ref_image = input_image
|
|
58
|
+
self._rois = input_image.build_image_roi_table(name=None).rois()
|
|
59
|
+
|
|
60
|
+
# Set iteration parameters
|
|
61
|
+
self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
|
|
62
|
+
image=self._input, channel_selection=channel_selection, slicing_dict={}
|
|
63
|
+
)
|
|
64
|
+
self._channel_selection = channel_selection
|
|
65
|
+
self._axes_order = axes_order
|
|
66
|
+
self._input_transforms = input_transforms
|
|
67
|
+
self._output_transforms = output_transforms
|
|
68
|
+
|
|
69
|
+
self._input.require_dimensions_match(self._output, allow_singleton=False)
|
|
70
|
+
|
|
71
|
+
def get_init_kwargs(self) -> dict:
|
|
72
|
+
"""Return the initialization arguments for the iterator."""
|
|
73
|
+
return {
|
|
74
|
+
"input_image": self._input,
|
|
75
|
+
"output_label": self._output,
|
|
76
|
+
"channel_selection": self._channel_selection,
|
|
77
|
+
"axes_order": self._axes_order,
|
|
78
|
+
"input_transforms": self._input_transforms,
|
|
79
|
+
"output_transforms": self._output_transforms,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
def build_numpy_getter(self, roi: Roi) -> DataGetterProtocol[np.ndarray]:
|
|
83
|
+
return NumpyRoiGetter(
|
|
84
|
+
zarr_array=self._input.zarr_array,
|
|
85
|
+
dimensions=self._input.dimensions,
|
|
86
|
+
roi=roi,
|
|
87
|
+
axes_order=self._axes_order,
|
|
88
|
+
transforms=self._input_transforms,
|
|
89
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def build_numpy_setter(self, roi: Roi) -> DataSetterProtocol[np.ndarray]:
|
|
93
|
+
return NumpyRoiSetter(
|
|
94
|
+
zarr_array=self._output.zarr_array,
|
|
95
|
+
dimensions=self._output.dimensions,
|
|
96
|
+
roi=roi,
|
|
97
|
+
axes_order=self._axes_order,
|
|
98
|
+
transforms=self._output_transforms,
|
|
99
|
+
remove_channel_selection=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def build_dask_getter(self, roi: Roi) -> DataGetterProtocol[da.Array]:
|
|
103
|
+
return DaskRoiGetter(
|
|
104
|
+
zarr_array=self._input.zarr_array,
|
|
105
|
+
dimensions=self._input.dimensions,
|
|
106
|
+
roi=roi,
|
|
107
|
+
axes_order=self._axes_order,
|
|
108
|
+
transforms=self._input_transforms,
|
|
109
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def build_dask_setter(self, roi: Roi) -> DataSetterProtocol[da.Array]:
|
|
113
|
+
return DaskRoiSetter(
|
|
114
|
+
zarr_array=self._output.zarr_array,
|
|
115
|
+
dimensions=self._output.dimensions,
|
|
116
|
+
roi=roi,
|
|
117
|
+
axes_order=self._axes_order,
|
|
118
|
+
transforms=self._output_transforms,
|
|
119
|
+
remove_channel_selection=True,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def post_consolidate(self):
|
|
123
|
+
self._output.consolidate()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class MaskedSegmentationIterator(SegmentationIterator):
|
|
127
|
+
"""Base class for iterators over ROIs."""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
input_image: MaskedImage,
|
|
132
|
+
output_label: Label,
|
|
133
|
+
channel_selection: ChannelSlicingInputType = None,
|
|
134
|
+
axes_order: Sequence[str] | None = None,
|
|
135
|
+
input_transforms: Sequence[TransformProtocol] | None = None,
|
|
136
|
+
output_transforms: Sequence[TransformProtocol] | None = None,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Initialize the iterator with a ROI table and input/output images.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
input_image (MaskedImage): The input image to be used as input for the
|
|
142
|
+
segmentation.
|
|
143
|
+
output_label (Label): The label image where the ROIs will be written.
|
|
144
|
+
channel_selection (ChannelSlicingInputType): Optional
|
|
145
|
+
selection of channels to use for the segmentation.
|
|
146
|
+
axes_order (Sequence[str] | None): Optional axes order for the
|
|
147
|
+
segmentation.
|
|
148
|
+
input_transforms (Sequence[TransformProtocol] | None): Optional
|
|
149
|
+
transforms to apply to the input image.
|
|
150
|
+
output_transforms (Sequence[TransformProtocol] | None): Optional
|
|
151
|
+
transforms to apply to the output label.
|
|
152
|
+
"""
|
|
153
|
+
self._input = input_image
|
|
154
|
+
self._output = output_label
|
|
155
|
+
|
|
156
|
+
self._ref_image = input_image
|
|
157
|
+
self._set_rois(input_image._masking_roi_table.rois())
|
|
158
|
+
|
|
159
|
+
# Set iteration parameters
|
|
160
|
+
self._input_slicing_kwargs = add_channel_selection_to_slicing_dict(
|
|
161
|
+
image=self._input, channel_selection=channel_selection, slicing_dict={}
|
|
162
|
+
)
|
|
163
|
+
self._channel_selection = channel_selection
|
|
164
|
+
self._axes_order = axes_order
|
|
165
|
+
self._input_transforms = input_transforms
|
|
166
|
+
self._output_transforms = output_transforms
|
|
167
|
+
|
|
168
|
+
# Check compatibility between input and output images
|
|
169
|
+
# if not self._input.dimensions.is_compatible_with(self._output.dimensions):
|
|
170
|
+
# raise NgioValidationError(
|
|
171
|
+
# "Input image and output label have incompatible dimensions. "
|
|
172
|
+
# f"Input: {self._input.dimensions}, Output: {self._output.dimensions}."
|
|
173
|
+
# )
|
|
174
|
+
|
|
175
|
+
def get_init_kwargs(self) -> dict:
|
|
176
|
+
"""Return the initialization arguments for the iterator."""
|
|
177
|
+
return {
|
|
178
|
+
"input_image": self._input,
|
|
179
|
+
"output_label": self._output,
|
|
180
|
+
"channel_selection": self._channel_selection,
|
|
181
|
+
"axes_order": self._axes_order,
|
|
182
|
+
"input_transforms": self._input_transforms,
|
|
183
|
+
"output_transforms": self._output_transforms,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
def build_numpy_getter(self, roi: Roi):
|
|
187
|
+
return NumpyGetterMasked(
|
|
188
|
+
zarr_array=self._input.zarr_array,
|
|
189
|
+
dimensions=self._input.dimensions,
|
|
190
|
+
roi=roi,
|
|
191
|
+
label_zarr_array=self._input._label.zarr_array,
|
|
192
|
+
label_dimensions=self._input._label.dimensions,
|
|
193
|
+
axes_order=self._axes_order,
|
|
194
|
+
transforms=self._input_transforms,
|
|
195
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
def build_numpy_setter(self, roi: Roi):
|
|
199
|
+
return NumpySetterMasked(
|
|
200
|
+
roi=roi,
|
|
201
|
+
zarr_array=self._output.zarr_array,
|
|
202
|
+
dimensions=self._output.dimensions,
|
|
203
|
+
label_zarr_array=self._input._label.zarr_array,
|
|
204
|
+
label_dimensions=self._input._label.dimensions,
|
|
205
|
+
axes_order=self._axes_order,
|
|
206
|
+
transforms=self._output_transforms,
|
|
207
|
+
remove_channel_selection=True,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
def build_dask_getter(self, roi: Roi):
|
|
211
|
+
return DaskGetterMasked(
|
|
212
|
+
roi=roi,
|
|
213
|
+
zarr_array=self._input.zarr_array,
|
|
214
|
+
dimensions=self._input.dimensions,
|
|
215
|
+
label_zarr_array=self._input._label.zarr_array,
|
|
216
|
+
label_dimensions=self._input._label.dimensions,
|
|
217
|
+
axes_order=self._axes_order,
|
|
218
|
+
transforms=self._input_transforms,
|
|
219
|
+
slicing_dict=self._input_slicing_kwargs,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def build_dask_setter(self, roi: Roi):
|
|
223
|
+
return DaskSetterMasked(
|
|
224
|
+
roi=roi,
|
|
225
|
+
zarr_array=self._output.zarr_array,
|
|
226
|
+
dimensions=self._output.dimensions,
|
|
227
|
+
label_zarr_array=self._input._label.zarr_array,
|
|
228
|
+
label_dimensions=self._input._label.dimensions,
|
|
229
|
+
axes_order=self._axes_order,
|
|
230
|
+
transforms=self._output_transforms,
|
|
231
|
+
remove_channel_selection=True,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def post_consolidate(self):
|
|
235
|
+
self._output.consolidate()
|
ngio/hcs/__init__.py
CHANGED
|
@@ -1,60 +1,19 @@
|
|
|
1
1
|
"""OME-Zarr HCS objects models."""
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def columns(self) -> list[str]:
|
|
21
|
-
"""Return the number of columns."""
|
|
22
|
-
raise NotImplementedError
|
|
23
|
-
|
|
24
|
-
def rows(self) -> list[str]:
|
|
25
|
-
"""Return the number of rows."""
|
|
26
|
-
raise NotImplementedError
|
|
27
|
-
|
|
28
|
-
def get_omezarr_well(self, *args, **kwargs) -> "OmeZarrWell":
|
|
29
|
-
"""Return the OME-Zarr well."""
|
|
30
|
-
raise NotImplementedError
|
|
31
|
-
|
|
32
|
-
def get_omezarr_image(self, *args, **kwargs) -> "OmeZarrContainer":
|
|
33
|
-
"""Return the OME-Zarr image."""
|
|
34
|
-
raise NotImplementedError
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class OmeZarrWell:
|
|
38
|
-
"""Placeholder for the Image object."""
|
|
39
|
-
|
|
40
|
-
def __init__(self, *args, **kwargs):
|
|
41
|
-
"""Initialize the OME-Zarr well."""
|
|
42
|
-
raise NotImplementedError
|
|
43
|
-
|
|
44
|
-
def acquisitions(self) -> list[str]:
|
|
45
|
-
"""Return the acquisition."""
|
|
46
|
-
raise NotImplementedError
|
|
47
|
-
|
|
48
|
-
def get_ome_zarr_image(self, *args, **kwargs) -> "OmeZarrContainer":
|
|
49
|
-
"""Return the OME-Zarr image."""
|
|
50
|
-
raise NotImplementedError
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def open_omezarr_plate(*args, **kwargs):
|
|
54
|
-
"""Open an OME-Zarr plate."""
|
|
55
|
-
return OmeZarrPlate(*args, **kwargs)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def open_omezarr_well(*args, **kwargs):
|
|
59
|
-
"""Open an OME-Zarr well."""
|
|
60
|
-
return OmeZarrWell(*args, **kwargs)
|
|
3
|
+
from ngio.hcs._plate import (
|
|
4
|
+
OmeZarrPlate,
|
|
5
|
+
OmeZarrWell,
|
|
6
|
+
create_empty_plate,
|
|
7
|
+
create_empty_well,
|
|
8
|
+
open_ome_zarr_plate,
|
|
9
|
+
open_ome_zarr_well,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"OmeZarrPlate",
|
|
14
|
+
"OmeZarrWell",
|
|
15
|
+
"create_empty_plate",
|
|
16
|
+
"create_empty_well",
|
|
17
|
+
"open_ome_zarr_plate",
|
|
18
|
+
"open_ome_zarr_well",
|
|
19
|
+
]
|