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.
- ngio/__init__.py +1 -2
- ngio/common/__init__.py +2 -51
- ngio/common/_dimensions.py +253 -74
- ngio/common/_pyramid.py +42 -23
- ngio/common/_roi.py +49 -413
- ngio/common/_zoom.py +32 -7
- ngio/experimental/iterators/__init__.py +0 -2
- ngio/experimental/iterators/_abstract_iterator.py +246 -26
- ngio/experimental/iterators/_feature.py +90 -52
- ngio/experimental/iterators/_image_processing.py +24 -63
- ngio/experimental/iterators/_mappers.py +48 -0
- ngio/experimental/iterators/_rois_utils.py +4 -4
- ngio/experimental/iterators/_segmentation.py +38 -85
- ngio/images/_abstract_image.py +192 -95
- ngio/images/_create.py +16 -0
- ngio/images/_create_synt_container.py +10 -0
- ngio/images/_image.py +35 -9
- ngio/images/_label.py +26 -3
- ngio/images/_masked_image.py +45 -61
- ngio/images/_ome_zarr_container.py +33 -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 +152 -0
- ngio/io_pipes/_io_pipes_types.py +56 -0
- ngio/io_pipes/_match_shape.py +376 -0
- ngio/io_pipes/_ops_axes.py +344 -0
- ngio/io_pipes/_ops_slices.py +446 -0
- ngio/io_pipes/_ops_slices_utils.py +196 -0
- ngio/io_pipes/_ops_transforms.py +104 -0
- ngio/io_pipes/_zoom_transform.py +175 -0
- ngio/ome_zarr_meta/__init__.py +4 -2
- ngio/ome_zarr_meta/ngio_specs/__init__.py +4 -4
- ngio/ome_zarr_meta/ngio_specs/_axes.py +129 -141
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +47 -121
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +30 -22
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +17 -1
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +33 -30
- ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
- ngio/resources/__init__.py +1 -0
- ngio/resources/resource_model.py +1 -0
- ngio/{common/transforms → transforms}/__init__.py +1 -1
- ngio/transforms/_zoom.py +19 -0
- ngio/utils/_datasets.py +5 -0
- ngio/utils/_zarr_utils.py +5 -1
- {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/METADATA +1 -1
- ngio-0.4.0b1.dist-info/RECORD +85 -0
- ngio/common/_array_io_pipes.py +0 -554
- ngio/common/_array_io_utils.py +0 -508
- ngio/common/transforms/_label.py +0 -12
- ngio/common/transforms/_zoom.py +0 -109
- ngio-0.4.0a3.dist-info/RECORD +0 -76
- {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/WHEEL +0 -0
- {ngio-0.4.0a3.dist-info → ngio-0.4.0b1.dist-info}/licenses/LICENSE +0 -0
ngio/images/_abstract_image.py
CHANGED
|
@@ -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
|
-
|
|
30
|
+
AxesHandler,
|
|
29
31
|
Dataset,
|
|
30
32
|
ImageMetaHandler,
|
|
31
33
|
LabelMetaHandler,
|
|
@@ -61,29 +63,54 @@ 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.
|
|
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(
|
|
94
|
+
shape=self.zarr_array.shape,
|
|
95
|
+
chunks=self.zarr_array.chunks,
|
|
96
|
+
dataset=self.dataset,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def pixel_size(self) -> PixelSize:
|
|
101
|
+
"""Return the pixel size of the image."""
|
|
102
|
+
return self.dataset.pixel_size
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def axes_handler(self) -> AxesHandler:
|
|
106
|
+
"""Return the axes handler of the image."""
|
|
107
|
+
return self.dataset.axes_handler
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def axes(self) -> tuple[str, ...]:
|
|
111
|
+
"""Return the axes of the image."""
|
|
112
|
+
return self.dimensions.axes
|
|
113
|
+
|
|
87
114
|
@property
|
|
88
115
|
def zarr_array(self) -> zarr.Array:
|
|
89
116
|
"""Return the Zarr array."""
|
|
@@ -104,16 +131,6 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
104
131
|
"""Return the chunks of the image."""
|
|
105
132
|
return self.zarr_array.chunks
|
|
106
133
|
|
|
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
134
|
@property
|
|
118
135
|
def is_3d(self) -> bool:
|
|
119
136
|
"""Return True if the image is 3D."""
|
|
@@ -147,32 +164,16 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
147
164
|
@property
|
|
148
165
|
def space_unit(self) -> str | None:
|
|
149
166
|
"""Return the space unit of the image."""
|
|
150
|
-
return self.
|
|
167
|
+
return self.axes_handler.space_unit
|
|
151
168
|
|
|
152
169
|
@property
|
|
153
170
|
def time_unit(self) -> str | None:
|
|
154
171
|
"""Return the time unit of the image."""
|
|
155
|
-
return self.
|
|
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
|
|
172
|
+
return self.axes_handler.time_unit
|
|
171
173
|
|
|
172
174
|
def has_axis(self, axis: str) -> bool:
|
|
173
175
|
"""Return True if the image has the given axis."""
|
|
174
|
-
self.
|
|
175
|
-
return self.dimensions.has_axis(axis)
|
|
176
|
+
return self.axes_handler.has_axis(axis)
|
|
176
177
|
|
|
177
178
|
def _get_as_numpy(
|
|
178
179
|
self,
|
|
@@ -190,7 +191,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
190
191
|
Returns:
|
|
191
192
|
The array of the region of interest.
|
|
192
193
|
"""
|
|
193
|
-
numpy_getter =
|
|
194
|
+
numpy_getter = NumpyGetter(
|
|
194
195
|
zarr_array=self.zarr_array,
|
|
195
196
|
dimensions=self.dimensions,
|
|
196
197
|
axes_order=axes_order,
|
|
@@ -217,11 +218,10 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
217
218
|
Returns:
|
|
218
219
|
The array of the region of interest.
|
|
219
220
|
"""
|
|
220
|
-
numpy_roi_getter =
|
|
221
|
+
numpy_roi_getter = NumpyRoiGetter(
|
|
221
222
|
zarr_array=self.zarr_array,
|
|
222
223
|
dimensions=self.dimensions,
|
|
223
224
|
roi=roi,
|
|
224
|
-
pixel_size=self.pixel_size,
|
|
225
225
|
axes_order=axes_order,
|
|
226
226
|
transforms=transforms,
|
|
227
227
|
slicing_dict=slicing_kwargs,
|
|
@@ -241,7 +241,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
241
241
|
transforms: The transforms to apply to the array.
|
|
242
242
|
**slicing_kwargs: The slices to get the array.
|
|
243
243
|
"""
|
|
244
|
-
dask_getter =
|
|
244
|
+
dask_getter = DaskGetter(
|
|
245
245
|
zarr_array=self.zarr_array,
|
|
246
246
|
dimensions=self.dimensions,
|
|
247
247
|
axes_order=axes_order,
|
|
@@ -265,11 +265,10 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
265
265
|
transforms: The transforms to apply to the array.
|
|
266
266
|
**slicing_kwargs: The slices to get the array.
|
|
267
267
|
"""
|
|
268
|
-
roi_dask_getter =
|
|
268
|
+
roi_dask_getter = DaskRoiGetter(
|
|
269
269
|
zarr_array=self.zarr_array,
|
|
270
270
|
dimensions=self.dimensions,
|
|
271
271
|
roi=roi,
|
|
272
|
-
pixel_size=self.pixel_size,
|
|
273
272
|
axes_order=axes_order,
|
|
274
273
|
transforms=transforms,
|
|
275
274
|
slicing_dict=slicing_kwargs,
|
|
@@ -282,7 +281,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
282
281
|
transforms: Sequence[TransformProtocol] | None = None,
|
|
283
282
|
mode: Literal["numpy", "dask"] = "numpy",
|
|
284
283
|
**slicing_kwargs: SlicingInputType,
|
|
285
|
-
) ->
|
|
284
|
+
) -> np.ndarray | da.Array:
|
|
286
285
|
"""Get a slice of the image.
|
|
287
286
|
|
|
288
287
|
Args:
|
|
@@ -305,7 +304,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
305
304
|
)
|
|
306
305
|
else:
|
|
307
306
|
raise ValueError(
|
|
308
|
-
f"
|
|
307
|
+
f"Unsupported mode: {mode}. Supported modes are: numpy, dask."
|
|
309
308
|
)
|
|
310
309
|
|
|
311
310
|
def _get_roi(
|
|
@@ -315,7 +314,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
315
314
|
transforms: Sequence[TransformProtocol] | None = None,
|
|
316
315
|
mode: Literal["numpy", "dask"] = "numpy",
|
|
317
316
|
**slice_kwargs: SlicingInputType,
|
|
318
|
-
) ->
|
|
317
|
+
) -> np.ndarray | da.Array:
|
|
319
318
|
"""Get a slice of the image.
|
|
320
319
|
|
|
321
320
|
Args:
|
|
@@ -339,12 +338,12 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
339
338
|
)
|
|
340
339
|
else:
|
|
341
340
|
raise ValueError(
|
|
342
|
-
f"
|
|
341
|
+
f"Unsupported mode: {mode}. Supported modes are: numpy, dask."
|
|
343
342
|
)
|
|
344
343
|
|
|
345
344
|
def _set_array(
|
|
346
345
|
self,
|
|
347
|
-
patch:
|
|
346
|
+
patch: np.ndarray | da.Array,
|
|
348
347
|
axes_order: Sequence[str] | None = None,
|
|
349
348
|
transforms: Sequence[TransformProtocol] | None = None,
|
|
350
349
|
**slicing_kwargs: SlicingInputType,
|
|
@@ -359,7 +358,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
359
358
|
|
|
360
359
|
"""
|
|
361
360
|
if isinstance(patch, np.ndarray):
|
|
362
|
-
numpy_setter =
|
|
361
|
+
numpy_setter = NumpySetter(
|
|
363
362
|
zarr_array=self.zarr_array,
|
|
364
363
|
dimensions=self.dimensions,
|
|
365
364
|
axes_order=axes_order,
|
|
@@ -369,7 +368,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
369
368
|
numpy_setter(patch)
|
|
370
369
|
|
|
371
370
|
elif isinstance(patch, da.Array):
|
|
372
|
-
dask_setter =
|
|
371
|
+
dask_setter = DaskSetter(
|
|
373
372
|
zarr_array=self.zarr_array,
|
|
374
373
|
dimensions=self.dimensions,
|
|
375
374
|
axes_order=axes_order,
|
|
@@ -387,7 +386,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
387
386
|
def _set_roi(
|
|
388
387
|
self,
|
|
389
388
|
roi: Roi | RoiPixels,
|
|
390
|
-
patch:
|
|
389
|
+
patch: np.ndarray | da.Array,
|
|
391
390
|
axes_order: Sequence[str] | None = None,
|
|
392
391
|
transforms: Sequence[TransformProtocol] | None = None,
|
|
393
392
|
**slicing_kwargs: SlicingInputType,
|
|
@@ -403,11 +402,10 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
403
402
|
|
|
404
403
|
"""
|
|
405
404
|
if isinstance(patch, np.ndarray):
|
|
406
|
-
roi_numpy_setter =
|
|
405
|
+
roi_numpy_setter = NumpyRoiSetter(
|
|
407
406
|
zarr_array=self.zarr_array,
|
|
408
407
|
dimensions=self.dimensions,
|
|
409
408
|
roi=roi,
|
|
410
|
-
pixel_size=self.pixel_size,
|
|
411
409
|
axes_order=axes_order,
|
|
412
410
|
transforms=transforms,
|
|
413
411
|
slicing_dict=slicing_kwargs,
|
|
@@ -415,11 +413,10 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
415
413
|
roi_numpy_setter(patch)
|
|
416
414
|
|
|
417
415
|
elif isinstance(patch, da.Array):
|
|
418
|
-
roi_dask_setter =
|
|
416
|
+
roi_dask_setter = DaskRoiSetter(
|
|
419
417
|
zarr_array=self.zarr_array,
|
|
420
418
|
dimensions=self.dimensions,
|
|
421
419
|
roi=roi,
|
|
422
|
-
pixel_size=self.pixel_size,
|
|
423
420
|
axes_order=axes_order,
|
|
424
421
|
transforms=transforms,
|
|
425
422
|
slicing_dict=slicing_kwargs,
|
|
@@ -434,7 +431,7 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
434
431
|
|
|
435
432
|
def _consolidate(
|
|
436
433
|
self,
|
|
437
|
-
order:
|
|
434
|
+
order: InterpolationOrder = "linear",
|
|
438
435
|
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
439
436
|
) -> None:
|
|
440
437
|
"""Consolidate the image on disk.
|
|
@@ -445,14 +442,137 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
445
442
|
"""
|
|
446
443
|
consolidate_image(image=self, order=order, mode=mode)
|
|
447
444
|
|
|
445
|
+
def roi(self, name: str | None = "image") -> Roi:
|
|
446
|
+
"""Return the ROI covering the entire image."""
|
|
447
|
+
dim_x = self.dimensions.get("x")
|
|
448
|
+
dim_y = self.dimensions.get("y")
|
|
449
|
+
assert dim_x is not None and dim_y is not None
|
|
450
|
+
dim_z = self.dimensions.get("z")
|
|
451
|
+
z = None if dim_z is None else 0
|
|
452
|
+
dim_t = self.dimensions.get("t")
|
|
453
|
+
t = None if dim_t is None else 0
|
|
454
|
+
roi_px = RoiPixels(
|
|
455
|
+
name=name,
|
|
456
|
+
x=0,
|
|
457
|
+
y=0,
|
|
458
|
+
z=z,
|
|
459
|
+
t=t,
|
|
460
|
+
x_length=dim_x,
|
|
461
|
+
y_length=dim_y,
|
|
462
|
+
z_length=dim_z,
|
|
463
|
+
t_length=dim_t,
|
|
464
|
+
)
|
|
465
|
+
return roi_px.to_roi(pixel_size=self.pixel_size)
|
|
466
|
+
|
|
448
467
|
def build_image_roi_table(self, name: str | None = "image") -> RoiTable:
|
|
449
|
-
"""Build the ROI table
|
|
450
|
-
return
|
|
468
|
+
"""Build the ROI table containing the ROI covering the entire image."""
|
|
469
|
+
return RoiTable(rois=[self.roi(name=name)])
|
|
470
|
+
|
|
471
|
+
def require_dimensions_match(
|
|
472
|
+
self,
|
|
473
|
+
other: "AbstractImage",
|
|
474
|
+
allow_singleton: bool = False,
|
|
475
|
+
) -> None:
|
|
476
|
+
"""Assert that two images have matching spatial dimensions.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
other: The other image to compare to.
|
|
480
|
+
allow_singleton: If True, allow singleton dimensions to be
|
|
481
|
+
compatible with non-singleton dimensions.
|
|
482
|
+
|
|
483
|
+
Raises:
|
|
484
|
+
NgioValueError: If the images do not have compatible dimensions.
|
|
485
|
+
"""
|
|
486
|
+
self.dimensions.require_dimensions_match(
|
|
487
|
+
other.dimensions, allow_singleton=allow_singleton
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
def check_if_dimensions_match(
|
|
491
|
+
self,
|
|
492
|
+
other: "AbstractImage",
|
|
493
|
+
allow_singleton: bool = False,
|
|
494
|
+
) -> bool:
|
|
495
|
+
"""Check if two images have matching spatial dimensions.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
other: The other image to compare to.
|
|
499
|
+
allow_singleton: If True, allow singleton dimensions to be
|
|
500
|
+
compatible with non-singleton dimensions.
|
|
501
|
+
|
|
502
|
+
Returns:
|
|
503
|
+
bool: True if the images have matching dimensions, False otherwise.
|
|
504
|
+
"""
|
|
505
|
+
return self.dimensions.check_if_dimensions_match(
|
|
506
|
+
other.dimensions, allow_singleton=allow_singleton
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
def require_axes_match(
|
|
510
|
+
self,
|
|
511
|
+
other: "AbstractImage",
|
|
512
|
+
) -> None:
|
|
513
|
+
"""Assert that two images have compatible axes.
|
|
514
|
+
|
|
515
|
+
Args:
|
|
516
|
+
other: The other image to compare to.
|
|
517
|
+
|
|
518
|
+
Raises:
|
|
519
|
+
NgioValueError: If the images do not have compatible axes.
|
|
520
|
+
"""
|
|
521
|
+
self.dimensions.require_axes_match(other.dimensions)
|
|
522
|
+
|
|
523
|
+
def check_if_axes_match(
|
|
524
|
+
self,
|
|
525
|
+
other: "AbstractImage",
|
|
526
|
+
) -> bool:
|
|
527
|
+
"""Check if two images have compatible axes.
|
|
528
|
+
|
|
529
|
+
Args:
|
|
530
|
+
other: The other image to compare to.
|
|
531
|
+
|
|
532
|
+
Returns:
|
|
533
|
+
bool: True if the images have compatible axes, False otherwise.
|
|
534
|
+
|
|
535
|
+
"""
|
|
536
|
+
return self.dimensions.check_if_axes_match(other.dimensions)
|
|
537
|
+
|
|
538
|
+
def require_rescalable(
|
|
539
|
+
self,
|
|
540
|
+
other: "AbstractImage",
|
|
541
|
+
) -> None:
|
|
542
|
+
"""Assert that two images can be rescaled to each other.
|
|
543
|
+
|
|
544
|
+
For this to be true, the images must have the same axes, and
|
|
545
|
+
the pixel sizes must be compatible (i.e. one can be scaled to the other).
|
|
546
|
+
|
|
547
|
+
Args:
|
|
548
|
+
other: The other image to compare to.
|
|
549
|
+
|
|
550
|
+
Raises:
|
|
551
|
+
NgioValueError: If the images cannot be scaled to each other.
|
|
552
|
+
"""
|
|
553
|
+
self.dimensions.require_rescalable(other.dimensions)
|
|
554
|
+
|
|
555
|
+
def check_if_rescalable(
|
|
556
|
+
self,
|
|
557
|
+
other: "AbstractImage",
|
|
558
|
+
) -> bool:
|
|
559
|
+
"""Check if two images can be rescaled to each other.
|
|
560
|
+
|
|
561
|
+
For this to be true, the images must have the same axes, and
|
|
562
|
+
the pixel sizes must be compatible (i.e. one can be scaled to the other).
|
|
563
|
+
|
|
564
|
+
Args:
|
|
565
|
+
other: The other image to compare to.
|
|
566
|
+
|
|
567
|
+
Returns:
|
|
568
|
+
bool: True if the images can be rescaled to each other, False otherwise.
|
|
569
|
+
"""
|
|
570
|
+
return self.dimensions.check_if_rescalable(other.dimensions)
|
|
451
571
|
|
|
452
572
|
|
|
453
573
|
def consolidate_image(
|
|
454
574
|
image: AbstractImage,
|
|
455
|
-
order:
|
|
575
|
+
order: InterpolationOrder = "linear",
|
|
456
576
|
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
457
577
|
) -> None:
|
|
458
578
|
"""Consolidate the image on disk."""
|
|
@@ -465,26 +585,3 @@ def consolidate_image(
|
|
|
465
585
|
consolidate_pyramid(
|
|
466
586
|
source=image.zarr_array, targets=targets, order=order, mode=mode
|
|
467
587
|
)
|
|
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,
|