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