ngio 0.4.0a3__py3-none-any.whl → 0.4.0b1__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.
Files changed (54) hide show
  1. ngio/__init__.py +1 -2
  2. ngio/common/__init__.py +2 -51
  3. ngio/common/_dimensions.py +253 -74
  4. ngio/common/_pyramid.py +42 -23
  5. ngio/common/_roi.py +49 -413
  6. ngio/common/_zoom.py +32 -7
  7. ngio/experimental/iterators/__init__.py +0 -2
  8. ngio/experimental/iterators/_abstract_iterator.py +246 -26
  9. ngio/experimental/iterators/_feature.py +90 -52
  10. ngio/experimental/iterators/_image_processing.py +24 -63
  11. ngio/experimental/iterators/_mappers.py +48 -0
  12. ngio/experimental/iterators/_rois_utils.py +4 -4
  13. ngio/experimental/iterators/_segmentation.py +38 -85
  14. ngio/images/_abstract_image.py +192 -95
  15. ngio/images/_create.py +16 -0
  16. ngio/images/_create_synt_container.py +10 -0
  17. ngio/images/_image.py +35 -9
  18. ngio/images/_label.py +26 -3
  19. ngio/images/_masked_image.py +45 -61
  20. ngio/images/_ome_zarr_container.py +33 -0
  21. ngio/io_pipes/__init__.py +75 -0
  22. ngio/io_pipes/_io_pipes.py +361 -0
  23. ngio/io_pipes/_io_pipes_masked.py +488 -0
  24. ngio/io_pipes/_io_pipes_roi.py +152 -0
  25. ngio/io_pipes/_io_pipes_types.py +56 -0
  26. ngio/io_pipes/_match_shape.py +376 -0
  27. ngio/io_pipes/_ops_axes.py +344 -0
  28. ngio/io_pipes/_ops_slices.py +446 -0
  29. ngio/io_pipes/_ops_slices_utils.py +196 -0
  30. ngio/io_pipes/_ops_transforms.py +104 -0
  31. ngio/io_pipes/_zoom_transform.py +175 -0
  32. ngio/ome_zarr_meta/__init__.py +4 -2
  33. ngio/ome_zarr_meta/ngio_specs/__init__.py +4 -4
  34. ngio/ome_zarr_meta/ngio_specs/_axes.py +129 -141
  35. ngio/ome_zarr_meta/ngio_specs/_dataset.py +47 -121
  36. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +30 -22
  37. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +17 -1
  38. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +33 -30
  39. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  40. ngio/resources/__init__.py +1 -0
  41. ngio/resources/resource_model.py +1 -0
  42. ngio/{common/transforms → transforms}/__init__.py +1 -1
  43. ngio/transforms/_zoom.py +19 -0
  44. ngio/utils/_datasets.py +5 -0
  45. ngio/utils/_zarr_utils.py +5 -1
  46. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/METADATA +1 -1
  47. ngio-0.4.0b1.dist-info/RECORD +85 -0
  48. ngio/common/_array_io_pipes.py +0 -554
  49. ngio/common/_array_io_utils.py +0 -508
  50. ngio/common/transforms/_label.py +0 -12
  51. ngio/common/transforms/_zoom.py +0 -109
  52. ngio-0.4.0a3.dist-info/RECORD +0 -76
  53. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/WHEEL +0 -0
  54. {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -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)
@@ -100,10 +100,10 @@ def by_chunks(
100
100
  ) -> list[Roi]:
101
101
  """This method is a placeholder for chunked processing."""
102
102
  chunk_size = ref_image.chunks
103
- t_axis = ref_image.axes_mapper.get_index("t")
104
- z_axis = ref_image.axes_mapper.get_index("z")
105
- y_axis = ref_image.axes_mapper.get_index("y")
106
- x_axis = ref_image.axes_mapper.get_index("x")
103
+ t_axis = ref_image.axes_handler.get_index("t")
104
+ z_axis = ref_image.axes_handler.get_index("z")
105
+ y_axis = ref_image.axes_handler.get_index("y")
106
+ x_axis = ref_image.axes_handler.get_index("x")
107
107
 
108
108
  size_x = chunk_size[x_axis] if x_axis is not None else None
109
109
  size_y = chunk_size[y_axis] if y_axis is not None else None
@@ -1,20 +1,9 @@
1
- from collections.abc import Callable, Generator, Sequence
1
+ from collections.abc import Sequence
2
2
 
3
3
  import dask.array as da
4
4
  import numpy as np
5
5
 
