ngio 0.4.0a3__py3-none-any.whl → 0.4.0a4__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 (50) hide show
  1. ngio/__init__.py +1 -2
  2. ngio/common/__init__.py +2 -51
  3. ngio/common/_dimensions.py +223 -64
  4. ngio/common/_pyramid.py +42 -23
  5. ngio/common/_roi.py +47 -411
  6. ngio/common/_zoom.py +32 -7
  7. ngio/experimental/iterators/_abstract_iterator.py +2 -2
  8. ngio/experimental/iterators/_feature.py +9 -14
  9. ngio/experimental/iterators/_image_processing.py +17 -27
  10. ngio/experimental/iterators/_rois_utils.py +4 -4
  11. ngio/experimental/iterators/_segmentation.py +37 -53
  12. ngio/images/_abstract_image.py +135 -93
  13. ngio/images/_create.py +16 -0
  14. ngio/images/_create_synt_container.py +10 -0
  15. ngio/images/_image.py +33 -9
  16. ngio/images/_label.py +24 -3
  17. ngio/images/_masked_image.py +60 -81
  18. ngio/images/_ome_zarr_container.py +33 -0
  19. ngio/io_pipes/__init__.py +49 -0
  20. ngio/io_pipes/_io_pipes.py +286 -0
  21. ngio/io_pipes/_io_pipes_masked.py +481 -0
  22. ngio/io_pipes/_io_pipes_roi.py +143 -0
  23. ngio/io_pipes/_io_pipes_utils.py +299 -0
  24. ngio/io_pipes/_match_shape.py +376 -0
  25. ngio/io_pipes/_ops_axes.py +146 -0
  26. ngio/io_pipes/_ops_slices.py +218 -0
  27. ngio/io_pipes/_ops_transforms.py +104 -0
  28. ngio/io_pipes/_zoom_transform.py +175 -0
  29. ngio/ome_zarr_meta/__init__.py +6 -2
  30. ngio/ome_zarr_meta/ngio_specs/__init__.py +6 -4
  31. ngio/ome_zarr_meta/ngio_specs/_axes.py +182 -70
  32. ngio/ome_zarr_meta/ngio_specs/_dataset.py +47 -121
  33. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +30 -22
  34. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +17 -1
  35. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +33 -30
  36. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  37. ngio/resources/__init__.py +1 -0
  38. ngio/resources/resource_model.py +1 -0
  39. ngio/{common/transforms → transforms}/__init__.py +1 -1
  40. ngio/transforms/_zoom.py +19 -0
  41. ngio/utils/_zarr_utils.py +5 -1
  42. {ngio-0.4.0a3.dist-info → ngio-0.4.0a4.dist-info}/METADATA +1 -1
  43. ngio-0.4.0a4.dist-info/RECORD +83 -0
  44. ngio/common/_array_io_pipes.py +0 -554
  45. ngio/common/_array_io_utils.py +0 -508
  46. ngio/common/transforms/_label.py +0 -12
  47. ngio/common/transforms/_zoom.py +0 -109
  48. ngio-0.4.0a3.dist-info/RECORD +0 -76
  49. {ngio-0.4.0a3.dist-info → ngio-0.4.0a4.dist-info}/WHEEL +0 -0
  50. {ngio-0.4.0a3.dist-info → ngio-0.4.0a4.dist-info}/licenses/LICENSE +0 -0
@@ -8,24 +8,26 @@ import numpy as np
8
8
  import zarr
9
9
 
10
10
  from ngio.common import (
11
- ArrayLike,
12
11
  Dimensions,
12
+ InterpolationOrder,
13
13
  Roi,
14
14
  RoiPixels,
15
+ consolidate_pyramid,
16
+ )
17
+ from ngio.io_pipes import (
18
+ DaskGetter,
19
+ DaskRoiGetter,
20
+ DaskRoiSetter,
21
+ DaskSetter,
22
+ NumpyGetter,
23
+ NumpyRoiGetter,
24
+ NumpyRoiSetter,
25
+ NumpySetter,
15
26
  SlicingInputType,
16
27
  TransformProtocol,
17
- build_dask_getter,
18
- build_dask_setter,
19
- build_numpy_getter,
20
- build_numpy_setter,
21
- build_roi_dask_getter,
22
- build_roi_dask_setter,
23
- build_roi_numpy_getter,
24
- build_roi_numpy_setter,
25
- consolidate_pyramid,
26
28
  )
