ngio 0.5.0b6__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 (88) hide show
  1. ngio/__init__.py +69 -0
  2. ngio/common/__init__.py +28 -0
  3. ngio/common/_dimensions.py +335 -0
  4. ngio/common/_masking_roi.py +153 -0
  5. ngio/common/_pyramid.py +408 -0
  6. ngio/common/_roi.py +315 -0
  7. ngio/common/_synt_images_utils.py +101 -0
  8. ngio/common/_zoom.py +188 -0
  9. ngio/experimental/__init__.py +5 -0
  10. ngio/experimental/iterators/__init__.py +15 -0
  11. ngio/experimental/iterators/_abstract_iterator.py +390 -0
  12. ngio/experimental/iterators/_feature.py +189 -0
  13. ngio/experimental/iterators/_image_processing.py +130 -0
  14. ngio/experimental/iterators/_mappers.py +48 -0
  15. ngio/experimental/iterators/_rois_utils.py +126 -0
  16. ngio/experimental/iterators/_segmentation.py +235 -0
  17. ngio/hcs/__init__.py +19 -0
  18. ngio/hcs/_plate.py +1354 -0
  19. ngio/images/__init__.py +44 -0
  20. ngio/images/_abstract_image.py +967 -0
  21. ngio/images/_create_synt_container.py +132 -0
  22. ngio/images/_create_utils.py +423 -0
  23. ngio/images/_image.py +926 -0
  24. ngio/images/_label.py +411 -0
  25. ngio/images/_masked_image.py +531 -0
  26. ngio/images/_ome_zarr_container.py +1237 -0
  27. ngio/images/_table_ops.py +471 -0
  28. ngio/io_pipes/__init__.py +75 -0
  29. ngio/io_pipes/_io_pipes.py +361 -0
  30. ngio/io_pipes/_io_pipes_masked.py +488 -0
  31. ngio/io_pipes/_io_pipes_roi.py +146 -0
  32. ngio/io_pipes/_io_pipes_types.py +56 -0
  33. ngio/io_pipes/_match_shape.py +377 -0
  34. ngio/io_pipes/_ops_axes.py +344 -0
  35. ngio/io_pipes/_ops_slices.py +411 -0
  36. ngio/io_pipes/_ops_slices_utils.py +199 -0
  37. ngio/io_pipes/_ops_transforms.py +104 -0
  38. ngio/io_pipes/_zoom_transform.py +180 -0
  39. ngio/ome_zarr_meta/__init__.py +65 -0
  40. ngio/ome_zarr_meta/_meta_handlers.py +536 -0
  41. ngio/ome_zarr_meta/ngio_specs/__init__.py +77 -0
  42. ngio/ome_zarr_meta/ngio_specs/_axes.py +515 -0
  43. ngio/ome_zarr_meta/ngio_specs/_channels.py +462 -0
  44. ngio/ome_zarr_meta/ngio_specs/_dataset.py +89 -0
  45. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +539 -0
  46. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +438 -0
  47. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +122 -0
  48. ngio/ome_zarr_meta/v04/__init__.py +27 -0
  49. ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
  50. ngio/ome_zarr_meta/v04/_v04_spec.py +473 -0
  51. ngio/ome_zarr_meta/v05/__init__.py +27 -0
  52. ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
  53. ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
  54. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/mask.png +0 -0
  55. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/nuclei.png +0 -0
  56. ngio/resources/20200812-CardiomyocyteDifferentiation14-Cycle1_B03/raw.jpg +0 -0
  57. ngio/resources/__init__.py +55 -0
  58. ngio/resources/resource_model.py +36 -0
  59. ngio/tables/__init__.py +43 -0
  60. ngio/tables/_abstract_table.py +270 -0
  61. ngio/tables/_tables_container.py +449 -0
  62. ngio/tables/backends/__init__.py +57 -0
  63. ngio/tables/backends/_abstract_backend.py +240 -0
  64. ngio/tables/backends/_anndata.py +139 -0
  65. ngio/tables/backends/_anndata_utils.py +90 -0
  66. ngio/tables/backends/_csv.py +19 -0
  67. ngio/tables/backends/_json.py +92 -0
  68. ngio/tables/backends/_parquet.py +19 -0
  69. ngio/tables/backends/_py_arrow_backends.py +222 -0
  70. ngio/tables/backends/_table_backends.py +226 -0
  71. ngio/tables/backends/_utils.py +608 -0
  72. ngio/tables/v1/__init__.py +23 -0
  73. ngio/tables/v1/_condition_table.py +71 -0
  74. ngio/tables/v1/_feature_table.py +125 -0
  75. ngio/tables/v1/_generic_table.py +49 -0
  76. ngio/tables/v1/_roi_table.py +575 -0
  77. ngio/transforms/__init__.py +5 -0
  78. ngio/transforms/_zoom.py +19 -0
  79. ngio/utils/__init__.py +45 -0
  80. ngio/utils/_cache.py +48 -0
  81. ngio/utils/_datasets.py +165 -0
  82. ngio/utils/_errors.py +37 -0
  83. ngio/utils/_fractal_fsspec_store.py +42 -0
  84. ngio/utils/_zarr_utils.py +534 -0
  85. ngio-0.5.0b6.dist-info/METADATA +148 -0
  86. ngio-0.5.0b6.dist-info/RECORD +88 -0
  87. ngio-0.5.0b6.dist-info/WHEEL +4 -0
  88. ngio-0.5.0b6.dist-info/licenses/LICENSE +28 -0