6
- from ngio.common import (
7
- Roi,
8
- TransformProtocol,
9
- build_roi_dask_getter,
10
- build_roi_dask_setter,
11
- build_roi_masked_dask_getter,
12
- build_roi_masked_dask_setter,
13
- build_roi_masked_numpy_getter,
14
- build_roi_masked_numpy_setter,
15
- build_roi_numpy_getter,
16
- build_roi_numpy_setter,
17
- )
6
+ from ngio.common import Roi
18
7
  from ngio.experimental.iterators._abstract_iterator import AbstractIteratorBuilder
19
8
  from ngio.images import Image, Label
20
9
  from ngio.images._image import (
@@ -22,10 +11,21 @@ from ngio.images._image import (
22
11
  add_channel_selection_to_slicing_dict,
23
12
  )
24
13
  from ngio.images._masked_image import MaskedImage
25
- from ngio.utils._errors import NgioValidationError
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
26
 
27
27
 
28
- class SegmentationIterator(AbstractIteratorBuilder):
28
+ class SegmentationIterator(AbstractIteratorBuilder[np.ndarray, da.Array]):
29
29
  """Base class for iterators over ROIs."""
30
30
 
31
31
  def __init__(
@@ -66,12 +66,7 @@ class SegmentationIterator(AbstractIteratorBuilder):
66
66
  self._input_transforms = input_transforms
67
67
  self._output_transforms = output_transforms
68
68
 
69
- # Check compatibility between input and output images
70
- if not self._input.dimensions.is_compatible_with(self._output.dimensions):
71
- raise NgioValidationError(
72
- "Input image and output label have incompatible dimensions. "
73
- f"Input: {self._input.dimensions}, Output: {self._output.dimensions}."
74
- )
69
+ self._input.require_dimensions_match(self._output, allow_singleton=False)
75
70
 
76
71
  def get_init_kwargs(self) -> dict:
77
72
  """Return the initialization arguments for the iterator."""
@@ -84,83 +79,49 @@ class SegmentationIterator(AbstractIteratorBuilder):
84
79
  "output_transforms": self._output_transforms,
85
80
  }
86
81
 
87
- def build_numpy_getter(self, roi: Roi):
88
- return build_roi_numpy_getter(
82
+ def build_numpy_getter(self, roi: Roi) -> DataGetterProtocol[np.ndarray]:
83
+ return NumpyRoiGetter(
89
84
  zarr_array=self._input.zarr_array,
90
85
  dimensions=self._input.dimensions,
86
+ roi=roi,
91
87
  axes_order=self._axes_order,
92
88
  transforms=self._input_transforms,
93
- pixel_size=self._input.pixel_size,
94
- roi=roi,
95
89
  slicing_dict=self._input_slicing_kwargs,
96
90
  )
97
91
 
98
- def build_numpy_setter(self, roi: Roi):
99
- return build_roi_numpy_setter(
92
+ def build_numpy_setter(self, roi: Roi) -> DataSetterProtocol[np.ndarray]:
93
+ return NumpyRoiSetter(
100
94
  zarr_array=self._output.zarr_array,
101
95
  dimensions=self._output.dimensions,
96
+ roi=roi,
102
97
  axes_order=self._axes_order,
103
98
  transforms=self._output_transforms,
104
- pixel_size=self._output.pixel_size,
105
- roi=roi,
106
99
  remove_channel_selection=True,
107
100
  )
108
101
 
109
- def build_dask_getter(self, roi: Roi):
110
- return build_roi_dask_getter(
102
+ def build_dask_getter(self, roi: Roi) -> DataGetterProtocol[da.Array]:
103
+ return DaskRoiGetter(
111
104
  zarr_array=self._input.zarr_array,
112
105
  dimensions=self._input.dimensions,
106
+ roi=roi,
113
107
  axes_order=self._axes_order,
114
108
  transforms=self._input_transforms,
115
- pixel_size=self._input.pixel_size,
116
- roi=roi,
117
109
  slicing_dict=self._input_slicing_kwargs,
118
110
  )
119
111
 
120
- def build_dask_setter(self, roi: Roi):
121
- return build_roi_dask_setter(
112
+ def build_dask_setter(self, roi: Roi) -> DataSetterProtocol[da.Array]:
113
+ return DaskRoiSetter(
122
114
  zarr_array=self._output.zarr_array,
123
115
  dimensions=self._output.dimensions,
116
+ roi=roi,
124
117
  axes_order=self._axes_order,
125
118
  transforms=self._output_transforms,
126
- pixel_size=self._output.pixel_size,
127
- roi=roi,
128
119
  remove_channel_selection=True,
129
120
  )
130
121
 
131
122
  def post_consolidate(self):
132
123
  self._output.consolidate()
133
124
 
134
- def iter_as_numpy(
135
- self,
136
- ) -> Generator[tuple[np.ndarray, Callable[[np.ndarray], None]]]:
137
- """Create an iterator over the pixels of the ROIs as Dask arrays.
138
-
139
- Returns:
140
- Generator[tuple[da.Array, DaskWriter]]: An iterator the input
141
- image as Dask arrays and a writer to write the output
142
- to the label image.
143
- """
144
- return super().iter_as_numpy()
145
-
146
- def map_as_numpy(self, func: Callable[[np.ndarray], np.ndarray]) -> None:
147
- """Apply a transformation function to the ROI pixels."""
148
- return super().map_as_numpy(func)
149
-
150
- def iter_as_dask(self) -> Generator[tuple[da.Array, Callable[[da.Array], None]]]:
151
- """Create an iterator over the pixels of the ROIs as Dask arrays.
152
-
153
- Returns:
154
- Generator[tuple[da.Array, DaskWriter]]: An iterator the input
155
- image as Dask arrays and a writer to write the output
156
- to the label image.
157
- """
158
- return super().iter_as_dask()
159
-
160
- def map_as_dask(self, func: Callable[[da.Array], da.Array]) -> None:
161
- """Apply a transformation function to the ROI pixels."""
162
- return super().map_as_dask(func)
163
-
164
125
 
165
126
  class MaskedSegmentationIterator(SegmentationIterator):
166
127
  """Base class for iterators over ROIs."""
@@ -205,11 +166,11 @@ class MaskedSegmentationIterator(SegmentationIterator):
205
166
  self._output_transforms = output_transforms
206
167
 
207
168
  # Check compatibility between input and output images
208
- if not self._input.dimensions.is_compatible_with(self._output.dimensions):
209
- raise NgioValidationError(
210
- "Input image and output label have incompatible dimensions. "
211
- f"Input: {self._input.dimensions}, Output: {self._output.dimensions}."
212
- )
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
+ # )
213
174
 
214
175
  def get_init_kwargs(self) -> dict:
215
176
  """Return the initialization arguments for the iterator."""
@@ -223,58 +184,50 @@ class MaskedSegmentationIterator(SegmentationIterator):
223
184
  }
224
185
 
225
186
  def build_numpy_getter(self, roi: Roi):
226
- return build_roi_masked_numpy_getter(
227
- roi=roi,
187
+ return NumpyGetterMasked(
228
188
  zarr_array=self._input.zarr_array,
229
189
  dimensions=self._input.dimensions,
190
+ roi=roi,
230
191
  label_zarr_array=self._input._label.zarr_array,
231
192
  label_dimensions=self._input._label.dimensions,
232
- label_pixel_size=self._input._label.pixel_size,
233
193
  axes_order=self._axes_order,
234
194
  transforms=self._input_transforms,
235
- pixel_size=self._input.pixel_size,
236
195
  slicing_dict=self._input_slicing_kwargs,
237
196
  )
238
197
 
239
198
  def build_numpy_setter(self, roi: Roi):
240
- return build_roi_masked_numpy_setter(
199
+ return NumpySetterMasked(
241
200
  roi=roi,
242
201
  zarr_array=self._output.zarr_array,
243
202
  dimensions=self._output.dimensions,
244
203
  label_zarr_array=self._input._label.zarr_array,
245
204
  label_dimensions=self._input._label.dimensions,
246
- label_pixel_size=self._input._label.pixel_size,
247
205
  axes_order=self._axes_order,
248
206
  transforms=self._output_transforms,
249
- pixel_size=self._output.pixel_size,
250
207
  remove_channel_selection=True,
251
208
  )
252
209
 
253
210
  def build_dask_getter(self, roi: Roi):
254
- return build_roi_masked_dask_getter(
211
+ return DaskGetterMasked(
255
212
  roi=roi,
256
213
  zarr_array=self._input.zarr_array,
257
214
  dimensions=self._input.dimensions,
258
215
  label_zarr_array=self._input._label.zarr_array,
259
216
  label_dimensions=self._input._label.dimensions,
260
- label_pixel_size=self._input._label.pixel_size,
261
217
  axes_order=self._axes_order,
262
218
  transforms=self._input_transforms,
263
- pixel_size=self._input.pixel_size,
264
219
  slicing_dict=self._input_slicing_kwargs,
265
220
  )
266
221
 
267
222
  def build_dask_setter(self, roi: Roi):
268
- return build_roi_masked_dask_setter(
223
+ return DaskSetterMasked(
269
224
  roi=roi,
270
225
  zarr_array=self._output.zarr_array,
271
226
  dimensions=self._output.dimensions,
272
227
  label_zarr_array=self._input._label.zarr_array,
273
228
  label_dimensions=self._input._label.dimensions,
274
- label_pixel_size=self._input._label.pixel_size,
275
229
  axes_order=self._axes_order,
276
230
  transforms=self._output_transforms,
277
- pixel_size=self._output.pixel_size,
278
231
  remove_channel_selection=True,
279
232
  )
280
233