ngio 0.3.4__py3-none-any.whl → 0.4.0a1__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 +6 -0
- ngio/common/__init__.py +50 -48
- ngio/common/_array_io_pipes.py +549 -0
- ngio/common/_array_io_utils.py +508 -0
- ngio/common/_dimensions.py +63 -27
- ngio/common/_masking_roi.py +38 -10
- ngio/common/_pyramid.py +9 -7
- ngio/common/_roi.py +571 -72
- ngio/common/_synt_images_utils.py +101 -0
- ngio/common/_zoom.py +17 -12
- ngio/common/transforms/__init__.py +5 -0
- ngio/common/transforms/_label.py +12 -0
- ngio/common/transforms/_zoom.py +109 -0
- ngio/experimental/__init__.py +5 -0
- ngio/experimental/iterators/__init__.py +17 -0
- ngio/experimental/iterators/_abstract_iterator.py +170 -0
- ngio/experimental/iterators/_feature.py +151 -0
- ngio/experimental/iterators/_image_processing.py +169 -0
- ngio/experimental/iterators/_rois_utils.py +127 -0
- ngio/experimental/iterators/_segmentation.py +278 -0
- ngio/hcs/_plate.py +41 -36
- ngio/images/__init__.py +22 -1
- ngio/images/_abstract_image.py +247 -117
- ngio/images/_create.py +15 -15
- ngio/images/_create_synt_container.py +128 -0
- ngio/images/_image.py +425 -62
- ngio/images/_label.py +33 -30
- ngio/images/_masked_image.py +396 -122
- ngio/images/_ome_zarr_container.py +203 -66
- ngio/{common → images}/_table_ops.py +41 -41
- ngio/ome_zarr_meta/ngio_specs/__init__.py +2 -8
- ngio/ome_zarr_meta/ngio_specs/_axes.py +151 -128
- ngio/ome_zarr_meta/ngio_specs/_channels.py +55 -18
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +7 -7
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +6 -15
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +11 -68
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +1 -1
- 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 +54 -0
- ngio/resources/resource_model.py +35 -0
- ngio/tables/backends/_abstract_backend.py +5 -6
- ngio/tables/backends/_anndata.py +1 -2
- ngio/tables/backends/_anndata_utils.py +3 -3
- ngio/tables/backends/_non_zarr_backends.py +1 -1
- ngio/tables/backends/_table_backends.py +0 -1
- ngio/tables/backends/_utils.py +3 -3
- ngio/tables/v1/_roi_table.py +156 -69
- ngio/utils/__init__.py +2 -3
- ngio/utils/_logger.py +19 -0
- ngio/utils/_zarr_utils.py +1 -5
- {ngio-0.3.4.dist-info → ngio-0.4.0a1.dist-info}/METADATA +12 -10
- ngio-0.4.0a1.dist-info/RECORD +76 -0
- ngio/common/_array_pipe.py +0 -288
- ngio/common/_axes_transforms.py +0 -64
- ngio/common/_common_types.py +0 -5
- ngio/common/_slicer.py +0 -96
- ngio-0.3.4.dist-info/RECORD +0 -61
- {ngio-0.3.4.dist-info → ngio-0.4.0a1.dist-info}/WHEEL +0 -0
- {ngio-0.3.4.dist-info → ngio-0.4.0a1.dist-info}/licenses/LICENSE +0 -0
ngio/images/_abstract_image.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Generic class to handle Image-like data in a OME-NGFF file."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import
|
|
3
|
+
from collections.abc import Sequence
|
|
4
4
|
from typing import Generic, Literal, TypeVar
|
|
5
5
|
|
|
6
|
+
import dask.array as da
|
|
7
|
+
import numpy as np
|
|
6
8
|
import zarr
|
|
7
9
|
|
|
8
10
|
from ngio.common import (
|
|
@@ -10,10 +12,17 @@ from ngio.common import (
|
|
|
10
12
|
Dimensions,
|
|
11
13
|
Roi,
|
|
12
14
|
RoiPixels,
|
|
15
|
+
SlicingInputType,
|
|
16
|
+
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,
|
|
13
25
|
consolidate_pyramid,
|
|
14
|
-
get_pipe,
|
|
15
|
-
roi_to_slice_kwargs,
|
|
16
|
-
set_pipe,
|
|
17
26
|
)
|
|
18
27
|
from ngio.ome_zarr_meta import (
|
|
19
28
|
AxesMapper,
|
|
@@ -165,80 +174,223 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
165
174
|
self.axes_mapper.get_index("x")
|
|
166
175
|
return self.dimensions.has_axis(axis)
|
|
167
176
|
|
|
168
|
-
def
|
|
177
|
+
def _get_as_numpy(
|
|
169
178
|
self,
|
|
170
|
-
axes_order:
|
|
171
|
-
|
|
172
|
-
**
|
|
173
|
-
) ->
|
|
174
|
-
"""Get
|
|
179
|
+
axes_order: Sequence[str] | None = None,
|
|
180
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
181
|
+
**slicing_kwargs: SlicingInputType,
|
|
182
|
+
) -> np.ndarray:
|
|
183
|
+
"""Get the image as a numpy array.
|
|
175
184
|
|
|
176
185
|
Args:
|
|
177
186
|
axes_order: The order of the axes to return the array.
|
|
178
|
-
|
|
179
|
-
**
|
|
187
|
+
transforms: The transforms to apply to the array.
|
|
188
|
+
**slicing_kwargs: The slices to get the array.
|
|
180
189
|
|
|
181
190
|
Returns:
|
|
182
191
|
The array of the region of interest.
|
|
183
192
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
193
|
+
numpy_getter = build_numpy_getter(
|
|
194
|
+
zarr_array=self.zarr_array,
|
|
186
195
|
dimensions=self.dimensions,
|
|
187
196
|
axes_order=axes_order,
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
transforms=transforms,
|
|
198
|
+
slicing_dict=slicing_kwargs,
|
|
190
199
|
)
|
|
200
|
+
return numpy_getter()
|
|
201
|
+
|
|
202
|
+
def _get_roi_as_numpy(
|
|
203
|
+
self,
|
|
204
|
+
roi: Roi | RoiPixels,
|
|
205
|
+
axes_order: Sequence[str] | None = None,
|
|
206
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
207
|
+
**slicing_kwargs: SlicingInputType,
|
|
208
|
+
) -> np.ndarray:
|
|
209
|
+
"""Get the image as a numpy array for a region of interest.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
roi: The region of interest to get the array.
|
|
213
|
+
axes_order: The order of the axes to return the array.
|
|
214
|
+
transforms: The transforms to apply to the array.
|
|
215
|
+
**slicing_kwargs: The slices to get the array.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
The array of the region of interest.
|
|
219
|
+
"""
|
|
220
|
+
numpy_roi_getter = build_roi_numpy_getter(
|
|
221
|
+
zarr_array=self.zarr_array,
|
|
222
|
+
dimensions=self.dimensions,
|
|
223
|
+
roi=roi,
|
|
224
|
+
pixel_size=self.pixel_size,
|
|
225
|
+
axes_order=axes_order,
|
|
226
|
+
transforms=transforms,
|
|
227
|
+
slicing_dict=slicing_kwargs,
|
|
228
|
+
)
|
|
229
|
+
return numpy_roi_getter()
|
|
230
|
+
|
|
231
|
+
def _get_as_dask(
|
|
232
|
+
self,
|
|
233
|
+
axes_order: Sequence[str] | None = None,
|
|
234
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
235
|
+
**slicing_kwargs: SlicingInputType,
|
|
236
|
+
) -> da.Array:
|
|
237
|
+
"""Get the image as a dask array.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
axes_order: The order of the axes to return the array.
|
|
241
|
+
transforms: The transforms to apply to the array.
|
|
242
|
+
**slicing_kwargs: The slices to get the array.
|
|
243
|
+
"""
|
|
244
|
+
dask_getter = build_dask_getter(
|
|
245
|
+
zarr_array=self.zarr_array,
|
|
246
|
+
dimensions=self.dimensions,
|
|
247
|
+
axes_order=axes_order,
|
|
248
|
+
transforms=transforms,
|
|
249
|
+
slicing_dict=slicing_kwargs,
|
|
250
|
+
)
|
|
251
|
+
return dask_getter()
|
|
252
|
+
|
|
253
|
+
def _get_roi_as_dask(
|
|
254
|
+
self,
|
|
255
|
+
roi: Roi | RoiPixels,
|
|
256
|
+
axes_order: Sequence[str] | None = None,
|
|
257
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
258
|
+
**slicing_kwargs: SlicingInputType,
|
|
259
|
+
) -> da.Array:
|
|
260
|
+
"""Get the image as a dask array for a region of interest.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
roi: The region of interest to get the array.
|
|
264
|
+
axes_order: The order of the axes to return the array.
|
|
265
|
+
transforms: The transforms to apply to the array.
|
|
266
|
+
**slicing_kwargs: The slices to get the array.
|
|
267
|
+
"""
|
|
268
|
+
roi_dask_getter = build_roi_dask_getter(
|
|
269
|
+
zarr_array=self.zarr_array,
|
|
270
|
+
dimensions=self.dimensions,
|
|
271
|
+
roi=roi,
|
|
272
|
+
pixel_size=self.pixel_size,
|
|
273
|
+
axes_order=axes_order,
|
|
274
|
+
transforms=transforms,
|
|
275
|
+
slicing_dict=slicing_kwargs,
|
|
276
|
+
)
|
|
277
|
+
return roi_dask_getter()
|
|
278
|
+
|
|
279
|
+
def _get_array(
|
|
280
|
+
self,
|
|
281
|
+
axes_order: Sequence[str] | None = None,
|
|
282
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
283
|
+
mode: Literal["numpy", "dask"] = "numpy",
|
|
284
|
+
**slicing_kwargs: SlicingInputType,
|
|
285
|
+
) -> ArrayLike:
|
|
286
|
+
"""Get a slice of the image.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
axes_order: The order of the axes to return the array.
|
|
290
|
+
transforms: The transforms to apply to the array.
|
|
291
|
+
mode: The object type to return.
|
|
292
|
+
Can be "dask", "numpy".
|
|
293
|
+
**slicing_kwargs: The slices to get the array.
|
|
191
294
|
|
|
192
|
-
|
|
295
|
+
Returns:
|
|
296
|
+
The array of the region of interest.
|
|
297
|
+
"""
|
|
298
|
+
if mode == "numpy":
|
|
299
|
+
return self._get_as_numpy(
|
|
300
|
+
axes_order=axes_order, transforms=transforms, **slicing_kwargs
|
|
301
|
+
)
|
|
302
|
+
elif mode == "dask":
|
|
303
|
+
return self._get_as_dask(
|
|
304
|
+
axes_order=axes_order, transforms=transforms, **slicing_kwargs
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
raise ValueError(
|
|
308
|
+
f"Unknown mode: {mode}. Choose from 'numpy', 'dask', or 'delayed'."
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
def _get_roi(
|
|
193
312
|
self,
|
|
194
|
-
roi: Roi,
|
|
195
|
-
axes_order:
|
|
196
|
-
|
|
197
|
-
|
|
313
|
+
roi: Roi | RoiPixels,
|
|
314
|
+
axes_order: Sequence[str] | None = None,
|
|
315
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
316
|
+
mode: Literal["numpy", "dask"] = "numpy",
|
|
317
|
+
**slice_kwargs: SlicingInputType,
|
|
198
318
|
) -> ArrayLike:
|
|
199
319
|
"""Get a slice of the image.
|
|
200
320
|
|
|
201
321
|
Args:
|
|
202
322
|
roi: The region of interest to get the array.
|
|
203
323
|
axes_order: The order of the axes to return the array.
|
|
324
|
+
transforms: The transforms to apply to the array.
|
|
204
325
|
mode: The mode to return the array.
|
|
326
|
+
Can be "dask", "numpy".
|
|
205
327
|
**slice_kwargs: The slices to get the array.
|
|
206
328
|
|
|
207
329
|
Returns:
|
|
208
330
|
The array of the region of interest.
|
|
209
331
|
"""
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
332
|
+
if mode == "numpy":
|
|
333
|
+
return self._get_roi_as_numpy(
|
|
334
|
+
roi=roi, axes_order=axes_order, transforms=transforms, **slice_kwargs
|
|
335
|
+
)
|
|
336
|
+
elif mode == "dask":
|
|
337
|
+
return self._get_roi_as_dask(
|
|
338
|
+
roi=roi, axes_order=axes_order, transforms=transforms, **slice_kwargs
|
|
339
|
+
)
|
|
340
|
+
else:
|
|
341
|
+
raise ValueError(
|
|
342
|
+
f"Unknown mode: {mode}. Choose from 'numpy', 'dask', or 'delayed'."
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
def _set_array(
|
|
215
346
|
self,
|
|
216
347
|
patch: ArrayLike,
|
|
217
|
-
axes_order:
|
|
218
|
-
|
|
348
|
+
axes_order: Sequence[str] | None = None,
|
|
349
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
350
|
+
**slicing_kwargs: SlicingInputType,
|
|
219
351
|
) -> None:
|
|
220
352
|
"""Set a slice of the image.
|
|
221
353
|
|
|
222
354
|
Args:
|
|
223
355
|
patch: The patch to set.
|
|
224
356
|
axes_order: The order of the axes to set the patch.
|
|
225
|
-
|
|
357
|
+
transforms: The transforms to apply to the patch.
|
|
358
|
+
**slicing_kwargs: The slices to set the patch.
|
|
226
359
|
|
|
227
360
|
"""
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
361
|
+
if isinstance(patch, np.ndarray):
|
|
362
|
+
numpy_setter = build_numpy_setter(
|
|
363
|
+
zarr_array=self.zarr_array,
|
|
364
|
+
dimensions=self.dimensions,
|
|
365
|
+
axes_order=axes_order,
|
|
366
|
+
transforms=transforms,
|
|
367
|
+
slicing_dict=slicing_kwargs,
|
|
368
|
+
)
|
|
369
|
+
numpy_setter(patch)
|
|
370
|
+
|
|
371
|
+
elif isinstance(patch, da.Array):
|
|
372
|
+
dask_setter = build_dask_setter(
|
|
373
|
+
zarr_array=self.zarr_array,
|
|
374
|
+
dimensions=self.dimensions,
|
|
375
|
+
axes_order=axes_order,
|
|
376
|
+
transforms=transforms,
|
|
377
|
+
slicing_dict=slicing_kwargs,
|
|
378
|
+
)
|
|
379
|
+
dask_setter(patch)
|
|
380
|
+
else:
|
|
381
|
+
raise TypeError(
|
|
382
|
+
f"Unsupported patch type: {type(patch)}. "
|
|
383
|
+
"Supported types are: "
|
|
384
|
+
"numpy.ndarray, dask.array.Array."
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
def _set_roi(
|
|
237
388
|
self,
|
|
238
|
-
roi: Roi,
|
|
389
|
+
roi: Roi | RoiPixels,
|
|
239
390
|
patch: ArrayLike,
|
|
240
|
-
axes_order:
|
|
241
|
-
|
|
391
|
+
axes_order: Sequence[str] | None = None,
|
|
392
|
+
transforms: Sequence[TransformProtocol] | None = None,
|
|
393
|
+
**slicing_kwargs: SlicingInputType,
|
|
242
394
|
) -> None:
|
|
243
395
|
"""Set a slice of the image.
|
|
244
396
|
|
|
@@ -246,12 +398,52 @@ class AbstractImage(Generic[_image_handler]):
|
|
|
246
398
|
roi: The region of interest to set the patch.
|
|
247
399
|
patch: The patch to set.
|
|
248
400
|
axes_order: The order of the axes to set the patch.
|
|
249
|
-
|
|
401
|
+
transforms: The transforms to apply to the patch.
|
|
402
|
+
**slicing_kwargs: The slices to set the patch.
|
|
250
403
|
|
|
251
404
|
"""
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
405
|
+
if isinstance(patch, np.ndarray):
|
|
406
|
+
roi_numpy_setter = build_roi_numpy_setter(
|
|
407
|
+
zarr_array=self.zarr_array,
|
|
408
|
+
dimensions=self.dimensions,
|
|
409
|
+
roi=roi,
|
|
410
|
+
pixel_size=self.pixel_size,
|
|
411
|
+
axes_order=axes_order,
|
|
412
|
+
transforms=transforms,
|
|
413
|
+
slicing_dict=slicing_kwargs,
|
|
414
|
+
)
|
|
415
|
+
roi_numpy_setter(patch)
|
|
416
|
+
|
|
417
|
+
elif isinstance(patch, da.Array):
|
|
418
|
+
roi_dask_setter = build_roi_dask_setter(
|
|
419
|
+
zarr_array=self.zarr_array,
|
|
420
|
+
dimensions=self.dimensions,
|
|
421
|
+
roi=roi,
|
|
422
|
+
pixel_size=self.pixel_size,
|
|
423
|
+
axes_order=axes_order,
|
|
424
|
+
transforms=transforms,
|
|
425
|
+
slicing_dict=slicing_kwargs,
|
|
426
|
+
)
|
|
427
|
+
roi_dask_setter(patch)
|
|
428
|
+
else:
|
|
429
|
+
raise TypeError(
|
|
430
|
+
f"Unsupported patch type: {type(patch)}. "
|
|
431
|
+
"Supported types are: "
|
|
432
|
+
"numpy.ndarray, dask.array.Array."
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
def _consolidate(
|
|
436
|
+
self,
|
|
437
|
+
order: Literal[0, 1, 2] = 1,
|
|
438
|
+
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
439
|
+
) -> None:
|
|
440
|
+
"""Consolidate the image on disk.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
order: The order of the consolidation.
|
|
444
|
+
mode: The mode of the consolidation.
|
|
445
|
+
"""
|
|
446
|
+
consolidate_image(image=self, order=order, mode=mode)
|
|
255
447
|
|
|
256
448
|
def build_image_roi_table(self, name: str = "image") -> RoiTable:
|
|
257
449
|
"""Build the ROI table for an image."""
|
|
@@ -275,86 +467,24 @@ def consolidate_image(
|
|
|
275
467
|
)
|
|
276
468
|
|
|
277
469
|
|
|
278
|
-
def get_roi_pipe(
|
|
279
|
-
image: AbstractImage,
|
|
280
|
-
roi: Roi,
|
|
281
|
-
axes_order: Collection[str] | None = None,
|
|
282
|
-
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
283
|
-
**slice_kwargs: slice | int | Iterable[int],
|
|
284
|
-
) -> ArrayLike:
|
|
285
|
-
"""Get a slice of the image.
|
|
286
|
-
|
|
287
|
-
Args:
|
|
288
|
-
image: The image to get the ROI.
|
|
289
|
-
roi: The region of interest to get the array.
|
|
290
|
-
axes_order: The order of the axes to return the array.
|
|
291
|
-
mode: The mode to return the array.
|
|
292
|
-
**slice_kwargs: The slices to get the array.
|
|
293
|
-
|
|
294
|
-
Returns:
|
|
295
|
-
The array of the region of interest.
|
|
296
|
-
"""
|
|
297
|
-
slice_kwargs = roi_to_slice_kwargs(
|
|
298
|
-
roi=roi,
|
|
299
|
-
pixel_size=image.pixel_size,
|
|
300
|
-
dimensions=image.dimensions,
|
|
301
|
-
**slice_kwargs,
|
|
302
|
-
)
|
|
303
|
-
return get_pipe(
|
|
304
|
-
array=image.zarr_array,
|
|
305
|
-
dimensions=image.dimensions,
|
|
306
|
-
axes_order=axes_order,
|
|
307
|
-
mode=mode,
|
|
308
|
-
**slice_kwargs,
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def set_roi_pipe(
|
|
313
|
-
image: AbstractImage,
|
|
314
|
-
roi: Roi,
|
|
315
|
-
patch: ArrayLike,
|
|
316
|
-
axes_order: Collection[str] | None = None,
|
|
317
|
-
**slice_kwargs: slice | int | Iterable[int],
|
|
318
|
-
) -> None:
|
|
319
|
-
"""Set a slice of the image.
|
|
320
|
-
|
|
321
|
-
Args:
|
|
322
|
-
image: The image to set the ROI.
|
|
323
|
-
roi: The region of interest to set the patch.
|
|
324
|
-
patch: The patch to set.
|
|
325
|
-
axes_order: The order of the axes to set the patch.
|
|
326
|
-
**slice_kwargs: The slices to set the patch.
|
|
327
|
-
|
|
328
|
-
"""
|
|
329
|
-
slice_kwargs = roi_to_slice_kwargs(
|
|
330
|
-
roi=roi,
|
|
331
|
-
pixel_size=image.pixel_size,
|
|
332
|
-
dimensions=image.dimensions,
|
|
333
|
-
**slice_kwargs,
|
|
334
|
-
)
|
|
335
|
-
set_pipe(
|
|
336
|
-
array=image.zarr_array,
|
|
337
|
-
patch=patch,
|
|
338
|
-
dimensions=image.dimensions,
|
|
339
|
-
axes_order=axes_order,
|
|
340
|
-
**slice_kwargs,
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
|
|
344
470
|
def build_image_roi_table(image: AbstractImage, name: str = "image") -> RoiTable:
|
|
345
471
|
"""Build the ROI table for an image."""
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
|
351
479
|
image_roi = RoiPixels(
|
|
352
480
|
name=name,
|
|
353
481
|
x=0,
|
|
354
482
|
y=0,
|
|
355
|
-
z=
|
|
483
|
+
z=z,
|
|
484
|
+
t=t,
|
|
356
485
|
x_length=dim_x,
|
|
357
486
|
y_length=dim_y,
|
|
358
487
|
z_length=dim_z,
|
|
488
|
+
t_length=dim_t,
|
|
359
489
|
)
|
|
360
490
|
return RoiTable(rois=[image_roi.to_roi(pixel_size=image.pixel_size)])
|
ngio/images/_create.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Utility functions for working with OME-Zarr images."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import
|
|
3
|
+
from collections.abc import Sequence
|
|
4
4
|
from typing import TypeVar
|
|
5
5
|
|
|
6
6
|
from ngio.common._pyramid import init_empty_pyramid
|
|
@@ -29,7 +29,7 @@ _image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelM
|
|
|
29
29
|
def _init_generic_meta(
|
|
30
30
|
meta_type: type[_image_or_label_meta],
|
|
31
31
|
pixelsize: float,
|
|
32
|
-
axes_names:
|
|
32
|
+
axes_names: Sequence[str],
|
|
33
33
|
z_spacing: float = 1.0,
|
|
34
34
|
time_spacing: float = 1.0,
|
|
35
35
|
levels: int | list[str] = 5,
|
|
@@ -80,7 +80,7 @@ def _init_generic_meta(
|
|
|
80
80
|
|
|
81
81
|
def create_empty_label_container(
|
|
82
82
|
store: StoreOrGroup,
|
|
83
|
-
shape:
|
|
83
|
+
shape: Sequence[int],
|
|
84
84
|
pixelsize: float,
|
|
85
85
|
z_spacing: float = 1.0,
|
|
86
86
|
time_spacing: float = 1.0,
|
|
@@ -89,10 +89,10 @@ def create_empty_label_container(
|
|
|
89
89
|
z_scaling_factor: float = 1.0,
|
|
90
90
|
space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
91
91
|
time_unit: TimeUnits | str | None = DefaultTimeUnit,
|
|
92
|
-
axes_names:
|
|
92
|
+
axes_names: Sequence[str] | None = None,
|
|
93
93
|
name: str | None = None,
|
|
94
|
-
chunks:
|
|
95
|
-
dtype: str = "
|
|
94
|
+
chunks: Sequence[int] | None = None,
|
|
95
|
+
dtype: str = "uint32",
|
|
96
96
|
overwrite: bool = False,
|
|
97
97
|
version: NgffVersions = DefaultNgffVersion,
|
|
98
98
|
) -> ZarrGroupHandler:
|
|
@@ -100,7 +100,7 @@ def create_empty_label_container(
|
|
|
100
100
|
|
|
101
101
|
Args:
|
|
102
102
|
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
103
|
-
shape (
|
|
103
|
+
shape (Sequence[int]): The shape of the image.
|
|
104
104
|
pixelsize (float): The pixel size in x and y dimensions.
|
|
105
105
|
z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
|
|
106
106
|
time_spacing (float, optional): The spacing between time points.
|
|
@@ -115,10 +115,10 @@ def create_empty_label_container(
|
|
|
115
115
|
DefaultSpaceUnit.
|
|
116
116
|
time_unit (TimeUnits, optional): The unit of time. Defaults to
|
|
117
117
|
DefaultTimeUnit.
|
|
118
|
-
axes_names (
|
|
118
|
+
axes_names (Sequence[str] | None, optional): The names of the axes.
|
|
119
119
|
If None the canonical names are used. Defaults to None.
|
|
120
120
|
name (str | None, optional): The name of the image. Defaults to None.
|
|
121
|
-
chunks (
|
|
121
|
+
chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
|
|
122
122
|
is used. Defaults to None.
|
|
123
123
|
dtype (str, optional): The data type of the image. Defaults to "uint16".
|
|
124
124
|
overwrite (bool, optional): Whether to overwrite an existing image.
|
|
@@ -171,7 +171,7 @@ def create_empty_label_container(
|
|
|
171
171
|
|
|
172
172
|
def create_empty_image_container(
|
|
173
173
|
store: StoreOrGroup,
|
|
174
|
-
shape:
|
|
174
|
+
shape: Sequence[int],
|
|
175
175
|
pixelsize: float,
|
|
176
176
|
z_spacing: float = 1.0,
|
|
177
177
|
time_spacing: float = 1.0,
|
|
@@ -180,9 +180,9 @@ def create_empty_image_container(
|
|
|
180
180
|
z_scaling_factor: float = 1.0,
|
|
181
181
|
space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
182
182
|
time_unit: TimeUnits | str | None = DefaultTimeUnit,
|
|
183
|
-
axes_names:
|
|
183
|
+
axes_names: Sequence[str] | None = None,
|
|
184
184
|
name: str | None = None,
|
|
185
|
-
chunks:
|
|
185
|
+
chunks: Sequence[int] | None = None,
|
|
186
186
|
dtype: str = "uint16",
|
|
187
187
|
overwrite: bool = False,
|
|
188
188
|
version: NgffVersions = DefaultNgffVersion,
|
|
@@ -191,7 +191,7 @@ def create_empty_image_container(
|
|
|
191
191
|
|
|
192
192
|
Args:
|
|
193
193
|
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
194
|
-
shape (
|
|
194
|
+
shape (Sequence[int]): The shape of the image.
|
|
195
195
|
pixelsize (float): The pixel size in x and y dimensions.
|
|
196
196
|
z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
|
|
197
197
|
time_spacing (float, optional): The spacing between time points.
|
|
@@ -206,10 +206,10 @@ def create_empty_image_container(
|
|
|
206
206
|
DefaultSpaceUnit.
|
|
207
207
|
time_unit (TimeUnits, optional): The unit of time. Defaults to
|
|
208
208
|
DefaultTimeUnit.
|
|
209
|
-
axes_names (
|
|
209
|
+
axes_names (Sequence[str] | None, optional): The names of the axes.
|
|
210
210
|
If None the canonical names are used. Defaults to None.
|
|
211
211
|
name (str | None, optional): The name of the image. Defaults to None.
|
|
212
|
-
chunks (
|
|
212
|
+
chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
|
|
213
213
|
is used. Defaults to None.
|
|
214
214
|
dtype (str, optional): The data type of the image. Defaults to "uint16".
|
|
215
215
|
overwrite (bool, optional): Whether to overwrite an existing image.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Abstract class for handling OME-NGFF images."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import PIL.Image
|
|
7
|
+
|
|
8
|
+
from ngio.common._synt_images_utils import fit_to_shape
|
|
9
|
+
from ngio.images._ome_zarr_container import OmeZarrContainer, create_ome_zarr_from_array
|
|
10
|
+
from ngio.ome_zarr_meta.ngio_specs import (
|
|
11
|
+
DefaultNgffVersion,
|
|
12
|
+
NgffVersions,
|
|
13
|
+
)
|
|
14
|
+
from ngio.resources import AVAILABLE_SAMPLES, SampleInfo, get_sample_info
|
|
15
|
+
from ngio.tables import (
|
|
16
|
+
DefaultTableBackend,
|
|
17
|
+
TableBackend,
|
|
18
|
+
)
|
|
19
|
+
from ngio.utils import (
|
|
20
|
+
StoreOrGroup,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_synthetic_ome_zarr(
|
|
25
|
+
store: StoreOrGroup,
|
|
26
|
+
shape: Sequence[int],
|
|
27
|
+
reference_sample: AVAILABLE_SAMPLES | SampleInfo = "Cardiomyocyte",
|
|
28
|
+
levels: int | list[str] = 5,
|
|
29
|
+
xy_scaling_factor: float = 2,
|
|
30
|
+
z_scaling_factor: float = 1.0,
|
|
31
|
+
axes_names: Sequence[str] | None = None,
|
|
32
|
+
chunks: Sequence[int] | None = None,
|
|
33
|
+
channel_labels: list[str] | None = None,
|
|
34
|
+
channel_wavelengths: list[str] | None = None,
|
|
35
|
+
channel_colors: Sequence[str] | None = None,
|
|
36
|
+
channel_active: Sequence[bool] | None = None,
|
|
37
|
+
table_backend: TableBackend = DefaultTableBackend,
|
|
38
|
+
overwrite: bool = False,
|
|
39
|
+
version: NgffVersions = DefaultNgffVersion,
|
|
40
|
+
) -> OmeZarrContainer:
|
|
41
|
+
"""Create an empty OME-Zarr image with the given shape and metadata.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
45
|
+
shape (Sequence[int]): The shape of the image.
|
|
46
|
+
reference_sample (AVAILABLE_SAMPLES | SampleInfo): The reference sample to use.
|
|
47
|
+
levels (int | list[str], optional): The number of levels in the pyramid or a
|
|
48
|
+
list of level names. Defaults to 5.
|
|
49
|
+
xy_scaling_factor (float, optional): The down-scaling factor in x and y
|
|
50
|
+
dimensions. Defaults to 2.0.
|
|
51
|
+
z_scaling_factor (float, optional): The down-scaling factor in z dimension.
|
|
52
|
+
Defaults to 1.0.
|
|
53
|
+
axes_names (Sequence[str] | None, optional): The names of the axes.
|
|
54
|
+
If None the canonical names are used. Defaults to None.
|
|
55
|
+
chunks (Sequence[int] | None, optional): The chunk shape. If None the shape
|
|
56
|
+
is used. Defaults to None.
|
|
57
|
+
channel_labels (list[str] | None, optional): The labels of the channels.
|
|
58
|
+
Defaults to None.
|
|
59
|
+
channel_wavelengths (list[str] | None, optional): The wavelengths of the
|
|
60
|
+
channels. Defaults to None.
|
|
61
|
+
channel_colors (Sequence[str] | None, optional): The colors of the channels.
|
|
62
|
+
Defaults to None.
|
|
63
|
+
channel_active (Sequence[bool] | None, optional): Whether the channels are
|
|
64
|
+
active. Defaults to None.
|
|
65
|
+
table_backend (TableBackend): Table backend to be used to store tables
|
|
66
|
+
overwrite (bool, optional): Whether to overwrite an existing image.
|
|
67
|
+
Defaults to True.
|
|
68
|
+
version (NgffVersion, optional): The version of the OME-Zarr specification.
|
|
69
|
+
Defaults to DefaultNgffVersion.
|
|
70
|
+
"""
|
|
71
|
+
if isinstance(reference_sample, str):
|
|
72
|
+
sample_info = get_sample_info(reference_sample)
|
|
73
|
+
else:
|
|
74
|
+
sample_info = reference_sample
|
|
75
|
+
|
|
76
|
+
raw = np.asarray(PIL.Image.open(sample_info.img_path))
|
|
77
|
+
raw = fit_to_shape(arr=raw, out_shape=tuple(shape))
|
|
78
|
+
raw = raw / np.max(raw) * (2**16 - 1)
|
|
79
|
+
raw = raw.astype(np.uint16)
|
|
80
|
+
ome_zarr = create_ome_zarr_from_array(
|
|
81
|
+
store=store,
|
|
82
|
+
array=raw,
|
|
83
|
+
xy_pixelsize=sample_info.xy_pixelsize,
|
|
84
|
+
z_spacing=sample_info.z_spacing,
|
|
85
|
+
time_spacing=sample_info.time_spacing,
|
|
86
|
+
levels=levels,
|
|
87
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
88
|
+
z_scaling_factor=z_scaling_factor,
|
|
89
|
+
space_unit=sample_info.space_unit,
|
|
90
|
+
time_unit=sample_info.time_unit,
|
|
91
|
+
axes_names=axes_names,
|
|
92
|
+
channel_labels=channel_labels,
|
|
93
|
+
channel_wavelengths=channel_wavelengths,
|
|
94
|
+
channel_colors=channel_colors,
|
|
95
|
+
channel_active=channel_active,
|
|
96
|
+
name=sample_info.name,
|
|
97
|
+
chunks=chunks,
|
|
98
|
+
overwrite=overwrite,
|
|
99
|
+
version=version,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
image = ome_zarr.get_image()
|
|
103
|
+
well_table = image.build_image_roi_table()
|
|
104
|
+
ome_zarr.add_table("well_ROI_table", table=well_table, backend=table_backend)
|
|
105
|
+
|
|
106
|
+
for label_info in sample_info.labels:
|
|
107
|
+
ome_zarr.derive_label(name=label_info.name)
|
|
108
|
+
label = ome_zarr.get_label(name=label_info.name)
|
|
109
|
+
|
|
110
|
+
ref_label = np.asarray(PIL.Image.open(label_info.label_path))
|
|
111
|
+
ref_label = fit_to_shape(
|
|
112
|
+
arr=ref_label,
|
|
113
|
+
out_shape=label.shape,
|
|
114
|
+
ensure_unique_info=label_info.ensure_unique_labels,
|
|
115
|
+
)
|
|
116
|
+
ref_label = ref_label.astype(np.uint32)
|
|
117
|
+
label.set_array(ref_label)
|
|
118
|
+
label.consolidate()
|
|
119
|
+
|
|
120
|
+
if label_info.create_masking_table:
|
|
121
|
+
masking_table = label.build_masking_roi_table()
|
|
122
|
+
ome_zarr.add_table(
|
|
123
|
+
name=f"{label_info.name}_masking_table",
|
|
124
|
+
table=masking_table,
|
|
125
|
+
backend=table_backend,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return ome_zarr
|