ngio 0.2.0a2__py3-none-any.whl → 0.5.0b4__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 +40 -12
- ngio/common/__init__.py +16 -32
- ngio/common/_dimensions.py +270 -48
- ngio/common/_masking_roi.py +153 -0
- ngio/common/_pyramid.py +267 -73
- ngio/common/_roi.py +290 -66
- ngio/common/_synt_images_utils.py +101 -0
- ngio/common/_zoom.py +54 -22
- ngio/experimental/__init__.py +5 -0
- ngio/experimental/iterators/__init__.py +15 -0
- ngio/experimental/iterators/_abstract_iterator.py +390 -0
- ngio/experimental/iterators/_feature.py +189 -0
- ngio/experimental/iterators/_image_processing.py +130 -0
- ngio/experimental/iterators/_mappers.py +48 -0
- ngio/experimental/iterators/_rois_utils.py +126 -0
- ngio/experimental/iterators/_segmentation.py +235 -0
- ngio/hcs/__init__.py +17 -58
- ngio/hcs/_plate.py +1354 -0
- ngio/images/__init__.py +30 -9
- ngio/images/_abstract_image.py +968 -0
- ngio/images/_create_synt_container.py +132 -0
- ngio/images/_create_utils.py +423 -0
- ngio/images/_image.py +926 -0
- ngio/images/_label.py +417 -0
- ngio/images/_masked_image.py +531 -0
- ngio/images/_ome_zarr_container.py +1235 -0
- ngio/images/_table_ops.py +471 -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 +146 -0
- ngio/io_pipes/_io_pipes_types.py +56 -0
- ngio/io_pipes/_match_shape.py +377 -0
- ngio/io_pipes/_ops_axes.py +344 -0
- ngio/io_pipes/_ops_slices.py +411 -0
- ngio/io_pipes/_ops_slices_utils.py +199 -0
- ngio/io_pipes/_ops_transforms.py +104 -0
- ngio/io_pipes/_zoom_transform.py +180 -0
- ngio/ome_zarr_meta/__init__.py +39 -15
- ngio/ome_zarr_meta/_meta_handlers.py +490 -96
- ngio/ome_zarr_meta/ngio_specs/__init__.py +24 -10
- ngio/ome_zarr_meta/ngio_specs/_axes.py +268 -234
- ngio/ome_zarr_meta/ngio_specs/_channels.py +125 -41
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +42 -87
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +536 -2
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +202 -198
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +72 -34
- ngio/ome_zarr_meta/v04/__init__.py +21 -5
- ngio/ome_zarr_meta/v04/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v04/{_v04_spec_utils.py → _v04_spec.py} +151 -90
- ngio/ome_zarr_meta/v05/__init__.py +27 -0
- ngio/ome_zarr_meta/v05/_custom_models.py +18 -0
- ngio/ome_zarr_meta/v05/_v05_spec.py +511 -0
- 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 +55 -0
- ngio/resources/resource_model.py +36 -0
- ngio/tables/__init__.py +20 -4
- ngio/tables/_abstract_table.py +270 -0
- ngio/tables/_tables_container.py +449 -0
- ngio/tables/backends/__init__.py +50 -1
- ngio/tables/backends/_abstract_backend.py +200 -31
- ngio/tables/backends/_anndata.py +139 -0
- ngio/tables/backends/_anndata_utils.py +10 -114
- ngio/tables/backends/_csv.py +19 -0
- ngio/tables/backends/_json.py +92 -0
- ngio/tables/backends/_parquet.py +19 -0
- ngio/tables/backends/_py_arrow_backends.py +222 -0
- ngio/tables/backends/_table_backends.py +162 -38
- ngio/tables/backends/_utils.py +608 -0
- ngio/tables/v1/__init__.py +19 -4
- ngio/tables/v1/_condition_table.py +71 -0
- ngio/tables/v1/_feature_table.py +79 -115
- ngio/tables/v1/_generic_table.py +21 -90
- ngio/tables/v1/_roi_table.py +486 -137
- ngio/transforms/__init__.py +5 -0
- ngio/transforms/_zoom.py +19 -0
- ngio/utils/__init__.py +16 -14
- ngio/utils/_cache.py +48 -0
- ngio/utils/_datasets.py +121 -13
- ngio/utils/_fractal_fsspec_store.py +42 -0
- ngio/utils/_zarr_utils.py +374 -218
- ngio-0.5.0b4.dist-info/METADATA +147 -0
- ngio-0.5.0b4.dist-info/RECORD +88 -0
- {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/WHEEL +1 -1
- ngio/common/_array_pipe.py +0 -160
- ngio/common/_axes_transforms.py +0 -63
- ngio/common/_common_types.py +0 -5
- ngio/common/_slicer.py +0 -97
- ngio/images/abstract_image.py +0 -240
- ngio/images/create.py +0 -251
- ngio/images/image.py +0 -389
- ngio/images/label.py +0 -236
- ngio/images/omezarr_container.py +0 -535
- ngio/ome_zarr_meta/_generic_handlers.py +0 -320
- ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
- ngio/tables/_validators.py +0 -192
- ngio/tables/backends/_anndata_v1.py +0 -75
- ngio/tables/backends/_json_v1.py +0 -56
- ngio/tables/tables_container.py +0 -300
- ngio/tables/v1/_masking_roi_table.py +0 -175
- ngio/utils/_logger.py +0 -29
- ngio-0.2.0a2.dist-info/METADATA +0 -95
- ngio-0.2.0a2.dist-info/RECORD +0 -53
- {ngio-0.2.0a2.dist-info → ngio-0.5.0b4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Abstract class for handling OME-NGFF images."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping, Sequence
|
|
4
|
+
from typing import Any, Literal
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import PIL.Image
|
|
8
|
+
from zarr.core.array import CompressorLike
|
|
9
|
+
|
|
10
|
+
from ngio.common._pyramid import ChunksLike, ShardsLike
|
|
11
|
+
from ngio.common._synt_images_utils import fit_to_shape
|
|
12
|
+
from ngio.images._ome_zarr_container import OmeZarrContainer, create_ome_zarr_from_array
|
|
13
|
+
from ngio.ome_zarr_meta.ngio_specs import (
|
|
14
|
+
Channel,
|
|
15
|
+
DefaultNgffVersion,
|
|
16
|
+
NgffVersions,
|
|
17
|
+
)
|
|
18
|
+
from ngio.resources import AVAILABLE_SAMPLES, SampleInfo, get_sample_info
|
|
19
|
+
from ngio.tables import (
|
|
20
|
+
DefaultTableBackend,
|
|
21
|
+
TableBackend,
|
|
22
|
+
)
|
|
23
|
+
from ngio.utils import (
|
|
24
|
+
StoreOrGroup,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def create_synthetic_ome_zarr(
|
|
29
|
+
store: StoreOrGroup,
|
|
30
|
+
shape: Sequence[int],
|
|
31
|
+
reference_sample: AVAILABLE_SAMPLES | SampleInfo = "Cardiomyocyte",
|
|
32
|
+
levels: int | list[str] = 5,
|
|
33
|
+
table_backend: TableBackend = DefaultTableBackend,
|
|
34
|
+
scaling_factors: Sequence[float] | Literal["auto"] = "auto",
|
|
35
|
+
axes_names: Sequence[str] | None = None,
|
|
36
|
+
channels_meta: Sequence[str | Channel] | None = None,
|
|
37
|
+
ngff_version: NgffVersions = DefaultNgffVersion,
|
|
38
|
+
chunks: ChunksLike = "auto",
|
|
39
|
+
shards: ShardsLike | None = None,
|
|
40
|
+
dimension_separator: Literal[".", "/"] = "/",
|
|
41
|
+
compressors: CompressorLike = "auto",
|
|
42
|
+
extra_array_kwargs: Mapping[str, Any] | None = None,
|
|
43
|
+
overwrite: bool = False,
|
|
44
|
+
) -> OmeZarrContainer:
|
|
45
|
+
"""Create a synthetic OME-Zarr image with the given shape and metadata.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
49
|
+
shape (Sequence[int]): The shape of the image.
|
|
50
|
+
reference_sample (AVAILABLE_SAMPLES | SampleInfo): The reference sample to use.
|
|
51
|
+
Defaults to "Cardiomyocyte".
|
|
52
|
+
levels (int | list[str]): The number of levels in the pyramid or a list of
|
|
53
|
+
level names. Defaults to 5.
|
|
54
|
+
table_backend (TableBackend): Table backend to be used to store tables.
|
|
55
|
+
Defaults to DefaultTableBackend.
|
|
56
|
+
scaling_factors (Sequence[float] | Literal["auto"]): The down-scaling factors
|
|
57
|
+
for the pyramid levels. Defaults to "auto".
|
|
58
|
+
axes_names (Sequence[str] | None): The names of the axes. If None the
|
|
59
|
+
canonical names are used. Defaults to None.
|
|
60
|
+
channels_meta (Sequence[str | Channel] | None): The channels metadata.
|
|
61
|
+
Defaults to None.
|
|
62
|
+
ngff_version (NgffVersions): The version of the OME-Zarr specification.
|
|
63
|
+
Defaults to DefaultNgffVersion.
|
|
64
|
+
chunks (ChunksLike): The chunk shape. Defaults to "auto".
|
|
65
|
+
shards (ShardsLike | None): The shard shape. Defaults to None.
|
|
66
|
+
dimension_separator (Literal[".", "/"]): The separator to use for
|
|
67
|
+
dimensions. Defaults to "/".
|
|
68
|
+
compressors (CompressorLike): The compressors to use. Defaults to "auto".
|
|
69
|
+
extra_array_kwargs (Mapping[str, Any] | None): Extra arguments to pass to
|
|
70
|
+
the zarr array creation. Defaults to None.
|
|
71
|
+
overwrite (bool): Whether to overwrite an existing image. Defaults to False.
|
|
72
|
+
"""
|
|
73
|
+
if isinstance(reference_sample, str):
|
|
74
|
+
sample_info = get_sample_info(reference_sample)
|
|
75
|
+
else:
|
|
76
|
+
sample_info = reference_sample
|
|
77
|
+
|
|
78
|
+
raw = np.asarray(PIL.Image.open(sample_info.img_path))
|
|
79
|
+
raw = fit_to_shape(arr=raw, out_shape=tuple(shape))
|
|
80
|
+
raw = raw / np.max(raw) * (2**16 - 1)
|
|
81
|
+
raw = raw.astype(np.uint16)
|
|
82
|
+
ome_zarr = create_ome_zarr_from_array(
|
|
83
|
+
store=store,
|
|
84
|
+
array=raw,
|
|
85
|
+
pixelsize=sample_info.xy_pixelsize,
|
|
86
|
+
z_spacing=sample_info.z_spacing,
|
|
87
|
+
time_spacing=sample_info.time_spacing,
|
|
88
|
+
levels=levels,
|
|
89
|
+
space_unit=sample_info.space_unit,
|
|
90
|
+
time_unit=sample_info.time_unit,
|
|
91
|
+
axes_names=axes_names,
|
|
92
|
+
channels_meta=channels_meta,
|
|
93
|
+
scaling_factors=scaling_factors,
|
|
94
|
+
extra_array_kwargs=extra_array_kwargs,
|
|
95
|
+
name=sample_info.name,
|
|
96
|
+
chunks=chunks,
|
|
97
|
+
shards=shards,
|
|
98
|
+
overwrite=overwrite,
|
|
99
|
+
dimension_separator=dimension_separator,
|
|
100
|
+
compressors=compressors,
|
|
101
|
+
ngff_version=ngff_version,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
image = ome_zarr.get_image()
|
|
105
|
+
well_table = image.build_image_roi_table()
|
|
106
|
+
ome_zarr.add_table("well_ROI_table", table=well_table, backend=table_backend)
|
|
107
|
+
|
|
108
|
+
for label_info in sample_info.labels:
|
|
109
|
+
ome_zarr.derive_label(name=label_info.name)
|
|
110
|
+
label = ome_zarr.get_label(name=label_info.name)
|
|
111
|
+
|
|
112
|
+
ref_label = np.asarray(PIL.Image.open(label_info.label_path))
|
|
113
|
+
ref_label = ref_label.astype(label_info.dtype)
|
|
114
|
+
|
|
115
|
+
ref_label = fit_to_shape(
|
|
116
|
+
arr=ref_label,
|
|
117
|
+
out_shape=label.shape,
|
|
118
|
+
ensure_unique_info=label_info.ensure_unique_labels,
|
|
119
|
+
)
|
|
120
|
+
ref_label = ref_label.astype(np.uint32)
|
|
121
|
+
label.set_array(ref_label)
|
|
122
|
+
label.consolidate()
|
|
123
|
+
|
|
124
|
+
if label_info.create_masking_table:
|
|
125
|
+
masking_table = label.build_masking_roi_table()
|
|
126
|
+
ome_zarr.add_table(
|
|
127
|
+
name=f"{label_info.name}_masking_table",
|
|
128
|
+
table=masking_table,
|
|
129
|
+
backend=table_backend,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
return ome_zarr
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Utility functions for working with OME-Zarr images."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from collections.abc import Mapping, Sequence
|
|
5
|
+
from typing import Any, Literal, TypeVar
|
|
6
|
+
|
|
7
|
+
from zarr.core.array import CompressorLike
|
|
8
|
+
|
|
9
|
+
from ngio.common._pyramid import ChunksLike, ImagePyramidBuilder, ShardsLike
|
|
10
|
+
from ngio.ome_zarr_meta import (
|
|
11
|
+
NgioImageMeta,
|
|
12
|
+
NgioLabelMeta,
|
|
13
|
+
update_ngio_meta,
|
|
14
|
+
)
|
|
15
|
+
from ngio.ome_zarr_meta.ngio_specs import (
|
|
16
|
+
AxesHandler,
|
|
17
|
+
Channel,
|
|
18
|
+
ChannelsMeta,
|
|
19
|
+
DefaultNgffVersion,
|
|
20
|
+
DefaultSpaceUnit,
|
|
21
|
+
DefaultTimeUnit,
|
|
22
|
+
NgffVersions,
|
|
23
|
+
SpaceUnits,
|
|
24
|
+
TimeUnits,
|
|
25
|
+
build_canonical_axes_handler,
|
|
26
|
+
canonical_axes_order,
|
|
27
|
+
canonical_label_axes_order,
|
|
28
|
+
)
|
|
29
|
+
from ngio.ome_zarr_meta.ngio_specs._axes import AxesSetup
|
|
30
|
+
from ngio.utils import NgioValueError, StoreOrGroup, ZarrGroupHandler
|
|
31
|
+
|
|
32
|
+
_image_or_label_meta = TypeVar("_image_or_label_meta", NgioImageMeta, NgioLabelMeta)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _build_axes_handler(
|
|
36
|
+
*,
|
|
37
|
+
shape: tuple[int, ...],
|
|
38
|
+
axes_names: Sequence[str] | None,
|
|
39
|
+
default_channel_order: tuple[str, ...],
|
|
40
|
+
space_units: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
41
|
+
time_units: TimeUnits | str | None = DefaultTimeUnit,
|
|
42
|
+
axes_setup: AxesSetup | None = None,
|
|
43
|
+
allow_non_canonical_axes: bool = False,
|
|
44
|
+
strict_canonical_order: bool = False,
|
|
45
|
+
) -> AxesHandler:
|
|
46
|
+
"""Compute axes names for given shape."""
|
|
47
|
+
if axes_names is None:
|
|
48
|
+
axes_names = default_channel_order[-len(shape) :]
|
|
49
|
+
# Validate length
|
|
50
|
+
if len(axes_names) != len(shape):
|
|
51
|
+
raise NgioValueError(
|
|
52
|
+
f"Number of axes names {axes_names} does not match the number of "
|
|
53
|
+
f"dimensions {shape}."
|
|
54
|
+
)
|
|
55
|
+
return build_canonical_axes_handler(
|
|
56
|
+
axes_names=axes_names,
|
|
57
|
+
space_units=space_units,
|
|
58
|
+
time_units=time_units,
|
|
59
|
+
axes_setup=axes_setup,
|
|
60
|
+
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
61
|
+
strict_canonical_order=strict_canonical_order,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _align_to_axes(
|
|
66
|
+
*,
|
|
67
|
+
values: dict[str, float],
|
|
68
|
+
axes_handler: AxesHandler,
|
|
69
|
+
default_value: float = 1.0,
|
|
70
|
+
) -> tuple[float, ...]:
|
|
71
|
+
"""Align given values to axes names."""
|
|
72
|
+
aligned_values = [default_value] * len(axes_handler.axes_names)
|
|
73
|
+
for ax, value in values.items():
|
|
74
|
+
index = axes_handler.get_index(ax)
|
|
75
|
+
if index is not None:
|
|
76
|
+
aligned_values[index] = value
|
|
77
|
+
return tuple(aligned_values)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _check_deprecated_scaling_factors(
|
|
81
|
+
*,
|
|
82
|
+
yx_scaling_factor: float | tuple[float, float] | None = None,
|
|
83
|
+
z_scaling_factor: float | None = None,
|
|
84
|
+
scaling_factors: Sequence[float] | Literal["auto"] = "auto",
|
|
85
|
+
shape: tuple[int, ...],
|
|
86
|
+
) -> Sequence[float] | Literal["auto"]:
|
|
87
|
+
if yx_scaling_factor is not None or z_scaling_factor is not None:
|
|
88
|
+
warnings.warn(
|
|
89
|
+
"The 'yx_scaling_factor' and 'z_scaling_factor' arguments are deprecated "
|
|
90
|
+
"and will be removed in future versions. Please use the 'scaling_factors' "
|
|
91
|
+
"argument instead.",
|
|
92
|
+
DeprecationWarning,
|
|
93
|
+
stacklevel=2,
|
|
94
|
+
)
|
|
95
|
+
if scaling_factors != "auto":
|
|
96
|
+
raise NgioValueError(
|
|
97
|
+
"Cannot use both 'scaling_factors' and deprecated "
|
|
98
|
+
"'yx_scaling_factor'/'z_scaling_factor' arguments."
|
|
99
|
+
)
|
|
100
|
+
if isinstance(yx_scaling_factor, tuple):
|
|
101
|
+
if len(yx_scaling_factor) != 2:
|
|
102
|
+
raise NgioValueError(
|
|
103
|
+
"yx_scaling_factor tuple must have length 2 for y and x scaling."
|
|
104
|
+
)
|
|
105
|
+
y_scale = yx_scaling_factor[0]
|
|
106
|
+
x_scale = yx_scaling_factor[1]
|
|
107
|
+
else:
|
|
108
|
+
y_scale = yx_scaling_factor if yx_scaling_factor is not None else 2.0
|
|
109
|
+
x_scale = yx_scaling_factor if yx_scaling_factor is not None else 2.0
|
|
110
|
+
z_scale = z_scaling_factor if z_scaling_factor is not None else 1.0
|
|
111
|
+
scaling_factors = (z_scale, x_scale, y_scale)
|
|
112
|
+
if len(scaling_factors) < len(shape):
|
|
113
|
+
padding = (1.0,) * (len(shape) - len(scaling_factors))
|
|
114
|
+
scaling_factors = padding + scaling_factors
|
|
115
|
+
|
|
116
|
+
return scaling_factors
|
|
117
|
+
return scaling_factors
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _compute_scaling_factors(
|
|
121
|
+
*,
|
|
122
|
+
scaling_factors: Sequence[float] | Literal["auto"],
|
|
123
|
+
shape: tuple[int, ...],
|
|
124
|
+
axes_handler: AxesHandler,
|
|
125
|
+
xy_scaling_factor: float | tuple[float, float] | None = None,
|
|
126
|
+
z_scaling_factor: float | None = None,
|
|
127
|
+
) -> tuple[float, ...]:
|
|
128
|
+
"""Compute scaling factors for given axes names."""
|
|
129
|
+
# TODO remove with ngio 0.6
|
|
130
|
+
scaling_factors = _check_deprecated_scaling_factors(
|
|
131
|
+
yx_scaling_factor=xy_scaling_factor,
|
|
132
|
+
z_scaling_factor=z_scaling_factor,
|
|
133
|
+
scaling_factors=scaling_factors,
|
|
134
|
+
shape=shape,
|
|
135
|
+
)
|
|
136
|
+
if scaling_factors == "auto":
|
|
137
|
+
return _align_to_axes(
|
|
138
|
+
values={
|
|
139
|
+
"x": 2.0,
|
|
140
|
+
"y": 2.0,
|
|
141
|
+
"z": 1.0,
|
|
142
|
+
},
|
|
143
|
+
axes_handler=axes_handler,
|
|
144
|
+
)
|
|
145
|
+
if len(scaling_factors) != len(shape):
|
|
146
|
+
raise NgioValueError(
|
|
147
|
+
"Length of scaling_factors does not match the number of dimensions."
|
|
148
|
+
)
|
|
149
|
+
return tuple(scaling_factors)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _compute_base_scale(
|
|
153
|
+
*,
|
|
154
|
+
pixelsize: float | tuple[float, float],
|
|
155
|
+
z_spacing: float,
|
|
156
|
+
time_spacing: float,
|
|
157
|
+
axes_handler: AxesHandler,
|
|
158
|
+
) -> tuple[float, ...]:
|
|
159
|
+
"""Compute base scale for given axes names."""
|
|
160
|
+
if isinstance(pixelsize, tuple):
|
|
161
|
+
if len(pixelsize) != 2:
|
|
162
|
+
raise NgioValueError(
|
|
163
|
+
"pixelsize tuple must have length 2 for y and x pixel sizes."
|
|
164
|
+
)
|
|
165
|
+
x_size = pixelsize[1]
|
|
166
|
+
y_size = pixelsize[0]
|
|
167
|
+
else:
|
|
168
|
+
x_size = pixelsize
|
|
169
|
+
y_size = pixelsize
|
|
170
|
+
return _align_to_axes(
|
|
171
|
+
values={
|
|
172
|
+
"x": x_size,
|
|
173
|
+
"y": y_size,
|
|
174
|
+
"z": z_spacing,
|
|
175
|
+
"t": time_spacing,
|
|
176
|
+
},
|
|
177
|
+
axes_handler=axes_handler,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _create_image_like_group(
|
|
182
|
+
*,
|
|
183
|
+
store: StoreOrGroup,
|
|
184
|
+
pyramid_builder: ImagePyramidBuilder,
|
|
185
|
+
meta: _image_or_label_meta,
|
|
186
|
+
overwrite: bool = False,
|
|
187
|
+
) -> ZarrGroupHandler:
|
|
188
|
+
"""Advanced create empty image container function placeholder."""
|
|
189
|
+
mode = "w" if overwrite else "w-"
|
|
190
|
+
group_handler = ZarrGroupHandler(
|
|
191
|
+
store=store, mode=mode, cache=False, zarr_format=meta.zarr_format
|
|
192
|
+
)
|
|
193
|
+
update_ngio_meta(group_handler, meta)
|
|
194
|
+
# Reopen in r+ mode
|
|
195
|
+
group_handler = group_handler.reopen_handler()
|
|
196
|
+
# Write the pyramid
|
|
197
|
+
pyramid_builder.to_zarr(group=group_handler.group)
|
|
198
|
+
return group_handler
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _add_channels_meta(
|
|
202
|
+
*,
|
|
203
|
+
meta: _image_or_label_meta,
|
|
204
|
+
channels_meta: Sequence[str | Channel] | None = None,
|
|
205
|
+
) -> _image_or_label_meta:
|
|
206
|
+
"""Create ChannelsMeta from given channels_meta input."""
|
|
207
|
+
if isinstance(meta, NgioLabelMeta):
|
|
208
|
+
if channels_meta is not None:
|
|
209
|
+
raise NgioValueError(
|
|
210
|
+
"Cannot add channels_meta to NgioLabelMeta. "
|
|
211
|
+
"Labels do not have channels."
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
return meta
|
|
215
|
+
if channels_meta is None:
|
|
216
|
+
return meta
|
|
217
|
+
list_of_channels = []
|
|
218
|
+
for c in channels_meta:
|
|
219
|
+
if isinstance(c, str):
|
|
220
|
+
channel = Channel.default_init(label=c)
|
|
221
|
+
elif isinstance(c, Channel):
|
|
222
|
+
channel = c
|
|
223
|
+
else:
|
|
224
|
+
raise NgioValueError(
|
|
225
|
+
"channels_meta must be a list of strings or Channel objects."
|
|
226
|
+
)
|
|
227
|
+
list_of_channels.append(channel)
|
|
228
|
+
|
|
229
|
+
channels_meta_ = ChannelsMeta(channels=list_of_channels)
|
|
230
|
+
meta.set_channels_meta(channels_meta=channels_meta_)
|
|
231
|
+
return meta
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def init_image_like(
|
|
235
|
+
*,
|
|
236
|
+
# Where to create the image
|
|
237
|
+
store: StoreOrGroup,
|
|
238
|
+
# Ngff image parameters
|
|
239
|
+
meta_type: type[_image_or_label_meta],
|
|
240
|
+
shape: Sequence[int],
|
|
241
|
+
pixelsize: float | tuple[float, float],
|
|
242
|
+
z_spacing: float = 1.0,
|
|
243
|
+
time_spacing: float = 1.0,
|
|
244
|
+
scaling_factors: Sequence[float] | Literal["auto"] = "auto",
|
|
245
|
+
levels: int | list[str] = 5,
|
|
246
|
+
space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
247
|
+
time_unit: TimeUnits | str | None = DefaultTimeUnit,
|
|
248
|
+
axes_names: Sequence[str] | None = None,
|
|
249
|
+
name: str | None = None,
|
|
250
|
+
channels_meta: Sequence[str | Channel] | None = None,
|
|
251
|
+
ngff_version: NgffVersions = DefaultNgffVersion,
|
|
252
|
+
# Zarr Array parameters
|
|
253
|
+
chunks: ChunksLike = "auto",
|
|
254
|
+
shards: ShardsLike | None = None,
|
|
255
|
+
dtype: str = "uint16",
|
|
256
|
+
dimension_separator: Literal[".", "/"] = "/",
|
|
257
|
+
compressors: CompressorLike = "auto",
|
|
258
|
+
extra_array_kwargs: Mapping[str, Any] | None = None,
|
|
259
|
+
# internal axes configuration for advanced use cases
|
|
260
|
+
axes_setup: AxesSetup | None = None,
|
|
261
|
+
allow_non_canonical_axes: bool = False,
|
|
262
|
+
strict_canonical_order: bool = False,
|
|
263
|
+
# Whether to overwrite existing image
|
|
264
|
+
overwrite: bool = False,
|
|
265
|
+
# Deprecated arguments
|
|
266
|
+
yx_scaling_factor: float | tuple[float, float] | None = None,
|
|
267
|
+
z_scaling_factor: float | None = None,
|
|
268
|
+
) -> ZarrGroupHandler:
|
|
269
|
+
"""Create an empty OME-Zarr image with the given shape and metadata."""
|
|
270
|
+
shape = tuple(shape)
|
|
271
|
+
if meta_type is NgioImageMeta:
|
|
272
|
+
default_axes_order = canonical_axes_order()
|
|
273
|
+
else:
|
|
274
|
+
default_axes_order = canonical_label_axes_order()
|
|
275
|
+
|
|
276
|
+
axes_handler = _build_axes_handler(
|
|
277
|
+
shape=shape,
|
|
278
|
+
axes_names=axes_names,
|
|
279
|
+
default_channel_order=default_axes_order,
|
|
280
|
+
space_units=space_unit,
|
|
281
|
+
time_units=time_unit,
|
|
282
|
+
axes_setup=axes_setup,
|
|
283
|
+
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
284
|
+
strict_canonical_order=strict_canonical_order,
|
|
285
|
+
)
|
|
286
|
+
base_scale = _compute_base_scale(
|
|
287
|
+
pixelsize=pixelsize,
|
|
288
|
+
z_spacing=z_spacing,
|
|
289
|
+
time_spacing=time_spacing,
|
|
290
|
+
axes_handler=axes_handler,
|
|
291
|
+
)
|
|
292
|
+
scaling_factors = _compute_scaling_factors(
|
|
293
|
+
scaling_factors=scaling_factors,
|
|
294
|
+
shape=shape,
|
|
295
|
+
axes_handler=axes_handler,
|
|
296
|
+
xy_scaling_factor=yx_scaling_factor,
|
|
297
|
+
z_scaling_factor=z_scaling_factor,
|
|
298
|
+
)
|
|
299
|
+
if isinstance(levels, int):
|
|
300
|
+
levels_paths = tuple(str(i) for i in range(levels))
|
|
301
|
+
else:
|
|
302
|
+
levels_paths = tuple(levels)
|
|
303
|
+
|
|
304
|
+
pyramid_builder = ImagePyramidBuilder.from_scaling_factors(
|
|
305
|
+
levels_paths=levels_paths,
|
|
306
|
+
scaling_factors=scaling_factors,
|
|
307
|
+
base_shape=shape,
|
|
308
|
+
base_scale=base_scale,
|
|
309
|
+
axes=axes_handler.axes_names,
|
|
310
|
+
chunks=chunks,
|
|
311
|
+
data_type=dtype,
|
|
312
|
+
dimension_separator=dimension_separator,
|
|
313
|
+
compressors=compressors,
|
|
314
|
+
shards=shards,
|
|
315
|
+
zarr_format=2 if ngff_version == "0.4" else 3,
|
|
316
|
+
other_array_kwargs=extra_array_kwargs,
|
|
317
|
+
)
|
|
318
|
+
meta = meta_type.default_init(
|
|
319
|
+
levels=[p.path for p in pyramid_builder.levels],
|
|
320
|
+
axes_handler=axes_handler,
|
|
321
|
+
scales=[p.scale for p in pyramid_builder.levels],
|
|
322
|
+
translations=[None for _ in pyramid_builder.levels],
|
|
323
|
+
name=name,
|
|
324
|
+
version=ngff_version,
|
|
325
|
+
)
|
|
326
|
+
meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
|
|
327
|
+
# Keep this creation at the end to avoid partial creations on errors
|
|
328
|
+
return _create_image_like_group(
|
|
329
|
+
store=store,
|
|
330
|
+
pyramid_builder=pyramid_builder,
|
|
331
|
+
meta=meta,
|
|
332
|
+
overwrite=overwrite,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def init_image_like_from_shapes(
|
|
337
|
+
*,
|
|
338
|
+
# Where to create the image
|
|
339
|
+
store: StoreOrGroup,
|
|
340
|
+
# Ngff image parameters
|
|
341
|
+
meta_type: type[_image_or_label_meta],
|
|
342
|
+
shapes: Sequence[tuple[int, ...]],
|
|
343
|
+
pixelsize: float | tuple[float, float],
|
|
344
|
+
z_spacing: float = 1.0,
|
|
345
|
+
time_spacing: float = 1.0,
|
|
346
|
+
levels: list[str] | None = None,
|
|
347
|
+
space_unit: SpaceUnits | str | None = DefaultSpaceUnit,
|
|
348
|
+
time_unit: TimeUnits | str | None = DefaultTimeUnit,
|
|
349
|
+
axes_names: Sequence[str] | None = None,
|
|
350
|
+
name: str | None = None,
|
|
351
|
+
channels_meta: Sequence[str | Channel] | None = None,
|
|
352
|
+
ngff_version: NgffVersions = DefaultNgffVersion,
|
|
353
|
+
# Zarr Array parameters
|
|
354
|
+
chunks: ChunksLike = "auto",
|
|
355
|
+
shards: ShardsLike | None = None,
|
|
356
|
+
dtype: str = "uint16",
|
|
357
|
+
dimension_separator: Literal[".", "/"] = "/",
|
|
358
|
+
compressors: CompressorLike = "auto",
|
|
359
|
+
extra_array_kwargs: Mapping[str, Any] | None = None,
|
|
360
|
+
# internal axes configuration for advanced use cases
|
|
361
|
+
axes_setup: AxesSetup | None = None,
|
|
362
|
+
allow_non_canonical_axes: bool = False,
|
|
363
|
+
strict_canonical_order: bool = False,
|
|
364
|
+
# Whether to overwrite existing image
|
|
365
|
+
overwrite: bool = False,
|
|
366
|
+
) -> ZarrGroupHandler:
|
|
367
|
+
"""Create an empty OME-Zarr image with the given shape and metadata."""
|
|
368
|
+
base_shape = shapes[0]
|
|
369
|
+
if meta_type is NgioImageMeta:
|
|
370
|
+
default_axes_order = canonical_axes_order()
|
|
371
|
+
else:
|
|
372
|
+
default_axes_order = canonical_label_axes_order()
|
|
373
|
+
|
|
374
|
+
axes_handler = _build_axes_handler(
|
|
375
|
+
shape=base_shape,
|
|
376
|
+
axes_names=axes_names,
|
|
377
|
+
default_channel_order=default_axes_order,
|
|
378
|
+
space_units=space_unit,
|
|
379
|
+
time_units=time_unit,
|
|
380
|
+
axes_setup=axes_setup,
|
|
381
|
+
allow_non_canonical_axes=allow_non_canonical_axes,
|
|
382
|
+
strict_canonical_order=strict_canonical_order,
|
|
383
|
+
)
|
|
384
|
+
base_scale = _compute_base_scale(
|
|
385
|
+
pixelsize=pixelsize,
|
|
386
|
+
z_spacing=z_spacing,
|
|
387
|
+
time_spacing=time_spacing,
|
|
388
|
+
axes_handler=axes_handler,
|
|
389
|
+
)
|
|
390
|
+
if levels is None:
|
|
391
|
+
levels_paths = tuple(str(i) for i in range(len(shapes)))
|
|
392
|
+
else:
|
|
393
|
+
levels_paths = tuple(levels)
|
|
394
|
+
|
|
395
|
+
pyramid_builder = ImagePyramidBuilder.from_shapes(
|
|
396
|
+
shapes=shapes,
|
|
397
|
+
base_scale=base_scale,
|
|
398
|
+
levels_paths=levels_paths,
|
|
399
|
+
axes=axes_handler.axes_names,
|
|
400
|
+
chunks=chunks,
|
|
401
|
+
data_type=dtype,
|
|
402
|
+
dimension_separator=dimension_separator,
|
|
403
|
+
compressors=compressors,
|
|
404
|
+
shards=shards,
|
|
405
|
+
zarr_format=2 if ngff_version == "0.4" else 3,
|
|
406
|
+
other_array_kwargs=extra_array_kwargs,
|
|
407
|
+
)
|
|
408
|
+
meta = meta_type.default_init(
|
|
409
|
+
levels=[p.path for p in pyramid_builder.levels],
|
|
410
|
+
axes_handler=axes_handler,
|
|
411
|
+
scales=[p.scale for p in pyramid_builder.levels],
|
|
412
|
+
translations=[None for _ in pyramid_builder.levels],
|
|
413
|
+
name=name,
|
|
414
|
+
version=ngff_version,
|
|
415
|
+
)
|
|
416
|
+
meta = _add_channels_meta(meta=meta, channels_meta=channels_meta)
|
|
417
|
+
# Keep this creation at the end to avoid partial creations on errors
|
|
418
|
+
return _create_image_like_group(
|
|
419
|
+
store=store,
|
|
420
|
+
pyramid_builder=pyramid_builder,
|
|
421
|
+
meta=meta,
|
|
422
|
+
overwrite=overwrite,
|
|
423
|
+
)
|