27
29
  from ngio.ome_zarr_meta import (
28
- AxesMapper,
30
+ AxesHandler,
29
31
  Dataset,
30
32
  ImageMetaHandler,
31
33
  LabelMetaHandler,
@@ -61,29 +63,50 @@ class AbstractImage(Generic[_image_handler]):
61
63
  self._group_handler = group_handler
62
64
  self._meta_handler = meta_handler
63
65
 
64
- self._dataset = self._meta_handler.meta.get_dataset(path=path)
65
- self._pixel_size = self._dataset.pixel_size
66
-
67
66
  try:
68
- self._zarr_array = self._group_handler.get_array(self._dataset.path)
67
+ self._zarr_array = self._group_handler.get_array(self._path)
69
68
  except NgioFileExistsError as e:
70
69
  raise NgioFileExistsError(f"Could not find the dataset at {path}.") from e
71
70
 
72
- self._dimensions = Dimensions(
73
- shape=self._zarr_array.shape, axes_mapper=self._dataset.axes_mapper
74
- )
75
-
76
- self._axes_mapper = self._dataset.axes_mapper
77
-
78
71
  def __repr__(self) -> str:
79
72
  """Return a string representation of the image."""
80
73
  return f"Image(path={self.path}, {self.dimensions})"
81
74
 
75
+ @property
76
+ def path(self) -> str:
77
+ """Return the path of the image."""
78
+ return self._path
79
+
82
80
  @property
83
81
  def meta_handler(self) -> _image_handler:
84
82
  """Return the metadata."""
85
83
  return self._meta_handler
86
84
 
85
+ @property
86
+ def dataset(self) -> Dataset:
87
+ """Return the dataset of the image."""
88
+ return self.meta_handler.meta.get_dataset(path=self.path)
89
+
90
+ @property
91
+ def dimensions(self) -> Dimensions:
92
+ """Return the dimensions of the image."""
93
+ return Dimensions(shape=self.zarr_array.shape, dataset=self.dataset)
94
+
95
+ @property
96
+ def pixel_size(self) -> PixelSize:
97
+ """Return the pixel size of the image."""
98
+ return self.dataset.pixel_size
99
+
100
+ @property
101
+ def axes_handler(self) -> AxesHandler:
102
+ """Return the axes handler of the image."""
103
+ return self.dataset.axes_handler
104
+
105
+ @property
106
+ def axes(self) -> tuple[str, ...]:
107
+ """Return the axes of the image."""
108
+ return self.dimensions.axes
109
+
87
110
  @property
88
111
  def zarr_array(self) -> zarr.Array:
89
112
  """Return the Zarr array."""
@@ -104,16 +127,6 @@ class AbstractImage(Generic[_image_handler]):
104
127
  """Return the chunks of the image."""
105
128
  return self.zarr_array.chunks
106
129
 
107
- @property
108
- def dimensions(self) -> Dimensions:
109
- """Return the dimensions of the image."""
110
- return self._dimensions
111
-
112
- @property
113
- def axes_mapper(self) -> AxesMapper:
114
- """Return the axes mapper of the image."""
115
- return self._axes_mapper
116
-
117
130
  @property
118
131
  def is_3d(self) -> bool:
119
132
  """Return True if the image is 3D."""
@@ -147,31 +160,15 @@ class AbstractImage(Generic[_image_handler]):
147
160
  @property
148
161
  def space_unit(self) -> str | None:
149
162
  """Return the space unit of the image."""
150
- return self.meta_handler.meta.space_unit
163
+ return self.axes_handler.space_unit
151
164
 
152
165
  @property
153
166
  def time_unit(self) -> str | None:
154
167
  """Return the time unit of the image."""
155
- return self.meta_handler.meta.time_unit
156
-
157
- @property
158
- def pixel_size(self) -> PixelSize:
159
- """Return the pixel size of the image."""
160
- return self._pixel_size
161
-
162
- @property
163
- def dataset(self) -> Dataset:
164
- """Return the dataset of the image."""
165
- return self._dataset
166
-
167
- @property
168
- def path(self) -> str:
169
- """Return the path of the image."""
170
- return self._dataset.path
168
+ return self.axes_handler.time_unit
171
169
 
172
170
  def has_axis(self, axis: str) -> bool:
173
171
  """Return True if the image has the given axis."""
174
- self.axes_mapper.get_index("x")
175
172
  return self.dimensions.has_axis(axis)
176
173
 
177
174
  def _get_as_numpy(
@@ -190,7 +187,7 @@ class AbstractImage(Generic[_image_handler]):
190
187
  Returns:
191
188
  The array of the region of interest.
192
189
  """
193
- numpy_getter = build_numpy_getter(
190
+ numpy_getter = NumpyGetter(
194
191
  zarr_array=self.zarr_array,
195
192
  dimensions=self.dimensions,
196
193
  axes_order=axes_order,
@@ -217,11 +214,10 @@ class AbstractImage(Generic[_image_handler]):
217
214
  Returns:
218
215
  The array of the region of interest.
219
216
  """
220
- numpy_roi_getter = build_roi_numpy_getter(
217
+ numpy_roi_getter = NumpyRoiGetter(
221
218
  zarr_array=self.zarr_array,
222
219
  dimensions=self.dimensions,
223
220
  roi=roi,
224
- pixel_size=self.pixel_size,
225
221
  axes_order=axes_order,
226
222
  transforms=transforms,
227
223
  slicing_dict=slicing_kwargs,
@@ -241,7 +237,7 @@ class AbstractImage(Generic[_image_handler]):
241
237
  transforms: The transforms to apply to the array.
242
238
  **slicing_kwargs: The slices to get the array.
243
239
  """
244
- dask_getter = build_dask_getter(
240
+ dask_getter = DaskGetter(
245
241
  zarr_array=self.zarr_array,
246
242
  dimensions=self.dimensions,
247
243
  axes_order=axes_order,
@@ -265,11 +261,10 @@ class AbstractImage(Generic[_image_handler]):
265
261
  transforms: The transforms to apply to the array.
266
262
  **slicing_kwargs: The slices to get the array.
267
263
  """
268
- roi_dask_getter = build_roi_dask_getter(
264
+ roi_dask_getter = DaskRoiGetter(
269
265
  zarr_array=self.zarr_array,
270
266
  dimensions=self.dimensions,
271
267
  roi=roi,
272
- pixel_size=self.pixel_size,
273
268
  axes_order=axes_order,
274
269
  transforms=transforms,
275
270
  slicing_dict=slicing_kwargs,
@@ -282,7 +277,7 @@ class AbstractImage(Generic[_image_handler]):
282
277
  transforms: Sequence[TransformProtocol] | None = None,
283
278
  mode: Literal["numpy", "dask"] = "numpy",
284
279
  **slicing_kwargs: SlicingInputType,
285
- ) -> ArrayLike:
280
+ ) -> np.ndarray | da.Array:
286
281
  """Get a slice of the image.
287
282
 
288
283
  Args:
@@ -305,7 +300,7 @@ class AbstractImage(Generic[_image_handler]):
305
300
  )
306
301
  else:
307
302
  raise ValueError(
308
- f"Unknown mode: {mode}. Choose from 'numpy', 'dask', or 'delayed'."
303
+ f"Unsupported mode: {mode}. Supported modes are: numpy, dask."
309
304
  )
310
305
 
311
306
  def _get_roi(
@@ -315,7 +310,7 @@ class AbstractImage(Generic[_image_handler]):
315
310
  transforms: Sequence[TransformProtocol] | None = None,
316
311
  mode: Literal["numpy", "dask"] = "numpy",
317
312
  **slice_kwargs: SlicingInputType,
318
- ) -> ArrayLike:
313
+ ) -> np.ndarray | da.Array:
319
314
  """Get a slice of the image.
320
315
 
321
316
  Args:
@@ -339,12 +334,12 @@ class AbstractImage(Generic[_image_handler]):
339
334
  )
340
335
  else:
341
336
  raise ValueError(
342
- f"Unknown mode: {mode}. Choose from 'numpy', 'dask', or 'delayed'."
337
+ f"Unsupported mode: {mode}. Supported modes are: numpy, dask."
343
338
  )
344
339
 
345
340
  def _set_array(
346
341
  self,
347
- patch: ArrayLike,
342
+ patch: np.ndarray | da.Array,
348
343
  axes_order: Sequence[str] | None = None,
349
344
  transforms: Sequence[TransformProtocol] | None = None,
350
345
  **slicing_kwargs: SlicingInputType,
@@ -359,7 +354,7 @@ class AbstractImage(Generic[_image_handler]):
359
354
 
360
355
  """
361
356
  if isinstance(patch, np.ndarray):
362
- numpy_setter = build_numpy_setter(
357
+ numpy_setter = NumpySetter(
363
358
  zarr_array=self.zarr_array,
364
359
  dimensions=self.dimensions,
365
360
  axes_order=axes_order,
@@ -369,7 +364,7 @@ class AbstractImage(Generic[_image_handler]):
369
364
  numpy_setter(patch)
370
365
 
371
366
  elif isinstance(patch, da.Array):
372
- dask_setter = build_dask_setter(
367
+ dask_setter = DaskSetter(
373
368
  zarr_array=self.zarr_array,
374
369
  dimensions=self.dimensions,
375
370
  axes_order=axes_order,
@@ -387,7 +382,7 @@ class AbstractImage(Generic[_image_handler]):
387
382
  def _set_roi(
388
383
  self,
389
384
  roi: Roi | RoiPixels,
390
- patch: ArrayLike,
385
+ patch: np.ndarray | da.Array,
391
386
  axes_order: Sequence[str] | None = None,
392
387
  transforms: Sequence[TransformProtocol] | None = None,
393
388
  **slicing_kwargs: SlicingInputType,
@@ -403,11 +398,10 @@ class AbstractImage(Generic[_image_handler]):
403
398
 
404
399
  """
405
400
  if isinstance(patch, np.ndarray):
406
- roi_numpy_setter = build_roi_numpy_setter(
401
+ roi_numpy_setter = NumpyRoiSetter(
407
402
  zarr_array=self.zarr_array,
408
403
  dimensions=self.dimensions,
409
404
  roi=roi,
410
- pixel_size=self.pixel_size,
411
405
  axes_order=axes_order,
412
406
  transforms=transforms,
413
407
  slicing_dict=slicing_kwargs,
@@ -415,11 +409,10 @@ class AbstractImage(Generic[_image_handler]):
415
409
  roi_numpy_setter(patch)
416
410
 
417
411
  elif isinstance(patch, da.Array):
418
- roi_dask_setter = build_roi_dask_setter(
412
+ roi_dask_setter = DaskRoiSetter(
419
413
  zarr_array=self.zarr_array,
420
414
  dimensions=self.dimensions,
421
415
  roi=roi,
422
- pixel_size=self.pixel_size,
423
416
  axes_order=axes_order,
424
417
  transforms=transforms,
425
418
  slicing_dict=slicing_kwargs,
@@ -434,7 +427,7 @@ class AbstractImage(Generic[_image_handler]):
434
427
 
435
428
  def _consolidate(
436
429
  self,
437
- order: Literal[0, 1, 2] = 1,
430
+ order: InterpolationOrder = "linear",
438
431
  mode: Literal["dask", "numpy", "coarsen"] = "dask",
439
432
  ) -> None:
440
433
  """Consolidate the image on disk.
@@ -445,14 +438,86 @@ class AbstractImage(Generic[_image_handler]):
445
438
  """
446
439
  consolidate_image(image=self, order=order, mode=mode)
447
440
 
441
+ def roi(self, name: str | None = "image") -> Roi:
442
+ """Return the ROI covering the entire image."""
443
+ dim_x = self.dimensions.get("x")
444
+ dim_y = self.dimensions.get("y")
445
+ assert dim_x is not None and dim_y is not None
446
+ dim_z = self.dimensions.get("z")
447
+ z = None if dim_z is None else 0
448
+ dim_t = self.dimensions.get("t")
449
+ t = None if dim_t is None else 0
450
+ roi_px = RoiPixels(
451
+ name=name,
452
+ x=0,
453
+ y=0,
454
+ z=z,
455
+ t=t,
456
+ x_length=dim_x,
457
+ y_length=dim_y,
458
+ z_length=dim_z,
459
+ t_length=dim_t,
460
+ )
461
+ return roi_px.to_roi(pixel_size=self.pixel_size)
462
+
448
463
  def build_image_roi_table(self, name: str | None = "image") -> RoiTable:
449
464
  """Build the ROI table for an image."""
450
- return build_image_roi_table(image=self, name=name)
465
+ return RoiTable(rois=[self.roi(name=name)])
466
+
467
+ def require_dimensions_match(
468
+ self,
469
+ other: "AbstractImage",
470
+ allow_singleton: bool = False,
471
+ ) -> None:
472
+ """Assert that two images have matching spatial dimensions.
473
+
474
+ Args:
475
+ other: The other image to compare to.
476
+ allow_singleton: If True, allow singleton dimensions to be
477
+ compatible with non-singleton dimensions.
478
+
479
+ Raises:
480
+ NgioValueError: If the images do not have compatible dimensions.
481
+ """
482
+ self.dimensions.require_dimensions_match(
483
+ other.dimensions, allow_singleton=allow_singleton
484
+ )
485
+
486
+ def require_axes_match(
487
+ self,
488
+ other: "AbstractImage",
489
+ ) -> None:
490
+ """Assert that two images have compatible axes.
491
+
492
+ Args:
493
+ other: The other image to compare to.
494
+
495
+ Raises:
496
+ NgioValueError: If the images do not have compatible axes.
497
+ """
498
+ self.dimensions.require_axes_match(other.dimensions)
499
+
500
+ def require_can_be_rescaled(
501
+ self,
502
+ other: "AbstractImage",
503
+ ) -> None:
504
+ """Assert that two images can be rescaled to each other.
505
+
506
+ For this to be true, the images must have the same axes, and
507
+ the pixel sizes must be compatible (i.e. one can be scaled to the other).
508
+
509
+ Args:
510
+ other: The other image to compare to.
511
+
512
+ Raises:
513
+ NgioValueError: If the images cannot be scaled to each other.
514
+ """
515
+ self.dimensions.require_can_be_rescaled(other.dimensions)
451
516
 
452
517
 
453
518
  def consolidate_image(
454
519
  image: AbstractImage,
455
- order: Literal[0, 1, 2] = 1,
520
+ order: InterpolationOrder = "linear",
456
521
  mode: Literal["dask", "numpy", "coarsen"] = "dask",
457
522
  ) -> None:
458
523
  """Consolidate the image on disk."""
@@ -465,26 +530,3 @@ def consolidate_image(
465
530
  consolidate_pyramid(
466
531
  source=image.zarr_array, targets=targets, order=order, mode=mode
467
532
  )
468
-
469
-
470
- def build_image_roi_table(image: AbstractImage, name: str | None = "image") -> RoiTable:
471
- """Build the ROI table for an image."""
472
- dim_x = image.dimensions.get("x")
473
- dim_y = image.dimensions.get("y")
474
- assert dim_x is not None and dim_y is not None
475
- dim_z = image.dimensions.get("z")
476
- z = None if dim_z is None else 0
477
- dim_t = image.dimensions.get("t")
478
- t = None if dim_t is None else 0
479
- image_roi = RoiPixels(
480
- name=name,
481
- x=0,
482
- y=0,
483
- z=z,
484
- t=t,
485
- x_length=dim_x,
486
- y_length=dim_y,
487
- z_length=dim_z,
488
- t_length=dim_t,
489
- )
490
- return RoiTable(rois=[image_roi.to_roi(pixel_size=image.pixel_size)])
ngio/images/_create.py CHANGED
@@ -3,6 +3,8 @@
3
3
  from collections.abc import Sequence
4
4
  from typing import TypeVar
5
5
 
6
+ from zarr.types import DIMENSION_SEPARATOR
7
+
6
8
  from ngio.common._pyramid import init_empty_pyramid
7
9
  from ngio.ome_zarr_meta import (
8
10
  NgioImageMeta,
@@ -93,6 +95,8 @@ def create_empty_label_container(
93
95
  name: str | None = None,
94
96
  chunks: Sequence[int] | None = None,
95
97
  dtype: str = "uint32",
98
+ dimension_separator: DIMENSION_SEPARATOR = "/",
99
+ compressor="default",
96
100
  overwrite: bool = False,
97
101
  version: NgffVersions = DefaultNgffVersion,
98
102
  ) -> ZarrGroupHandler:
@@ -120,6 +124,9 @@ def create_empty_label_container(
120
124
  name (str | None, optional): The name of the image. Defaults to None.
121
125
  chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
122
126
  is used. Defaults to None.
127
+ dimension_separator (DIMENSION_SEPARATOR): The separator to use for
128
+ dimensions. Defaults to "/".
129
+ compressor: The compressor to use. Defaults to "default".
123
130
  dtype (str, optional): The data type of the image. Defaults to "uint16".
124
131
  overwrite (bool, optional): Whether to overwrite an existing image.
125
132
  Defaults to True.
@@ -164,6 +171,8 @@ def create_empty_label_container(
164
171
  chunks=chunks,
165
172
  dtype=dtype,
166
173
  mode="a",
174
+ dimension_separator=dimension_separator,
175
+ compressor=compressor,
167
176
  )
168
177
  group_handler._mode = "r+"
169
178
  return group_handler
@@ -184,6 +193,8 @@ def create_empty_image_container(
184
193
  name: str | None = None,
185
194
  chunks: Sequence[int] | None = None,
186
195
  dtype: str = "uint16",
196
+ dimension_separator: DIMENSION_SEPARATOR = "/",
197
+ compressor="default",
187
198
  overwrite: bool = False,
188
199
  version: NgffVersions = DefaultNgffVersion,
189
200
  ) -> ZarrGroupHandler:
@@ -212,6 +223,9 @@ def create_empty_image_container(
212
223
  chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
213
224
  is used. Defaults to None.
214
225
  dtype (str, optional): The data type of the image. Defaults to "uint16".
226
+ dimension_separator (DIMENSION_SEPARATOR): The separator to use for
227
+ dimensions. Defaults to "/".
228
+ compressor: The compressor to use. Defaults to "default".
215
229
  overwrite (bool, optional): Whether to overwrite an existing image.
216
230
  Defaults to True.
217
231
  version (str, optional): The version of the OME-Zarr specification.
@@ -254,6 +268,8 @@ def create_empty_image_container(
254
268
  chunks=chunks,
255
269
  dtype=dtype,
256
270
  mode="a",
271
+ dimension_separator=dimension_separator,
272
+ compressor=compressor,
257
273
  )
258
274
 
259
275
  group_handler._mode = "r+"
@@ -4,6 +4,7 @@ from collections.abc import Sequence
4
4
 
5
5
  import numpy as np
6
6
  import PIL.Image
7
+ from zarr.types import DIMENSION_SEPARATOR
7
8
 
8
9
  from ngio.common._synt_images_utils import fit_to_shape
9
10
  from ngio.images._ome_zarr_container import OmeZarrContainer, create_ome_zarr_from_array
@@ -35,6 +36,8 @@ def create_synthetic_ome_zarr(
35
36
  channel_colors: Sequence[str] | None = None,
36
37
  channel_active: Sequence[bool] | None = None,
37
38
  table_backend: TableBackend = DefaultTableBackend,
39
+ dimension_separator: DIMENSION_SEPARATOR = "/",
40
+ compressor="default",
38
41
  overwrite: bool = False,
39
42
  version: NgffVersions = DefaultNgffVersion,
40
43
  ) -> OmeZarrContainer:
@@ -63,6 +66,9 @@ def create_synthetic_ome_zarr(
63
66
  channel_active (Sequence[bool] | None, optional): Whether the channels are
64
67
  active. Defaults to None.
65
68
  table_backend (TableBackend): Table backend to be used to store tables
69
+ dimension_separator (DIMENSION_SEPARATOR): The separator to use for
70
+ dimensions. Defaults to "/".
71
+ compressor: The compressor to use. Defaults to "default".
66
72
  overwrite (bool, optional): Whether to overwrite an existing image.
67
73
  Defaults to True.
68
74
  version (NgffVersion, optional): The version of the OME-Zarr specification.
@@ -96,6 +102,8 @@ def create_synthetic_ome_zarr(
96
102
  name=sample_info.name,
97
103
  chunks=chunks,
98
104
  overwrite=overwrite,
105
+ dimension_separator=dimension_separator,
106
+ compressor=compressor,
99
107
  version=version,
100
108
  )
101
109
 
@@ -108,6 +116,8 @@ def create_synthetic_ome_zarr(
108
116
  label = ome_zarr.get_label(name=label_info.name)
109
117
 
110
118
  ref_label = np.asarray(PIL.Image.open(label_info.label_path))
119
+ ref_label = ref_label.astype(label_info.dtype)
120
+
111
121
  ref_label = fit_to_shape(
112
122
  arr=ref_label,
113
123
  out_shape=label.shape,
ngio/images/_image.py CHANGED
@@ -6,17 +6,20 @@ from typing import Literal
6
6
  import dask.array as da
7
7
  import numpy as np
8
8
  from pydantic import BaseModel, model_validator
9
+ from zarr.types import DIMENSION_SEPARATOR
9
10
 
10
11
  from ngio.common import (
11
- ArrayLike,
12
12
  Dimensions,
13
+ InterpolationOrder,
13
14
  Roi,
14
15
  RoiPixels,
15
- SlicingInputType,
16
- TransformProtocol,
17
16
  )
18
17
  from ngio.images._abstract_image import AbstractImage
19
18
  from ngio.images._create import create_empty_image_container
19
+ from ngio.io_pipes import (
20
+ SlicingInputType,
21
+ TransformProtocol,
22
+ )
20
23
  from ngio.ome_zarr_meta import (
21
24
  ImageMetaHandler,
22
25
  NgioImageMeta,
@@ -269,7 +272,7 @@ class Image(AbstractImage[ImageMetaHandler]):
269
272
  transforms: Sequence[TransformProtocol] | None = None,
270
273
  mode: Literal["numpy", "dask"] = "numpy",
271
274
  **slicing_kwargs: SlicingInputType,
272
- ) -> ArrayLike:
275
+ ) -> np.ndarray | da.Array:
273
276
  """Get the image as a zarr array.
274
277
 
275
278
  Args:
@@ -299,7 +302,7 @@ class Image(AbstractImage[ImageMetaHandler]):
299
302
  transforms: Sequence[TransformProtocol] | None = None,
300
303
  mode: Literal["numpy", "dask"] = "numpy",
301
304
  **slicing_kwargs: SlicingInputType,
302
- ) -> ArrayLike:
305
+ ) -> np.ndarray | da.Array:
303
306
  """Get the image as a zarr array for a region of interest.
304
307
 
305
308
  Args:
@@ -328,7 +331,7 @@ class Image(AbstractImage[ImageMetaHandler]):
328
331
 
329
332
  def set_array(
330
333
  self,
331
- patch: ArrayLike,
334
+ patch: np.ndarray | da.Array,
332
335
  channel_selection: ChannelSlicingInputType = None,
333
336
  axes_order: Sequence[str] | None = None,
334
337
  transforms: Sequence[TransformProtocol] | None = None,
@@ -354,7 +357,7 @@ class Image(AbstractImage[ImageMetaHandler]):
354
357
  def set_roi(
355
358
  self,
356
359
  roi: Roi | RoiPixels,
357
- patch: ArrayLike,
360
+ patch: np.ndarray | da.Array,
358
361
  channel_selection: ChannelSlicingInputType = None,
359
362
  axes_order: Sequence[str] | None = None,
360
363
  transforms: Sequence[TransformProtocol] | None = None,
@@ -383,7 +386,7 @@ class Image(AbstractImage[ImageMetaHandler]):
383
386
 
384
387
  def consolidate(
385
388
  self,
386
- order: Literal[0, 1, 2] = 1,
389
+ order: InterpolationOrder = "linear",
387
390
  mode: Literal["dask", "numpy", "coarsen"] = "dask",
388
391
  ) -> None:
389
392
  """Consolidate the label on disk."""
@@ -601,6 +604,8 @@ class ImagesContainer:
601
604
  name: str | None = None,
602
605
  chunks: Sequence[int] | None = None,
603
606
  dtype: str | None = None,
607
+ dimension_separator: DIMENSION_SEPARATOR | None = None,
608
+ compressor: str | None = None,
604
609
  overwrite: bool = False,
605
610
  ) -> "ImagesContainer":
606
611
  """Create an empty OME-Zarr image from an existing image.
@@ -615,6 +620,10 @@ class ImagesContainer:
615
620
  axes_names (Sequence[str] | None): The axes names of the new image.
616
621
  name (str | None): The name of the new image.
617
622
  chunks (Sequence[int] | None): The chunk shape of the new image.
623
+ dimension_separator (DIMENSION_SEPARATOR | None): The separator to use for
624
+ dimensions. If None it will use the same as the reference image.
625
+ compressor (str | None): The compressor to use. If None it will use
626
+ the same as the reference image.
618
627
  dtype (str | None): The data type of the new image.
619
628
  overwrite (bool): Whether to overwrite an existing image.
620
629
 
@@ -714,6 +723,8 @@ def derive_image_container(
714
723
  name: str | None = None,
715
724
  chunks: Sequence[int] | None = None,
716
725
  dtype: str | None = None,
726
+ dimension_separator: DIMENSION_SEPARATOR | None = None,
727
+ compressor=None,
717
728
  overwrite: bool = False,
718
729
  ) -> ImagesContainer:
719
730
  """Create an empty OME-Zarr image from an existing image.
@@ -728,6 +739,10 @@ def derive_image_container(
728
739
  axes_names (Sequence[str] | None): The axes names of the new image.
729
740
  name (str | None): The name of the new image.
730
741
  chunks (Sequence[int] | None): The chunk shape of the new image.
742
+ dimension_separator (DIMENSION_SEPARATOR | None): The separator to use for
743
+ dimensions. If None it will use the same as the reference image.
744
+ compressor: The compressor to use. If None it will use
745
+ the same as the reference image.
731
746
  dtype (str | None): The data type of the new image.
732
747
  overwrite (bool): Whether to overwrite an existing image.
733
748
 
@@ -749,7 +764,7 @@ def derive_image_container(
749
764
  pixel_size = ref_image.pixel_size
750
765
 
751
766
  if axes_names is None:
752
- axes_names = ref_meta.axes_mapper.axes_names
767
+ axes_names = ref_meta.axes_handler.axes_names
753
768
 
754
769
  if len(axes_names) != len(shape):
755
770
  raise NgioValidationError(
@@ -771,6 +786,13 @@ def derive_image_container(
771
786
 
772
787
  if dtype is None:
773
788
  dtype = ref_image.dtype
789
+
790
+ if dimension_separator is None:
791
+ dimension_separator = ref_image.zarr_array._dimension_separator # type: ignore
792
+
793
+ if compressor is None:
794
+ compressor = ref_image.zarr_array.compressor # type: ignore
795
+
774
796
  handler = create_empty_image_container(
775
797
  store=store,
776
798
  shape=shape,
@@ -786,6 +808,8 @@ def derive_image_container(
786
808
  name=name,
787
809
  chunks=chunks,
788
810
  dtype=dtype,
811
+ dimension_separator=dimension_separator, # type: ignore
812
+ compressor=compressor, # type: ignore
789
813
  overwrite=overwrite,
790
814
  version=ref_meta.version,
791
815
  )