ngio/images/_label.py ADDED
@@ -0,0 +1,411 @@
1
+ """A module for handling label images in OME-NGFF files."""
2
+
3
+ from collections.abc import Mapping, Sequence
4
+ from typing import Any, Literal
5
+
6
+ from zarr.core.array import CompressorLike
7
+
8
+ from ngio.common import compute_masking_roi
9
+ from ngio.common._pyramid import ChunksLike, ShardsLike
10
+ from ngio.images._abstract_image import AbstractImage, abstract_derive
11
+ from ngio.images._image import Image
12
+ from ngio.ome_zarr_meta import (
13
+ LabelMetaHandler,
14
+ LabelsGroupMetaHandler,
15
+ NgioLabelMeta,
16
+ NgioLabelsGroupMeta,
17
+ PixelSize,
18
+ update_ngio_labels_group_meta,
19
+ )
20
+ from ngio.ome_zarr_meta.ngio_specs import (
21
+ DefaultSpaceUnit,
22
+ DefaultTimeUnit,
23
+ NgffVersions,
24
+ SpaceUnits,
25
+ TimeUnits,
26
+ )
27
+ from ngio.tables import MaskingRoiTable
28
+ from ngio.utils import (
29
+ NgioValidationError,
30
+ NgioValueError,
31
+ StoreOrGroup,
32
+ ZarrGroupHandler,
33
+ )
34
+
35
+
36
+ class Label(AbstractImage):
37
+ """Placeholder class for a label."""
38
+
39
+ get_as_numpy = AbstractImage._get_as_numpy
40
+ get_as_dask = AbstractImage._get_as_dask
41
+ get_array = AbstractImage._get_array
42
+ get_roi_as_numpy = AbstractImage._get_roi_as_numpy
43
+ get_roi_as_dask = AbstractImage._get_roi_as_dask
44
+ get_roi = AbstractImage._get_roi
45
+ set_array = AbstractImage._set_array
46
+ set_roi = AbstractImage._set_roi
47
+
48
+ def __init__(
49
+ self,
50
+ group_handler: ZarrGroupHandler,
51
+ path: str,
52
+ meta_handler: LabelMetaHandler | None,
53
+ ) -> None:
54
+ """Initialize the Image at a single level.
55
+
56
+ Args:
57
+ group_handler: The Zarr group handler.
58
+ path: The path to the image in the ome_zarr file.
59
+ meta_handler: The image metadata handler.
60
+
61
+ """
62
+ if meta_handler is None:
63
+ meta_handler = LabelMetaHandler(group_handler)
64
+ super().__init__(
65
+ group_handler=group_handler, path=path, meta_handler=meta_handler
66
+ )
67
+
68
+ def __repr__(self) -> str:
69
+ """Return the string representation of the label."""
70
+ return f"Label(path={self.path}, {self.dimensions})"
71
+
72
+ @property
73
+ def meta_handler(self) -> LabelMetaHandler:
74
+ """Return the metadata handler."""
75
+ assert isinstance(self._meta_handler, LabelMetaHandler)
76
+ return self._meta_handler
77
+
78
+ @property
79
+ def meta(self) -> NgioLabelMeta:
80
+ """Return the metadata."""
81
+ meta = self.meta_handler.get_meta()
82
+ assert isinstance(meta, NgioLabelMeta)
83
+ return meta
84
+
85
+ def set_axes_unit(
86
+ self,
87
+ space_unit: SpaceUnits = DefaultSpaceUnit,
88
+ time_unit: TimeUnits = DefaultTimeUnit,
89
+ ) -> None:
90
+ """Set the axes unit of the image.
91
+
92
+ Args:
93
+ space_unit (SpaceUnits): The space unit of the image.
94
+ time_unit (TimeUnits): The time unit of the image.
95
+ """
96
+ meta = self.meta
97
+ meta = meta.to_units(space_unit=space_unit, time_unit=time_unit)
98
+ self.meta_handler.update_meta(meta)
99
+
100
+ def build_masking_roi_table(
101
+ self, axes_order: Sequence[str] | None = None
102
+ ) -> MaskingRoiTable:
103
+ """Compute the masking ROI table."""
104
+ return build_masking_roi_table(self, axes_order=axes_order)
105
+
106
+ def consolidate(
107
+ self,
108
+ mode: Literal["dask", "numpy", "coarsen"] = "dask",
109
+ ) -> None:
110
+ """Consolidate the label on disk."""
111
+ self._consolidate(
112
+ order="nearest",
113
+ mode=mode,
114
+ )
115
+
116
+
117
+ class LabelsContainer:
118
+ """A class to handle the /labels group in an OME-NGFF file."""
119
+
120
+ def __init__(
121
+ self,
122
+ group_handler: ZarrGroupHandler,
123
+ ngff_version: NgffVersions | None = None,
124
+ ) -> None:
125
+ """Initialize the LabelGroupHandler."""
126
+ self._group_handler = group_handler
127
+ # If the group is empty, initialize the metadata
128
+ try:
129
+ self._meta_handler = LabelsGroupMetaHandler(group_handler)
130
+ except NgioValidationError:
131
+ if ngff_version is None:
132
+ raise NgioValueError(
133
+ "The /labels group is missing metadata. "
134
+ "Please provide the ngff_version to initialize it."
135
+ ) from None
136
+ meta = NgioLabelsGroupMeta(labels=[], version=ngff_version)
137
+ update_ngio_labels_group_meta(
138
+ group_handler=group_handler,
139
+ ngio_meta=meta,
140
+ )
141
+ self._group_handler = self._group_handler.reopen_handler()
142
+ self._meta_handler = LabelsGroupMetaHandler(group_handler)
143
+
144
+ @property
145
+ def meta(self) -> NgioLabelsGroupMeta:
146
+ """Return the metadata."""
147
+ meta = self._meta_handler.get_meta()
148
+ return meta
149
+
150
+ def list(self) -> list[str]:
151
+ """Create the /labels group if it doesn't exist."""
152
+ return self.meta.labels
153
+
154
+ def get(
155
+ self,
156
+ name: str,
157
+ path: str | None = None,
158
+ pixel_size: PixelSize | None = None,
159
+ strict: bool = False,
160
+ ) -> Label:
161
+ """Get a label from the group.
162
+
163
+ Args:
164
+ name (str): The name of the label.
165
+ path (str | None): The path to the image in the ome_zarr file.
166
+ pixel_size (PixelSize | None): The pixel size of the image.
167
+ strict (bool): Only used if the pixel size is provided. If True, the
168
+ pixel size must match the image pixel size exactly. If False, the
169
+ closest pixel size level will be returned.
170
+
171
+ """
172
+ if name not in self.list():
173
+ raise NgioValueError(
174
+ f"Label '{name}' not found in the Labels group. "
175
+ f"Available labels: {self.list()}"
176
+ )
177
+
178
+ group_handler = self._group_handler.get_handler(name)
179
+ label_meta_handler = LabelMetaHandler(group_handler)
180
+ path = (
181
+ label_meta_handler.get_meta()
182
+ .get_dataset(path=path, pixel_size=pixel_size, strict=strict)
183
+ .path
184
+ )
185
+ return Label(group_handler, path, label_meta_handler)
186
+
187
+ def delete(self, name: str, missing_ok: bool = False) -> None:
188
+ """Delete a label from the group.
189
+
190
+ Args:
191
+ name (str): The name of the label to delete.
192
+ missing_ok (bool): If True, do not raise an error if the label does not
193
+ exist.
194
+
195
+ """
196
+ existing_labels = self.list()
197
+ if name not in existing_labels:
198
+ if missing_ok:
199
+ return
200
+ raise NgioValueError(
201
+ f"Label '{name}' not found in the Labels group. "
202
+ f"Available labels: {existing_labels}"
203
+ )
204
+
205
+ self._group_handler.delete_group(name)
206
+ existing_labels.remove(name)
207
+ update_meta = NgioLabelsGroupMeta(
208
+ labels=existing_labels, version=self.meta.version
209
+ )
210
+ self._meta_handler.update_meta(update_meta)
211
+
212
+ def derive(
213
+ self,
214
+ name: str,
215
+ ref_image: Image | Label,
216
+ # Metadata parameters
217
+ shape: Sequence[int] | None = None,
218
+ pixelsize: float | tuple[float, float] | None = None,
219
+ z_spacing: float | None = None,
220
+ time_spacing: float | None = None,
221
+ channels_policy: Literal["same", "squeeze", "singleton"] | int = "squeeze",
222
+ ngff_version: NgffVersions | None = None,
223
+ # Zarr Array parameters
224
+ chunks: ChunksLike | None = None,
225
+ shards: ShardsLike | None = None,
226
+ dtype: str | None = None,
227
+ dimension_separator: Literal[".", "/"] | None = None,
228
+ compressors: CompressorLike | None = None,
229
+ extra_array_kwargs: Mapping[str, Any] | None = None,
230
+ overwrite: bool = False,
231
+ # Deprecated arguments
232
+ labels: Sequence[str] | None = None,
233
+ pixel_size: PixelSize | None = None,
234
+ ) -> "Label":
235
+ """Create an empty OME-Zarr label from an existing image or label.
236
+
237
+ If a kwarg is not provided, the value from the reference image will be used.
238
+
239
+ Args:
240
+ name (str): The name of the new label.
241
+ ref_image (Image | Label): The reference image to derive the new label from.
242
+ shape (Sequence[int] | None): The shape of the new label.
243
+ pixelsize (float | tuple[float, float] | None): The pixel size of the new
244
+ label.
245
+ z_spacing (float | None): The z spacing of the new label.
246
+ time_spacing (float | None): The time spacing of the new label.
247
+ channels_policy (Literal["squeeze", "same", "singleton"] | int):
248
+ Possible policies:
249
+ - If "squeeze", the channels axis will be removed (no matter its size).
250
+ - If "same", the channels axis will be kept as is (if it exists).
251
+ - If "singleton", the channels axis will be set to size 1.
252
+ - If an integer is provided, the channels axis will be changed to have
253
+ that size.
254
+ ngff_version (NgffVersions | None): The NGFF version to use.
255
+ chunks (ChunksLike | None): The chunk shape of the new label.
256
+ shards (ShardsLike | None): The shard shape of the new label.
257
+ dtype (str | None): The data type of the new label.
258
+ dimension_separator (Literal[".", "/"] | None): The separator to use for
259
+ dimensions.
260
+ compressors (CompressorLike | None): The compressors to use.
261
+ extra_array_kwargs (Mapping[str, Any] | None): Extra arguments to pass to
262
+ the zarr array creation.
263
+ overwrite (bool): Whether to overwrite an existing label.
264
+ labels (Sequence[str] | None): Deprecated. This argument is deprecated,
265
+ please use channels_meta instead.
266
+ pixel_size (PixelSize | None): Deprecated. The pixel size of the new label.
267
+ This argument is deprecated, please use pixelsize, z_spacing,
268
+ and time_spacing instead.
269
+
270
+ Returns:
271
+ Label: The new derived label.
272
+
273
+ """
274
+ existing_labels = self.list()
275
+ if name in existing_labels and not overwrite:
276
+ raise NgioValueError(
277
+ f"Label '{name}' already exists in the group. "
278
+ "Use overwrite=True to replace it."
279
+ )
280
+
281
+ label_group = self._group_handler.get_group(name, create_mode=True)
282
+
283
+ derive_label(
284
+ ref_image=ref_image,
285
+ store=label_group,
286
+ shape=shape,
287
+ pixelsize=pixelsize,
288
+ z_spacing=z_spacing,
289
+ time_spacing=time_spacing,
290
+ name=name,
291
+ channels_policy=channels_policy,
292
+ ngff_version=ngff_version,
293
+ chunks=chunks,
294
+ shards=shards,
295
+ dtype=dtype,
296
+ dimension_separator=dimension_separator,
297
+ compressors=compressors,
298
+ extra_array_kwargs=extra_array_kwargs,
299
+ overwrite=overwrite,
300
+ labels=labels,
301
+ pixel_size=pixel_size,
302
+ )
303
+
304
+ if name not in existing_labels:
305
+ existing_labels.append(name)
306
+
307
+ update_meta = NgioLabelsGroupMeta(
308
+ labels=existing_labels, version=self.meta.version
309
+ )
310
+ self._meta_handler.update_meta(update_meta)
311
+ return self.get(name)
312
+
313
+
314
+ def derive_label(
315
+ *,
316
+ store: StoreOrGroup,
317
+ ref_image: Image | Label,
318
+ # Metadata parameters
319
+ shape: Sequence[int] | None = None,
320
+ pixelsize: float | tuple[float, float] | None = None,
321
+ z_spacing: float | None = None,
322
+ time_spacing: float | None = None,
323
+ name: str | None = None,
324
+ channels_policy: Literal["same", "squeeze", "singleton"] | int = "squeeze",
325
+ ngff_version: NgffVersions | None = None,
326
+ # Zarr Array parameters
327
+ chunks: ChunksLike | None = None,
328
+ shards: ShardsLike | None = None,
329
+ dtype: str | None = None,
330
+ dimension_separator: Literal[".", "/"] | None = None,
331
+ compressors: CompressorLike | None = None,
332
+ extra_array_kwargs: Mapping[str, Any] | None = None,
333
+ overwrite: bool = False,
334
+ # Deprecated arguments
335
+ labels: Sequence[str] | None = None,
336
+ pixel_size: PixelSize | None = None,
337
+ ) -> ZarrGroupHandler:
338
+ """Derive a new OME-Zarr label from an existing image or label.
339
+
340
+ If a kwarg is not provided, the value from the reference image will be used.
341
+
342
+ Args:
343
+ store (StoreOrGroup): The Zarr store or group to create the label in.
344
+ ref_image (Image | Label): The reference image to derive the new label from.
345
+ shape (Sequence[int] | None): The shape of the new label.
346
+ pixelsize (float | tuple[float, float] | None): The pixel size of the new label.
347
+ z_spacing (float | None): The z spacing of the new label.
348
+ time_spacing (float | None): The time spacing of the new label.
349
+ name (str | None): The name of the new label.
350
+ channels_policy (Literal["squeeze", "same", "singleton"] | int): Possible
351
+ policies:
352
+ - If "squeeze", the channels axis will be removed (no matter its size).
353
+ - If "same", the channels axis will be kept as is (if it exists).
354
+ - If "singleton", the channels axis will be set to size 1.
355
+ - If an integer is provided, the channels axis will be changed to have that
356
+ size.
357
+ ngff_version (NgffVersions | None): The NGFF version to use.
358
+ chunks (ChunksLike | None): The chunk shape of the new label.
359
+ shards (ShardsLike | None): The shard shape of the new label.
360
+ dtype (str | None): The data type of the new label.
361
+ dimension_separator (Literal[".", "/"] | None): The separator to use for
362
+ dimensions.
363
+ compressors (CompressorLike | None): The compressors to use.
364
+ extra_array_kwargs (Mapping[str, Any] | None): Extra arguments to pass to
365
+ the zarr array creation.
366
+ overwrite (bool): Whether to overwrite an existing label. Defaults to False.
367
+ labels (Sequence[str] | None): Deprecated. This argument is deprecated,
368
+ please use channels_meta instead.
369
+ pixel_size (PixelSize | None): Deprecated. The pixel size of the new label.
370
+ This argument is deprecated, please use pixelsize, z_spacing,
371
+ and time_spacing instead.
372
+
373
+ Returns:
374
+ ZarrGroupHandler: The group handler of the new label.
375
+
376
+ """
377
+ if dtype is None and isinstance(ref_image, Image):
378
+ dtype = "uint32"
379
+ group_handler = abstract_derive(
380
+ ref_image=ref_image,
381
+ meta_type=NgioLabelMeta,
382
+ store=store,
383
+ shape=shape,
384
+ pixelsize=pixelsize,
385
+ z_spacing=z_spacing,
386
+ time_spacing=time_spacing,
387
+ name=name,
388
+ channels_meta=None,
389
+ channels_policy=channels_policy,
390
+ ngff_version=ngff_version,
391
+ chunks=chunks,
392
+ shards=shards,
393
+ dtype=dtype,
394
+ dimension_separator=dimension_separator,
395
+ compressors=compressors,
396
+ extra_array_kwargs=extra_array_kwargs,
397
+ overwrite=overwrite,
398
+ labels=labels,
399
+ pixel_size=pixel_size,
400
+ )
401
+ return group_handler
402
+
403
+
404
+ def build_masking_roi_table(
405
+ label: Label, axes_order: Sequence[str] | None = None
406
+ ) -> MaskingRoiTable:
407
+ """Compute the masking ROI table for a label."""
408
+ axes_order = axes_order or label.axes
409
+ array = label.get_as_dask(axes_order=axes_order)
410
+ rois = compute_masking_roi(array, label.pixel_size, axes_order=axes_order)
411
+ return MaskingRoiTable(rois, reference_label=label.meta.name)