ngio 0.1.5__py3-none-any.whl → 0.2.0__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 (87) hide show
  1. ngio/__init__.py +33 -5
  2. ngio/common/__init__.py +54 -0
  3. ngio/common/_array_pipe.py +265 -0
  4. ngio/common/_axes_transforms.py +64 -0
  5. ngio/common/_common_types.py +5 -0
  6. ngio/common/_dimensions.py +120 -0
  7. ngio/common/_masking_roi.py +158 -0
  8. ngio/common/_pyramid.py +228 -0
  9. ngio/common/_roi.py +165 -0
  10. ngio/common/_slicer.py +96 -0
  11. ngio/{pipes/_zoom_utils.py → common/_zoom.py} +51 -83
  12. ngio/hcs/__init__.py +5 -0
  13. ngio/hcs/plate.py +448 -0
  14. ngio/images/__init__.py +23 -0
  15. ngio/images/abstract_image.py +349 -0
  16. ngio/images/create.py +270 -0
  17. ngio/images/image.py +453 -0
  18. ngio/images/label.py +285 -0
  19. ngio/images/masked_image.py +273 -0
  20. ngio/images/ome_zarr_container.py +738 -0
  21. ngio/ome_zarr_meta/__init__.py +47 -0
  22. ngio/ome_zarr_meta/_meta_handlers.py +791 -0
  23. ngio/ome_zarr_meta/ngio_specs/__init__.py +71 -0
  24. ngio/ome_zarr_meta/ngio_specs/_axes.py +481 -0
  25. ngio/ome_zarr_meta/ngio_specs/_channels.py +389 -0
  26. ngio/ome_zarr_meta/ngio_specs/_dataset.py +134 -0
  27. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +377 -0
  28. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +489 -0
  29. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +116 -0
  30. ngio/ome_zarr_meta/v04/__init__.py +23 -0
  31. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +485 -0
  32. ngio/tables/__init__.py +24 -6
  33. ngio/tables/_validators.py +190 -0
  34. ngio/tables/backends/__init__.py +8 -0
  35. ngio/tables/backends/_abstract_backend.py +71 -0
  36. ngio/tables/backends/_anndata_utils.py +198 -0
  37. ngio/tables/backends/_anndata_v1.py +76 -0
  38. ngio/tables/backends/_json_v1.py +56 -0
  39. ngio/tables/backends/_table_backends.py +102 -0
  40. ngio/tables/tables_container.py +310 -0
  41. ngio/tables/v1/__init__.py +5 -5
  42. ngio/tables/v1/_feature_table.py +182 -0
  43. ngio/tables/v1/_generic_table.py +160 -179
  44. ngio/tables/v1/_roi_table.py +366 -0
  45. ngio/utils/__init__.py +26 -10
  46. ngio/utils/_datasets.py +53 -0
  47. ngio/utils/_errors.py +10 -4
  48. ngio/utils/_fractal_fsspec_store.py +13 -0
  49. ngio/utils/_logger.py +3 -1
  50. ngio/utils/_zarr_utils.py +401 -0
  51. {ngio-0.1.5.dist-info → ngio-0.2.0.dist-info}/METADATA +31 -43
  52. ngio-0.2.0.dist-info/RECORD +54 -0
  53. ngio/core/__init__.py +0 -7
  54. ngio/core/dimensions.py +0 -122
  55. ngio/core/image_handler.py +0 -228
  56. ngio/core/image_like_handler.py +0 -549
  57. ngio/core/label_handler.py +0 -410
  58. ngio/core/ngff_image.py +0 -387
  59. ngio/core/roi.py +0 -92
  60. ngio/core/utils.py +0 -287
  61. ngio/io/__init__.py +0 -19
  62. ngio/io/_zarr.py +0 -88
  63. ngio/io/_zarr_array_utils.py +0 -0
  64. ngio/io/_zarr_group_utils.py +0 -61
  65. ngio/iterators/__init__.py +0 -1
  66. ngio/ngff_meta/__init__.py +0 -27
  67. ngio/ngff_meta/fractal_image_meta.py +0 -1267
  68. ngio/ngff_meta/meta_handler.py +0 -92
  69. ngio/ngff_meta/utils.py +0 -235
  70. ngio/ngff_meta/v04/__init__.py +0 -6
  71. ngio/ngff_meta/v04/specs.py +0 -158
  72. ngio/ngff_meta/v04/zarr_utils.py +0 -376
  73. ngio/pipes/__init__.py +0 -7
  74. ngio/pipes/_slicer_transforms.py +0 -176
  75. ngio/pipes/_transforms.py +0 -33
  76. ngio/pipes/data_pipe.py +0 -52
  77. ngio/tables/_ad_reader.py +0 -80
  78. ngio/tables/_utils.py +0 -301
  79. ngio/tables/tables_group.py +0 -252
  80. ngio/tables/v1/feature_tables.py +0 -182
  81. ngio/tables/v1/masking_roi_tables.py +0 -243
  82. ngio/tables/v1/roi_tables.py +0 -285
  83. ngio/utils/_common_types.py +0 -5
  84. ngio/utils/_pydantic_utils.py +0 -52
  85. ngio-0.1.5.dist-info/RECORD +0 -44
  86. {ngio-0.1.5.dist-info → ngio-0.2.0.dist-info}/WHEEL +0 -0
  87. {ngio-0.1.5.dist-info → ngio-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,738 @@
1
+ """Abstract class for handling OME-NGFF images."""
2
+
3
+ from collections.abc import Collection
4
+ from typing import Literal, overload
5
+
6
+ import numpy as np
7
+
8
+ from ngio.images.create import _create_empty_image
9
+ from ngio.images.image import Image, ImagesContainer
10
+ from ngio.images.label import Label, LabelsContainer
11
+ from ngio.images.masked_image import MaskedImage, MaskedLabel
12
+ from ngio.ome_zarr_meta import (
13
+ NgioImageMeta,
14
+ PixelSize,
15
+ )
16
+ from ngio.ome_zarr_meta.ngio_specs import (
17
+ SpaceUnits,
18
+ TimeUnits,
19
+ )
20
+ from ngio.tables import (
21
+ FeatureTable,
22
+ GenericRoiTable,
23
+ MaskingRoiTable,
24
+ RoiTable,
25
+ Table,
26
+ TablesContainer,
27
+ TypedTable,
28
+ )
29
+ from ngio.utils import (
30
+ AccessModeLiteral,
31
+ NgioValidationError,
32
+ NgioValueError,
33
+ StoreOrGroup,
34
+ ZarrGroupHandler,
35
+ )
36
+
37
+
38
+ def _default_table_container(handler: ZarrGroupHandler) -> TablesContainer | None:
39
+ """Return a default table container."""
40
+ success, table_handler = handler.safe_derive_handler("tables")
41
+ if success and isinstance(table_handler, ZarrGroupHandler):
42
+ return TablesContainer(table_handler)
43
+
44
+
45
+ def _default_label_container(handler: ZarrGroupHandler) -> LabelsContainer | None:
46
+ """Return a default label container."""
47
+ success, label_handler = handler.safe_derive_handler("labels")
48
+ if success and isinstance(label_handler, ZarrGroupHandler):
49
+ return LabelsContainer(label_handler)
50
+
51
+
52
+ class OmeZarrContainer:
53
+ """This class contains an OME-Zarr image and its associated tables and labels."""
54
+
55
+ _images_container: ImagesContainer
56
+ _labels_container: LabelsContainer | None
57
+ _tables_container: TablesContainer | None
58
+
59
+ def __init__(
60
+ self,
61
+ group_handler: ZarrGroupHandler,
62
+ table_container: TablesContainer | None = None,
63
+ label_container: LabelsContainer | None = None,
64
+ validate_arrays: bool = True,
65
+ ) -> None:
66
+ """Initialize the OmeZarrContainer."""
67
+ self._group_handler = group_handler
68
+ self._images_container = ImagesContainer(self._group_handler)
69
+
70
+ self._labels_container = label_container
71
+ self._tables_container = table_container
72
+
73
+ def __repr__(self) -> str:
74
+ """Return a string representation of the image."""
75
+ num_labels = len(self.list_labels())
76
+ num_tables = len(self.list_tables())
77
+
78
+ base_str = f"OmeZarrContainer(levels={self.levels}"
79
+ if num_labels > 0 and num_labels < 3:
80
+ base_str += f", labels={self.list_labels()}"
81
+ elif num_labels >= 3:
82
+ base_str += f", #labels={num_labels}"
83
+ if num_tables > 0 and num_tables < 3:
84
+ base_str += f", tables={self.list_tables()}"
85
+ elif num_tables >= 3:
86
+ base_str += f", #tables={num_tables}"
87
+ base_str += ")"
88
+ return base_str
89
+
90
+ @property
91
+ def images_container(self) -> ImagesContainer:
92
+ """Return the image container."""
93
+ return self._images_container
94
+
95
+ @property
96
+ def labels_container(self) -> LabelsContainer:
97
+ """Return the labels container."""
98
+ if self._labels_container is None:
99
+ self._labels_container = _default_label_container(self._group_handler)
100
+ if self._labels_container is None:
101
+ raise NgioValidationError("No labels found in the image.")
102
+ return self._labels_container
103
+
104
+ @property
105
+ def tables_container(self) -> TablesContainer:
106
+ """Return the tables container."""
107
+ if self._tables_container is None:
108
+ self._tables_container = _default_table_container(self._group_handler)
109
+ if self._tables_container is None:
110
+ raise NgioValidationError("No tables found in the image.")
111
+ return self._tables_container
112
+
113
+ @property
114
+ def image_meta(self) -> NgioImageMeta:
115
+ """Return the image metadata."""
116
+ return self._images_container.meta
117
+
118
+ @property
119
+ def levels(self) -> int:
120
+ """Return the number of levels in the image."""
121
+ return self._images_container.levels
122
+
123
+ @property
124
+ def levels_paths(self) -> list[str]:
125
+ """Return the paths of the levels in the image."""
126
+ return self._images_container.levels_paths
127
+
128
+ @property
129
+ def is_3d(self) -> bool:
130
+ """Return True if the image is 3D."""
131
+ return self.get_image().is_3d
132
+
133
+ @property
134
+ def is_2d(self) -> bool:
135
+ """Return True if the image is 2D."""
136
+ return self.get_image().is_2d
137
+
138
+ @property
139
+ def is_time_series(self) -> bool:
140
+ """Return True if the image is a time series."""
141
+ return self.get_image().is_time_series
142
+
143
+ @property
144
+ def is_2d_time_series(self) -> bool:
145
+ """Return True if the image is a 2D time series."""
146
+ return self.get_image().is_2d_time_series
147
+
148
+ @property
149
+ def is_3d_time_series(self) -> bool:
150
+ """Return True if the image is a 3D time series."""
151
+ return self.get_image().is_3d_time_series
152
+
153
+ @property
154
+ def is_multi_channels(self) -> bool:
155
+ """Return True if the image is multichannel."""
156
+ return self.get_image().is_multi_channels
157
+
158
+ def initialize_channel_meta(
159
+ self,
160
+ labels: Collection[str] | int | None = None,
161
+ wavelength_id: Collection[str] | None = None,
162
+ percentiles: tuple[float, float] | None = None,
163
+ colors: Collection[str] | None = None,
164
+ active: Collection[bool] | None = None,
165
+ **omero_kwargs: dict,
166
+ ) -> None:
167
+ """Create a ChannelsMeta object with the default unit."""
168
+ self._images_container.initialize_channel_meta(
169
+ labels=labels,
170
+ wavelength_id=wavelength_id,
171
+ percentiles=percentiles,
172
+ colors=colors,
173
+ active=active,
174
+ **omero_kwargs,
175
+ )
176
+
177
+ def update_percentiles(
178
+ self,
179
+ start_percentile: float = 0.1,
180
+ end_percentile: float = 99.9,
181
+ ) -> None:
182
+ """Update the percentiles of the image."""
183
+ self._images_container.update_percentiles(
184
+ start_percentile=start_percentile, end_percentile=end_percentile
185
+ )
186
+
187
+ def get_image(
188
+ self,
189
+ path: str | None = None,
190
+ pixel_size: PixelSize | None = None,
191
+ strict: bool = False,
192
+ ) -> Image:
193
+ """Get an image at a specific level.
194
+
195
+ Args:
196
+ path (str | None): The path to the image in the ome_zarr file.
197
+ pixel_size (PixelSize | None): The pixel size of the image.
198
+ strict (bool): Only used if the pixel size is provided. If True, the
199
+ pixel size must match the image pixel size exactly. If False, the
200
+ closest pixel size level will be returned.
201
+
202
+ """
203
+ return self._images_container.get(
204
+ path=path, pixel_size=pixel_size, strict=strict
205
+ )
206
+
207
+ def get_masked_image(
208
+ self,
209
+ masking_label_name: str,
210
+ masking_table_name: str | None = None,
211
+ path: str | None = None,
212
+ pixel_size: PixelSize | None = None,
213
+ strict: bool = False,
214
+ ) -> MaskedImage:
215
+ """Get a masked image at a specific level.
216
+
217
+ Args:
218
+ masking_label_name (str): The name of the label.
219
+ masking_table_name (str | None): The name of the masking table.
220
+ path (str | None): The path to the image in the ome_zarr file.
221
+ pixel_size (PixelSize | None): The pixel size of the image.
222
+ strict (bool): Only used if the pixel size is provided. If True, the
223
+ pixel size must match the image pixel size exactly. If False, the
224
+ closest pixel size level will be returned.
225
+ """
226
+ image = self.get_image(path=path, pixel_size=pixel_size, strict=strict)
227
+ masking_label = self.get_label(
228
+ name=masking_label_name, path=path, pixel_size=pixel_size, strict=strict
229
+ )
230
+ if masking_table_name is None:
231
+ masking_table = masking_label.build_masking_roi_table()
232
+ else:
233
+ masking_table = self.get_table(
234
+ masking_table_name, check_type="masking_roi_table"
235
+ )
236
+
237
+ return MaskedImage(
238
+ group_handler=image._group_handler,
239
+ path=masking_label.path,
240
+ meta_handler=image.meta_handler,
241
+ label=masking_label,
242
+ masking_roi_table=masking_table,
243
+ )
244
+
245
+ def derive_image(
246
+ self,
247
+ store: StoreOrGroup,
248
+ ref_path: str | None = None,
249
+ shape: Collection[int] | None = None,
250
+ labels: Collection[str] | None = None,
251
+ pixel_size: PixelSize | None = None,
252
+ axes_names: Collection[str] | None = None,
253
+ chunks: Collection[int] | None = None,
254
+ dtype: str | None = None,
255
+ copy_labels: bool = False,
256
+ copy_tables: bool = False,
257
+ overwrite: bool = False,
258
+ ) -> "OmeZarrContainer":
259
+ """Create an empty OME-Zarr container from an existing image.
260
+
261
+ Args:
262
+ store (StoreOrGroup): The Zarr store or group to create the image in.
263
+ ref_path (str | None): The path to the reference image in
264
+ the image container.
265
+ shape (Collection[int] | None): The shape of the new image.
266
+ labels (Collection[str] | None): The labels of the new image.
267
+ pixel_size (PixelSize | None): The pixel size of the new image.
268
+ axes_names (Collection[str] | None): The axes names of the new image.
269
+ chunks (Collection[int] | None): The chunk shape of the new image.
270
+ dtype (str | None): The data type of the new image.
271
+ copy_labels (bool): Whether to copy the labels from the reference image.
272
+ copy_tables (bool): Whether to copy the tables from the reference image.
273
+ overwrite (bool): Whether to overwrite an existing image.
274
+
275
+ Returns:
276
+ OmeZarrContainer: The new image container.
277
+
278
+ """
279
+ _ = self._images_container.derive(
280
+ store=store,
281
+ ref_path=ref_path,
282
+ shape=shape,
283
+ labels=labels,
284
+ pixel_size=pixel_size,
285
+ axes_names=axes_names,
286
+ chunks=chunks,
287
+ dtype=dtype,
288
+ overwrite=overwrite,
289
+ )
290
+
291
+ handler = ZarrGroupHandler(
292
+ store, cache=self._group_handler.use_cache, mode=self._group_handler.mode
293
+ )
294
+
295
+ new_ome_zarr = OmeZarrContainer(
296
+ group_handler=handler,
297
+ validate_arrays=False,
298
+ )
299
+
300
+ if copy_labels:
301
+ self.labels_container._group_handler.copy_handler(
302
+ new_ome_zarr.labels_container._group_handler
303
+ )
304
+
305
+ if copy_tables:
306
+ self.tables_container._group_handler.copy_handler(
307
+ new_ome_zarr.tables_container._group_handler
308
+ )
309
+ return new_ome_zarr
310
+
311
+ def list_tables(self) -> list[str]:
312
+ """List all tables in the image."""
313
+ return self.tables_container.list()
314
+
315
+ def list_roi_tables(self) -> list[str]:
316
+ """List all ROI tables in the image."""
317
+ return self.tables_container.list_roi_tables()
318
+
319
+ @overload
320
+ def get_table(self, name: str, check_type: None) -> Table: ...
321
+
322
+ @overload
323
+ def get_table(self, name: str, check_type: Literal["roi_table"]) -> RoiTable: ...
324
+
325
+ @overload
326
+ def get_table(
327
+ self, name: str, check_type: Literal["masking_roi_table"]
328
+ ) -> MaskingRoiTable: ...
329
+
330
+ @overload
331
+ def get_table(
332
+ self, name: str, check_type: Literal["feature_table"]
333
+ ) -> FeatureTable: ...
334
+
335
+ @overload
336
+ def get_table(
337
+ self, name: str, check_type: Literal["generic_roi_table"]
338
+ ) -> GenericRoiTable: ...
339
+
340
+ def get_table(self, name: str, check_type: TypedTable | None = None) -> Table:
341
+ """Get a table from the image."""
342
+ table = self.tables_container.get(name)
343
+ match check_type:
344
+ case "roi_table":
345
+ if not isinstance(table, RoiTable):
346
+ raise NgioValueError(
347
+ f"Table '{name}' is not a ROI table. Found type: {table.type()}"
348
+ )
349
+ return table
350
+ case "masking_roi_table":
351
+ if not isinstance(table, MaskingRoiTable):
352
+ raise NgioValueError(
353
+ f"Table '{name}' is not a masking ROI table. "
354
+ f"Found type: {table.type()}"
355
+ )
356
+ return table
357
+
358
+ case "generic_roi_table":
359
+ if not isinstance(table, GenericRoiTable):
360
+ raise NgioValueError(
361
+ f"Table '{name}' is not a generic ROI table. "
362
+ f"Found type: {table.type()}"
363
+ )
364
+ return table
365
+
366
+ case "feature_table":
367
+ if not isinstance(table, FeatureTable):
368
+ raise NgioValueError(
369
+ f"Table '{name}' is not a feature table. "
370
+ f"Found type: {table.type()}"
371
+ )
372
+ return table
373
+ case None:
374
+ return table
375
+ case _:
376
+ raise NgioValueError(f"Unknown check_type: {check_type}")
377
+
378
+ def build_image_roi_table(self, name: str = "image") -> RoiTable:
379
+ """Compute the ROI table for an image."""
380
+ return self.get_image().build_image_roi_table(name=name)
381
+
382
+ def build_masking_roi_table(self, label: str) -> MaskingRoiTable:
383
+ """Compute the masking ROI table for a label."""
384
+ return self.get_label(label).build_masking_roi_table()
385
+
386
+ def add_table(
387
+ self,
388
+ name: str,
389
+ table: Table,
390
+ backend: str | None = None,
391
+ overwrite: bool = False,
392
+ ) -> None:
393
+ """Add a table to the image."""
394
+ self.tables_container.add(
395
+ name=name, table=table, backend=backend, overwrite=overwrite
396
+ )
397
+
398
+ def list_labels(self) -> list[str]:
399
+ """List all labels in the image."""
400
+ return self.labels_container.list()
401
+
402
+ def get_label(
403
+ self,
404
+ name: str,
405
+ path: str | None = None,
406
+ pixel_size: PixelSize | None = None,
407
+ strict: bool = False,
408
+ ) -> Label:
409
+ """Get a label from the group.
410
+
411
+ Args:
412
+ name (str): The name of the label.
413
+ path (str | None): The path to the image in the ome_zarr file.
414
+ pixel_size (PixelSize | None): The pixel size of the image.
415
+ strict (bool): Only used if the pixel size is provided. If True, the
416
+ pixel size must match the image pixel size exactly. If False, the
417
+ closest pixel size level will be returned.
418
+ """
419
+ return self.labels_container.get(
420
+ name=name, path=path, pixel_size=pixel_size, strict=strict
421
+ )
422
+
423
+ def get_masked_label(
424
+ self,
425
+ label_name: str,
426
+ masking_label_name: str,
427
+ masking_table_name: str | None = None,
428
+ path: str | None = None,
429
+ pixel_size: PixelSize | None = None,
430
+ strict: bool = False,
431
+ ) -> MaskedLabel:
432
+ """Get a masked image at a specific level.
433
+
434
+ Args:
435
+ label_name (str): The name of the label.
436
+ masking_label_name (str): The name of the masking label.
437
+ masking_table_name (str | None): The name of the masking table.
438
+ path (str | None): The path to the image in the ome_zarr file.
439
+ pixel_size (PixelSize | None): The pixel size of the image.
440
+ strict (bool): Only used if the pixel size is provided. If True, the
441
+ pixel size must match the image pixel size exactly. If False, the
442
+ closest pixel size level will be returned.
443
+ """
444
+ label = self.get_label(
445
+ name=label_name, path=path, pixel_size=pixel_size, strict=strict
446
+ )
447
+ masking_label = self.get_label(
448
+ name=masking_label_name, path=path, pixel_size=pixel_size, strict=strict
449
+ )
450
+ if masking_table_name is None:
451
+ masking_table = masking_label.build_masking_roi_table()
452
+ else:
453
+ masking_table = self.get_table(
454
+ masking_table_name, check_type="masking_roi_table"
455
+ )
456
+
457
+ return MaskedLabel(
458
+ group_handler=label._group_handler,
459
+ path=label.path,
460
+ meta_handler=label.meta_handler,
461
+ label=masking_label,
462
+ masking_roi_table=masking_table,
463
+ )
464
+
465
+ def derive_label(
466
+ self,
467
+ name: str,
468
+ ref_image: Image | None = None,
469
+ shape: Collection[int] | None = None,
470
+ pixel_size: PixelSize | None = None,
471
+ axes_names: Collection[str] | None = None,
472
+ chunks: Collection[int] | None = None,
473
+ dtype: str | None = None,
474
+ overwrite: bool = False,
475
+ ) -> "Label":
476
+ """Create an empty OME-Zarr label from a reference image.
477
+
478
+ And add the label to the /labels group.
479
+
480
+ Args:
481
+ store (StoreOrGroup): The Zarr store or group to create the image in.
482
+ ref_image (Image): The reference image.
483
+ name (str): The name of the new image.
484
+ shape (Collection[int] | None): The shape of the new image.
485
+ pixel_size (PixelSize | None): The pixel size of the new image.
486
+ axes_names (Collection[str] | None): The axes names of the new image.
487
+ For labels, the channel axis is not allowed.
488
+ chunks (Collection[int] | None): The chunk shape of the new image.
489
+ dtype (str | None): The data type of the new image.
490
+ overwrite (bool): Whether to overwrite an existing image.
491
+
492
+ Returns:
493
+ Label: The new label.
494
+
495
+ """
496
+ if ref_image is None:
497
+ ref_image = self.get_image()
498
+ return self.labels_container.derive(
499
+ name=name,
500
+ ref_image=ref_image,
501
+ shape=shape,
502
+ pixel_size=pixel_size,
503
+ axes_names=axes_names,
504
+ chunks=chunks,
505
+ dtype=dtype,
506
+ overwrite=overwrite,
507
+ )
508
+
509
+
510
+ def open_ome_zarr_container(
511
+ store: StoreOrGroup,
512
+ cache: bool = False,
513
+ mode: AccessModeLiteral = "r+",
514
+ validate_arrays: bool = True,
515
+ ) -> OmeZarrContainer:
516
+ """Open an OME-Zarr image."""
517
+ handler = ZarrGroupHandler(store=store, cache=cache, mode=mode)
518
+ return OmeZarrContainer(
519
+ group_handler=handler,
520
+ validate_arrays=validate_arrays,
521
+ )
522
+
523
+
524
+ def open_image(
525
+ store: StoreOrGroup,
526
+ path: str | None = None,
527
+ pixel_size: PixelSize | None = None,
528
+ strict: bool = True,
529
+ cache: bool = False,
530
+ mode: AccessModeLiteral = "r+",
531
+ ) -> Image:
532
+ """Open a single level image from an OME-Zarr image.
533
+
534
+ Args:
535
+ store (StoreOrGroup): The Zarr store or group to create the image in.
536
+ path (str | None): The path to the image in the ome_zarr file.
537
+ pixel_size (PixelSize | None): The pixel size of the image.
538
+ strict (bool): Only used if the pixel size is provided. If True, the
539
+ pixel size must match the image pixel size exactly. If False, the
540
+ closest pixel size level will be returned.
541
+ cache (bool): Whether to use a cache for the zarr group metadata.
542
+ mode (AccessModeLiteral): The
543
+ access mode for the image. Defaults to "r+".
544
+ """
545
+ group_handler = ZarrGroupHandler(store, cache, mode)
546
+ images_container = ImagesContainer(group_handler)
547
+ return images_container.get(
548
+ path=path,
549
+ pixel_size=pixel_size,
550
+ strict=strict,
551
+ )
552
+
553
+
554
+ def create_empty_ome_zarr(
555
+ store: StoreOrGroup,
556
+ shape: Collection[int],
557
+ xy_pixelsize: float,
558
+ z_spacing: float = 1.0,
559
+ time_spacing: float = 1.0,
560
+ levels: int | list[str] = 5,
561
+ xy_scaling_factor: float = 2,
562
+ z_scaling_factor: float = 1.0,
563
+ space_unit: SpaceUnits | str | None = None,
564
+ time_unit: TimeUnits | str | None = None,
565
+ axes_names: Collection[str] | None = None,
566
+ name: str | None = None,
567
+ chunks: Collection[int] | None = None,
568
+ dtype: str = "uint16",
569
+ channel_labels: list[str] | None = None,
570
+ channel_wavelengths: list[str] | None = None,
571
+ percentiles: tuple[float, float] | None = None,
572
+ channel_colors: Collection[str] | None = None,
573
+ channel_active: Collection[bool] | None = None,
574
+ overwrite: bool = False,
575
+ version: str = "0.4",
576
+ ) -> OmeZarrContainer:
577
+ """Create an empty OME-Zarr image with the given shape and metadata.
578
+
579
+ Args:
580
+ store (StoreOrGroup): The Zarr store or group to create the image in.
581
+ shape (Collection[int]): The shape of the image.
582
+ xy_pixelsize (float): The pixel size in x and y dimensions.
583
+ z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
584
+ time_spacing (float, optional): The spacing between time points.
585
+ Defaults to 1.0.
586
+ levels (int | list[str], optional): The number of levels in the pyramid or a
587
+ list of level names. Defaults to 5.
588
+ xy_scaling_factor (float, optional): The down-scaling factor in x and y
589
+ dimensions. Defaults to 2.0.
590
+ z_scaling_factor (float, optional): The down-scaling factor in z dimension.
591
+ Defaults to 1.0.
592
+ space_unit (SpaceUnits | str | None, optional): The unit of space. Defaults to
593
+ None.
594
+ time_unit (TimeUnits | str | None, optional): The unit of time. Defaults to
595
+ None.
596
+ axes_names (Collection[str] | None, optional): The names of the axes.
597
+ If None the canonical names are used. Defaults to None.
598
+ name (str | None, optional): The name of the image. Defaults to None.
599
+ chunks (Collection[int] | None, optional): The chunk shape. If None the shape
600
+ is used. Defaults to None.
601
+ dtype (str, optional): The data type of the image. Defaults to "uint16".
602
+ channel_labels (list[str] | None, optional): The labels of the channels.
603
+ Defaults to None.
604
+ channel_wavelengths (list[str] | None, optional): The wavelengths of the
605
+ channels. Defaults to None.
606
+ percentiles (tuple[float, float] | None, optional): The percentiles of the
607
+ channels. Defaults to None.
608
+ channel_colors (Collection[str] | None, optional): The colors of the channels.
609
+ Defaults to None.
610
+ channel_active (Collection[bool] | None, optional): Whether the channels are
611
+ active. Defaults to None.
612
+ overwrite (bool, optional): Whether to overwrite an existing image.
613
+ Defaults to True.
614
+ version (str, optional): The version of the OME-Zarr specification.
615
+ Defaults to "0.4".
616
+ """
617
+ handler = _create_empty_image(
618
+ store=store,
619
+ shape=shape,
620
+ pixelsize=xy_pixelsize,
621
+ z_spacing=z_spacing,
622
+ time_spacing=time_spacing,
623
+ levels=levels,
624
+ yx_scaling_factor=xy_scaling_factor,
625
+ z_scaling_factor=z_scaling_factor,
626
+ space_unit=space_unit,
627
+ time_unit=time_unit,
628
+ axes_names=axes_names,
629
+ name=name,
630
+ chunks=chunks,
631
+ dtype=dtype,
632
+ overwrite=overwrite,
633
+ version=version,
634
+ )
635
+
636
+ ome_zarr = OmeZarrContainer(group_handler=handler)
637
+ ome_zarr.initialize_channel_meta(
638
+ labels=channel_labels,
639
+ wavelength_id=channel_wavelengths,
640
+ percentiles=percentiles,
641
+ colors=channel_colors,
642
+ active=channel_active,
643
+ )
644
+ return ome_zarr
645
+
646
+
647
+ def create_ome_zarr_from_array(
648
+ store: StoreOrGroup,
649
+ array: np.ndarray,
650
+ xy_pixelsize: float,
651
+ z_spacing: float = 1.0,
652
+ time_spacing: float = 1.0,
653
+ levels: int | list[str] = 5,
654
+ xy_scaling_factor: float = 2.0,
655
+ z_scaling_factor: float = 1.0,
656
+ space_unit: SpaceUnits | str | None = None,
657
+ time_unit: TimeUnits | str | None = None,
658
+ axes_names: Collection[str] | None = None,
659
+ channel_labels: list[str] | None = None,
660
+ channel_wavelengths: list[str] | None = None,
661
+ percentiles: tuple[float, float] | None = (0.1, 99.9),
662
+ channel_colors: Collection[str] | None = None,
663
+ channel_active: Collection[bool] | None = None,
664
+ name: str | None = None,
665
+ chunks: Collection[int] | None = None,
666
+ overwrite: bool = False,
667
+ version: str = "0.4",
668
+ ) -> OmeZarrContainer:
669
+ """Create an OME-Zarr image from a numpy array.
670
+
671
+ Args:
672
+ store (StoreOrGroup): The Zarr store or group to create the image in.
673
+ array (np.ndarray): The image data.
674
+ xy_pixelsize (float): The pixel size in x and y dimensions.
675
+ z_spacing (float, optional): The spacing between z slices. Defaults to 1.0.
676
+ time_spacing (float, optional): The spacing between time points.
677
+ Defaults to 1.0.
678
+ levels (int | list[str], optional): The number of levels in the pyramid or a
679
+ list of level names. Defaults to 5.
680
+ xy_scaling_factor (float, optional): The down-scaling factor in x and y
681
+ dimensions. Defaults to 2.0.
682
+ z_scaling_factor (float, optional): The down-scaling factor in z dimension.
683
+ Defaults to 1.0.
684
+ space_unit (SpaceUnits | str | None, optional): The unit of space. Defaults to
685
+ None.
686
+ time_unit (TimeUnits | str | None, optional): The unit of time. Defaults to
687
+ None.
688
+ axes_names (Collection[str] | None, optional): The names of the axes.
689
+ If None the canonical names are used. Defaults to None.
690
+ name (str | None, optional): The name of the image. Defaults to None.
691
+ chunks (Collection[int] | None, optional): The chunk shape. If None the shape
692
+ is used. Defaults to None.
693
+ channel_labels (list[str] | None, optional): The labels of the channels.
694
+ Defaults to None.
695
+ channel_wavelengths (list[str] | None, optional): The wavelengths of the
696
+ channels. Defaults to None.
697
+ percentiles (tuple[float, float] | None, optional): The percentiles of the
698
+ channels. Defaults to None.
699
+ channel_colors (Collection[str] | None, optional): The colors of the channels.
700
+ Defaults to None.
701
+ channel_active (Collection[bool] | None, optional): Whether the channels are
702
+ active. Defaults to None.
703
+ overwrite (bool, optional): Whether to overwrite an existing image.
704
+ Defaults to True.
705
+ version (str, optional): The version of the OME-Zarr specification.
706
+ Defaults to "0.4".
707
+ """
708
+ handler = _create_empty_image(
709
+ store=store,
710
+ shape=array.shape,
711
+ pixelsize=xy_pixelsize,
712
+ z_spacing=z_spacing,
713
+ time_spacing=time_spacing,
714
+ levels=levels,
715
+ yx_scaling_factor=xy_scaling_factor,
716
+ z_scaling_factor=z_scaling_factor,
717
+ space_unit=space_unit,
718
+ time_unit=time_unit,
719
+ axes_names=axes_names,
720
+ name=name,
721
+ chunks=chunks,
722
+ dtype=array.dtype,
723
+ overwrite=overwrite,
724
+ version=version,
725
+ )
726
+
727
+ ome_zarr = OmeZarrContainer(group_handler=handler)
728
+ image = ome_zarr.get_image()
729
+ image.set_array(array)
730
+ image.consolidate()
731
+ ome_zarr.initialize_channel_meta(
732
+ labels=channel_labels,
733
+ wavelength_id=channel_wavelengths,
734
+ percentiles=percentiles,
735
+ colors=channel_colors,
736
+ active=channel_active,
737
+ )
738
+ return ome_zarr