ngio 0.2.0a2__py3-none-any.whl → 0.2.0b1__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 +4 -4
- ngio/common/__init__.py +12 -2
- ngio/common/_array_pipe.py +106 -0
- ngio/common/_axes_transforms.py +3 -2
- ngio/common/_dimensions.py +7 -0
- ngio/common/_masking_roi.py +158 -0
- ngio/common/_pyramid.py +16 -11
- ngio/common/_roi.py +74 -0
- ngio/common/_slicer.py +1 -2
- ngio/common/_zoom.py +5 -3
- ngio/hcs/__init__.py +2 -57
- ngio/hcs/plate.py +399 -0
- ngio/images/abstract_image.py +97 -28
- ngio/images/create.py +48 -29
- ngio/images/image.py +121 -57
- ngio/images/label.py +131 -86
- ngio/images/masked_image.py +259 -0
- ngio/images/omezarr_container.py +250 -77
- ngio/ome_zarr_meta/__init__.py +25 -13
- ngio/ome_zarr_meta/_meta_handlers.py +718 -69
- ngio/ome_zarr_meta/ngio_specs/__init__.py +8 -0
- ngio/ome_zarr_meta/ngio_specs/_channels.py +11 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +374 -2
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +174 -113
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +35 -3
- ngio/ome_zarr_meta/v04/__init__.py +17 -5
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +85 -12
- ngio/tables/__init__.py +2 -0
- ngio/tables/_validators.py +2 -4
- ngio/tables/backends/_anndata_utils.py +2 -1
- ngio/tables/backends/_anndata_v1.py +2 -1
- ngio/tables/backends/_json_v1.py +1 -1
- ngio/tables/tables_container.py +12 -2
- ngio/tables/v1/__init__.py +1 -2
- ngio/tables/v1/_feature_table.py +7 -5
- ngio/tables/v1/_generic_table.py +65 -11
- ngio/tables/v1/_roi_table.py +145 -27
- ngio/utils/__init__.py +3 -0
- ngio/utils/_datasets.py +4 -2
- ngio/utils/_fractal_fsspec_store.py +13 -0
- ngio/utils/_logger.py +3 -1
- ngio/utils/_zarr_utils.py +25 -2
- {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/METADATA +4 -1
- ngio-0.2.0b1.dist-info/RECORD +54 -0
- ngio/ome_zarr_meta/_generic_handlers.py +0 -320
- ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
- ngio/tables/v1/_masking_roi_table.py +0 -175
- ngio-0.2.0a2.dist-info/RECORD +0 -53
- {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/WHEEL +0 -0
- {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/licenses/LICENSE +0 -0
ngio/images/label.py
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
from collections.abc import Collection
|
|
4
4
|
from typing import Literal
|
|
5
5
|
|
|
6
|
+
from ngio.common import compute_masking_roi
|
|
6
7
|
from ngio.images.abstract_image import AbstractImage, consolidate_image
|
|
7
8
|
from ngio.images.create import _create_empty_label
|
|
8
9
|
from ngio.images.image import Image
|
|
9
10
|
from ngio.ome_zarr_meta import (
|
|
10
|
-
ImplementedLabelMetaHandlers,
|
|
11
11
|
LabelMetaHandler,
|
|
12
12
|
NgioLabelMeta,
|
|
13
|
+
PixelSize,
|
|
14
|
+
find_label_meta_handler,
|
|
13
15
|
)
|
|
14
|
-
from ngio.
|
|
16
|
+
from ngio.tables import MaskingROITable
|
|
15
17
|
from ngio.utils import (
|
|
16
18
|
NgioValidationError,
|
|
17
19
|
NgioValueError,
|
|
@@ -38,9 +40,7 @@ class Label(AbstractImage[LabelMetaHandler]):
|
|
|
38
40
|
|
|
39
41
|
"""
|
|
40
42
|
if meta_handler is None:
|
|
41
|
-
meta_handler =
|
|
42
|
-
group_handler
|
|
43
|
-
)
|
|
43
|
+
meta_handler = find_label_meta_handler(group_handler)
|
|
44
44
|
super().__init__(
|
|
45
45
|
group_handler=group_handler, path=path, meta_handler=meta_handler
|
|
46
46
|
)
|
|
@@ -50,6 +50,10 @@ class Label(AbstractImage[LabelMetaHandler]):
|
|
|
50
50
|
"""Return the metadata."""
|
|
51
51
|
return self._meta_handler.meta
|
|
52
52
|
|
|
53
|
+
def build_masking_roi_table(self) -> MaskingROITable:
|
|
54
|
+
"""Compute the masking ROI table."""
|
|
55
|
+
return build_masking_roi_table(self)
|
|
56
|
+
|
|
53
57
|
def consolidate(
|
|
54
58
|
self,
|
|
55
59
|
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
@@ -86,66 +90,62 @@ class LabelsContainer:
|
|
|
86
90
|
attrs = self._group_handler.load_attrs()
|
|
87
91
|
return attrs.get("labels", [])
|
|
88
92
|
|
|
89
|
-
def get(
|
|
90
|
-
|
|
93
|
+
def get(
|
|
94
|
+
self,
|
|
95
|
+
name: str,
|
|
96
|
+
path: str | None = None,
|
|
97
|
+
pixel_size: PixelSize | None = None,
|
|
98
|
+
strict: bool = False,
|
|
99
|
+
) -> Label:
|
|
100
|
+
"""Get a label from the group.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
name (str): The name of the label.
|
|
104
|
+
path (str | None): The path to the image in the omezarr file.
|
|
105
|
+
pixel_size (PixelSize | None): The pixel size of the image.
|
|
106
|
+
strict (bool): Only used if the pixel size is provided. If True, the
|
|
107
|
+
pixel size must match the image pixel size exactly. If False, the
|
|
108
|
+
closest pixel size level will be returned.
|
|
109
|
+
|
|
110
|
+
"""
|
|
91
111
|
group_handler = self._group_handler.derive_handler(name)
|
|
92
|
-
|
|
112
|
+
label_meta_handler = find_label_meta_handler(group_handler)
|
|
113
|
+
path = label_meta_handler.meta.get_dataset(
|
|
114
|
+
path=path, pixel_size=pixel_size, strict=strict
|
|
115
|
+
).path
|
|
116
|
+
return Label(group_handler, path, label_meta_handler)
|
|
93
117
|
|
|
94
118
|
def derive(
|
|
95
119
|
self,
|
|
96
120
|
name: str,
|
|
97
121
|
ref_image: Image,
|
|
98
122
|
shape: Collection[int] | None = None,
|
|
123
|
+
pixel_size: PixelSize | None = None,
|
|
124
|
+
axes_names: Collection[str] | None = None,
|
|
99
125
|
chunks: Collection[int] | None = None,
|
|
100
|
-
dtype: str =
|
|
101
|
-
xy_scaling_factor=2.0,
|
|
102
|
-
z_scaling_factor=1.0,
|
|
126
|
+
dtype: str | None = None,
|
|
103
127
|
overwrite: bool = False,
|
|
104
|
-
) ->
|
|
105
|
-
"""
|
|
106
|
-
existing_labels = self.list()
|
|
107
|
-
if name in existing_labels and not overwrite:
|
|
108
|
-
raise NgioValueError(
|
|
109
|
-
f"Table '{name}' already exists in the group. "
|
|
110
|
-
"Use overwrite=True to replace it."
|
|
111
|
-
)
|
|
128
|
+
) -> "Label":
|
|
129
|
+
"""Create an empty OME-Zarr label from a reference image.
|
|
112
130
|
|
|
113
|
-
|
|
131
|
+
And add the label to the /labels group.
|
|
114
132
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
Args:
|
|
134
|
+
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
135
|
+
ref_image (Image): The reference image.
|
|
136
|
+
name (str): The name of the new image.
|
|
137
|
+
shape (Collection[int] | None): The shape of the new image.
|
|
138
|
+
pixel_size (PixelSize | None): The pixel size of the new image.
|
|
139
|
+
axes_names (Collection[str] | None): The axes names of the new image.
|
|
140
|
+
For labels, the channel axis is not allowed.
|
|
141
|
+
chunks (Collection[int] | None): The chunk shape of the new image.
|
|
142
|
+
dtype (str | None): The data type of the new image.
|
|
143
|
+
overwrite (bool): Whether to overwrite an existing image.
|
|
125
144
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
self._group_handler.write_attrs({"labels": existing_labels})
|
|
145
|
+
Returns:
|
|
146
|
+
Label: The new label.
|
|
129
147
|
|
|
130
|
-
|
|
131
|
-
self,
|
|
132
|
-
name: str,
|
|
133
|
-
shape: Collection[int],
|
|
134
|
-
xy_pixelsize: float,
|
|
135
|
-
z_spacing: float = 1.0,
|
|
136
|
-
time_spacing: float = 1.0,
|
|
137
|
-
levels: "int | list[str]" = 5,
|
|
138
|
-
xy_scaling_factor: float = 2.0,
|
|
139
|
-
z_scaling_factor: float = 1.0,
|
|
140
|
-
space_unit: SpaceUnits | str | None = None,
|
|
141
|
-
time_unit: TimeUnits | str | None = None,
|
|
142
|
-
axes_names: Collection[str] | None = None,
|
|
143
|
-
chunks: Collection[int] | None = None,
|
|
144
|
-
dtype: str = "uint16",
|
|
145
|
-
overwrite: bool = False,
|
|
146
|
-
version: str = "0.4",
|
|
147
|
-
) -> None:
|
|
148
|
-
"""Add a label to the group."""
|
|
148
|
+
"""
|
|
149
149
|
existing_labels = self.list()
|
|
150
150
|
if name in existing_labels and not overwrite:
|
|
151
151
|
raise NgioValueError(
|
|
@@ -155,82 +155,127 @@ class LabelsContainer:
|
|
|
155
155
|
|
|
156
156
|
label_group = self._group_handler.get_group(name, create_mode=True)
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
_derive_label(
|
|
159
159
|
store=label_group,
|
|
160
|
+
ref_image=ref_image,
|
|
161
|
+
name=name,
|
|
160
162
|
shape=shape,
|
|
161
|
-
|
|
162
|
-
z_spacing=z_spacing,
|
|
163
|
-
time_spacing=time_spacing,
|
|
164
|
-
levels=levels,
|
|
165
|
-
xy_scaling_factor=xy_scaling_factor,
|
|
166
|
-
z_scaling_factor=z_scaling_factor,
|
|
167
|
-
space_unit=space_unit,
|
|
168
|
-
time_unit=time_unit,
|
|
163
|
+
pixel_size=pixel_size,
|
|
169
164
|
axes_names=axes_names,
|
|
170
165
|
chunks=chunks,
|
|
171
166
|
dtype=dtype,
|
|
172
167
|
overwrite=overwrite,
|
|
173
|
-
version=version,
|
|
174
168
|
)
|
|
175
169
|
|
|
176
170
|
if name not in existing_labels:
|
|
177
171
|
existing_labels.append(name)
|
|
178
172
|
self._group_handler.write_attrs({"labels": existing_labels})
|
|
179
173
|
|
|
174
|
+
return self.get(name)
|
|
175
|
+
|
|
180
176
|
|
|
181
177
|
def _derive_label(
|
|
182
|
-
ref_image: Image,
|
|
183
178
|
store: StoreOrGroup,
|
|
179
|
+
ref_image: Image,
|
|
180
|
+
name: str,
|
|
184
181
|
shape: Collection[int] | None = None,
|
|
182
|
+
pixel_size: PixelSize | None = None,
|
|
183
|
+
axes_names: Collection[str] | None = None,
|
|
185
184
|
chunks: Collection[int] | None = None,
|
|
186
|
-
dtype: str =
|
|
187
|
-
xy_scaling_factor=2.0,
|
|
188
|
-
z_scaling_factor=1.0,
|
|
185
|
+
dtype: str | None = None,
|
|
189
186
|
overwrite: bool = False,
|
|
190
187
|
) -> None:
|
|
191
|
-
"""Create an OME-Zarr
|
|
188
|
+
"""Create an empty OME-Zarr label from a reference image.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
store (StoreOrGroup): The Zarr store or group to create the image in.
|
|
192
|
+
ref_image (Image): The reference image.
|
|
193
|
+
name (str): The name of the new image.
|
|
194
|
+
shape (Collection[int] | None): The shape of the new image.
|
|
195
|
+
pixel_size (PixelSize | None): The pixel size of the new image.
|
|
196
|
+
axes_names (Collection[str] | None): The axes names of the new image.
|
|
197
|
+
For labels, the channel axis is not allowed.
|
|
198
|
+
chunks (Collection[int] | None): The chunk shape of the new image.
|
|
199
|
+
dtype (str | None): The data type of the new image.
|
|
200
|
+
overwrite (bool): Whether to overwrite an existing image.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
None
|
|
204
|
+
|
|
205
|
+
"""
|
|
192
206
|
ref_meta = ref_image.meta
|
|
193
|
-
# remove channls if present
|
|
194
|
-
shape_ref = ref_image.shape
|
|
195
|
-
chunks_ref = ref_image.chunks
|
|
196
|
-
axes_names_ref = ref_image.dataset.axes_mapper.on_disk_axes_names
|
|
197
|
-
c_axis = ref_image.dataset.axes_mapper.get_index("c")
|
|
198
|
-
if c_axis is not None:
|
|
199
|
-
shape_ref = shape_ref[:c_axis] + shape_ref[c_axis + 1 :]
|
|
200
|
-
chunks_ref = chunks_ref[:c_axis] + chunks_ref[c_axis + 1 :]
|
|
201
|
-
axes_names_ref = axes_names_ref[:c_axis] + axes_names_ref[c_axis + 1 :]
|
|
202
207
|
|
|
203
208
|
if shape is None:
|
|
204
|
-
shape =
|
|
209
|
+
shape = ref_image.shape
|
|
205
210
|
|
|
206
|
-
if
|
|
207
|
-
|
|
211
|
+
if pixel_size is None:
|
|
212
|
+
pixel_size = ref_image.pixel_size
|
|
208
213
|
|
|
209
|
-
if
|
|
214
|
+
if axes_names is None:
|
|
215
|
+
axes_names = ref_meta.axes_mapper.on_disk_axes_names
|
|
216
|
+
c_axis = ref_meta.axes_mapper.get_index("c")
|
|
217
|
+
else:
|
|
218
|
+
if "c" in axes_names:
|
|
219
|
+
raise NgioValidationError(
|
|
220
|
+
"Labels cannot have a channel axis. "
|
|
221
|
+
"Please remove the channel axis from the axes names."
|
|
222
|
+
)
|
|
223
|
+
c_axis = None
|
|
224
|
+
|
|
225
|
+
if len(axes_names) != len(shape):
|
|
210
226
|
raise NgioValidationError(
|
|
211
|
-
"The
|
|
227
|
+
"The axes names of the new image does not match the reference image."
|
|
228
|
+
f"Got {axes_names} for shape {shape}."
|
|
212
229
|
)
|
|
213
230
|
|
|
214
|
-
if
|
|
231
|
+
if chunks is None:
|
|
232
|
+
chunks = ref_image.chunks
|
|
233
|
+
|
|
234
|
+
if len(chunks) != len(shape):
|
|
215
235
|
raise NgioValidationError(
|
|
216
236
|
"The chunks of the new image does not match the reference image."
|
|
237
|
+
f"Got {chunks} for shape {shape}."
|
|
217
238
|
)
|
|
218
239
|
|
|
240
|
+
if dtype is None:
|
|
241
|
+
dtype = ref_image.dtype
|
|
242
|
+
|
|
243
|
+
if c_axis is not None:
|
|
244
|
+
# remove channel if present
|
|
245
|
+
shape = list(shape)
|
|
246
|
+
shape = shape[:c_axis] + shape[c_axis + 1 :]
|
|
247
|
+
chunks = list(chunks)
|
|
248
|
+
chunks = chunks[:c_axis] + chunks[c_axis + 1 :]
|
|
249
|
+
axes_names = list(axes_names)
|
|
250
|
+
axes_names = axes_names[:c_axis] + axes_names[c_axis + 1 :]
|
|
251
|
+
|
|
219
252
|
_ = _create_empty_label(
|
|
220
253
|
store=store,
|
|
221
254
|
shape=shape,
|
|
222
|
-
|
|
255
|
+
pixelsize=ref_image.pixel_size.x,
|
|
223
256
|
z_spacing=ref_image.pixel_size.z,
|
|
224
257
|
time_spacing=ref_image.pixel_size.t,
|
|
225
258
|
levels=ref_meta.levels,
|
|
226
|
-
|
|
227
|
-
z_scaling_factor=
|
|
259
|
+
yx_scaling_factor=ref_meta.yx_scaling(),
|
|
260
|
+
z_scaling_factor=ref_meta.z_scaling(),
|
|
228
261
|
time_unit=ref_image.pixel_size.time_unit,
|
|
229
262
|
space_unit=ref_image.pixel_size.space_unit,
|
|
230
|
-
axes_names=
|
|
263
|
+
axes_names=axes_names,
|
|
231
264
|
chunks=chunks,
|
|
232
265
|
dtype=dtype,
|
|
233
266
|
overwrite=overwrite,
|
|
234
267
|
version=ref_meta.version,
|
|
268
|
+
name=name,
|
|
235
269
|
)
|
|
236
270
|
return None
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def build_masking_roi_table(label: Label) -> MaskingROITable:
|
|
274
|
+
"""Compute the masking ROI table for a label."""
|
|
275
|
+
if label.dimensions.is_time_series:
|
|
276
|
+
raise NgioValueError("Time series labels are not supported.")
|
|
277
|
+
|
|
278
|
+
array = label.get_array(axes_order=["z", "y", "x"], mode="dask")
|
|
279
|
+
|
|
280
|
+
rois = compute_masking_roi(array, label.pixel_size)
|
|
281
|
+
return MaskingROITable(rois, reference_label=label.meta.name)
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""A module for handling label images in OME-NGFF files."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Collection, Iterable
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
from ngio.common import ArrayLike, get_masked_pipe, roi_to_slice_kwargs, set_masked_pipe
|
|
7
|
+
from ngio.images.image import Image
|
|
8
|
+
from ngio.images.label import Label
|
|
9
|
+
from ngio.ome_zarr_meta import ImageMetaHandler, LabelMetaHandler
|
|
10
|
+
from ngio.tables import MaskingROITable
|
|
11
|
+
from ngio.utils import (
|
|
12
|
+
ZarrGroupHandler,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MaskedImage(Image):
|
|
17
|
+
"""Placeholder class for a label."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
group_handler: ZarrGroupHandler,
|
|
22
|
+
path: str,
|
|
23
|
+
meta_handler: ImageMetaHandler | None,
|
|
24
|
+
label: Label,
|
|
25
|
+
masking_roi_table: MaskingROITable,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Initialize the Image at a single level.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
group_handler: The Zarr group handler.
|
|
31
|
+
path: The path to the image in the omezarr file.
|
|
32
|
+
meta_handler: The image metadata handler.
|
|
33
|
+
label: The label image.
|
|
34
|
+
masking_roi_table: The masking ROI table.
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
super().__init__(
|
|
38
|
+
group_handler=group_handler, path=path, meta_handler=meta_handler
|
|
39
|
+
)
|
|
40
|
+
self._label = label
|
|
41
|
+
self._masking_roi_table = masking_roi_table
|
|
42
|
+
|
|
43
|
+
def get_roi(
|
|
44
|
+
self,
|
|
45
|
+
label: int,
|
|
46
|
+
zoom_factor: float = 1.0,
|
|
47
|
+
axes_order: Collection[str] | None = None,
|
|
48
|
+
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
49
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
50
|
+
) -> ArrayLike:
|
|
51
|
+
"""Return the array for a given ROI."""
|
|
52
|
+
roi = self._masking_roi_table.get(label)
|
|
53
|
+
roi = roi.zoom(zoom_factor)
|
|
54
|
+
return super().get_roi(
|
|
55
|
+
roi=roi, axes_order=axes_order, mode=mode, **slice_kwargs
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def set_roi(
|
|
59
|
+
self,
|
|
60
|
+
label: int,
|
|
61
|
+
patch: ArrayLike,
|
|
62
|
+
zoom_factor: float = 1.0,
|
|
63
|
+
axes_order: Collection[str] | None = None,
|
|
64
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Set the array for a given ROI."""
|
|
67
|
+
roi = self._masking_roi_table.get(label)
|
|
68
|
+
roi = roi.zoom(zoom_factor)
|
|
69
|
+
return super().set_roi(
|
|
70
|
+
roi=roi, patch=patch, axes_order=axes_order, **slice_kwargs
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def get_roi_masked(
|
|
74
|
+
self,
|
|
75
|
+
label: int,
|
|
76
|
+
axes_order: Collection[str] | None = None,
|
|
77
|
+
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
78
|
+
zoom_factor: float = 1.0,
|
|
79
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
80
|
+
) -> ArrayLike:
|
|
81
|
+
"""Return the masked array for a given label."""
|
|
82
|
+
return get_masked_roi_pipe(
|
|
83
|
+
image=self,
|
|
84
|
+
label=label,
|
|
85
|
+
axes_order=axes_order,
|
|
86
|
+
mode=mode,
|
|
87
|
+
zoom_factor=zoom_factor,
|
|
88
|
+
**slice_kwargs,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def set_roi_masked(
|
|
92
|
+
self,
|
|
93
|
+
label: int,
|
|
94
|
+
patch: ArrayLike,
|
|
95
|
+
axes_order: Collection[str] | None = None,
|
|
96
|
+
zoom_factor: float = 1.0,
|
|
97
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Set the masked array for a given label."""
|
|
100
|
+
return set_masked_roi_pipe(
|
|
101
|
+
image=self,
|
|
102
|
+
label=label,
|
|
103
|
+
patch=patch,
|
|
104
|
+
axes_order=axes_order,
|
|
105
|
+
zoom_factor=zoom_factor,
|
|
106
|
+
**slice_kwargs,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class MaskedLabel(Label):
|
|
111
|
+
"""Placeholder class for a label."""
|
|
112
|
+
|
|
113
|
+
def __init__(
|
|
114
|
+
self,
|
|
115
|
+
group_handler: ZarrGroupHandler,
|
|
116
|
+
path: str,
|
|
117
|
+
meta_handler: LabelMetaHandler | None,
|
|
118
|
+
label: Label,
|
|
119
|
+
masking_roi_table: MaskingROITable,
|
|
120
|
+
) -> None:
|
|
121
|
+
"""Initialize the Image at a single level.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
group_handler: The Zarr group handler.
|
|
125
|
+
path: The path to the image in the omezarr file.
|
|
126
|
+
meta_handler: The image metadata handler.
|
|
127
|
+
label: The label image.
|
|
128
|
+
masking_roi_table: The masking ROI table.
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
super().__init__(
|
|
132
|
+
group_handler=group_handler, path=path, meta_handler=meta_handler
|
|
133
|
+
)
|
|
134
|
+
self._label = label
|
|
135
|
+
self._masking_roi_table = masking_roi_table
|
|
136
|
+
|
|
137
|
+
def get_roi(
|
|
138
|
+
self,
|
|
139
|
+
label: int,
|
|
140
|
+
zoom_factor: float = 1.0,
|
|
141
|
+
axes_order: Collection[str] | None = None,
|
|
142
|
+
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
143
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
144
|
+
) -> ArrayLike:
|
|
145
|
+
"""Return the array for a given ROI."""
|
|
146
|
+
roi = self._masking_roi_table.get(label)
|
|
147
|
+
roi = roi.zoom(zoom_factor)
|
|
148
|
+
return super().get_roi(
|
|
149
|
+
roi=roi, axes_order=axes_order, mode=mode, **slice_kwargs
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def set_roi(
|
|
153
|
+
self,
|
|
154
|
+
label: int,
|
|
155
|
+
patch: ArrayLike,
|
|
156
|
+
zoom_factor: float = 1.0,
|
|
157
|
+
axes_order: Collection[str] | None = None,
|
|
158
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Set the array for a given ROI."""
|
|
161
|
+
roi = self._masking_roi_table.get(label)
|
|
162
|
+
roi = roi.zoom(zoom_factor)
|
|
163
|
+
return super().set_roi(
|
|
164
|
+
roi=roi, patch=patch, axes_order=axes_order, **slice_kwargs
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def get_roi_masked(
|
|
168
|
+
self,
|
|
169
|
+
label: int,
|
|
170
|
+
axes_order: Collection[str] | None = None,
|
|
171
|
+
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
172
|
+
zoom_factor: float = 1.0,
|
|
173
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
174
|
+
) -> ArrayLike:
|
|
175
|
+
"""Return the masked array for a given label."""
|
|
176
|
+
return get_masked_roi_pipe(
|
|
177
|
+
image=self,
|
|
178
|
+
label=label,
|
|
179
|
+
axes_order=axes_order,
|
|
180
|
+
mode=mode,
|
|
181
|
+
zoom_factor=zoom_factor,
|
|
182
|
+
**slice_kwargs,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def set_roi_masked(
|
|
186
|
+
self,
|
|
187
|
+
label: int,
|
|
188
|
+
patch: ArrayLike,
|
|
189
|
+
axes_order: Collection[str] | None = None,
|
|
190
|
+
zoom_factor: float = 1.0,
|
|
191
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Set the masked array for a given label."""
|
|
194
|
+
return set_masked_roi_pipe(
|
|
195
|
+
image=self,
|
|
196
|
+
label=label,
|
|
197
|
+
patch=patch,
|
|
198
|
+
axes_order=axes_order,
|
|
199
|
+
zoom_factor=zoom_factor,
|
|
200
|
+
**slice_kwargs,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def get_masked_roi_pipe(
|
|
205
|
+
image: MaskedImage | MaskedLabel,
|
|
206
|
+
label: int,
|
|
207
|
+
axes_order: Collection[str] | None = None,
|
|
208
|
+
mode: Literal["numpy", "dask", "delayed"] = "numpy",
|
|
209
|
+
zoom_factor: float = 1.0,
|
|
210
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
211
|
+
) -> ArrayLike:
|
|
212
|
+
"""Return the masked array for a given label."""
|
|
213
|
+
roi = image._masking_roi_table.get(label)
|
|
214
|
+
roi = roi.zoom(zoom_factor)
|
|
215
|
+
slice_kwargs = roi_to_slice_kwargs(
|
|
216
|
+
roi=roi,
|
|
217
|
+
pixel_size=image.pixel_size,
|
|
218
|
+
dimensions=image.dimensions,
|
|
219
|
+
**slice_kwargs,
|
|
220
|
+
)
|
|
221
|
+
return get_masked_pipe(
|
|
222
|
+
array=image.zarr_array,
|
|
223
|
+
label_array=image._label.zarr_array,
|
|
224
|
+
label=label,
|
|
225
|
+
dimensions_array=image.dimensions,
|
|
226
|
+
dimensions_label=image._label.dimensions,
|
|
227
|
+
axes_order=axes_order,
|
|
228
|
+
mode=mode,
|
|
229
|
+
**slice_kwargs,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def set_masked_roi_pipe(
|
|
234
|
+
image: MaskedImage | MaskedLabel,
|
|
235
|
+
label: int,
|
|
236
|
+
patch: ArrayLike,
|
|
237
|
+
axes_order: Collection[str] | None = None,
|
|
238
|
+
zoom_factor: float = 1.0,
|
|
239
|
+
**slice_kwargs: slice | int | Iterable[int],
|
|
240
|
+
) -> None:
|
|
241
|
+
"""Set the masked array for a given label."""
|
|
242
|
+
roi = image._masking_roi_table.get(label)
|
|
243
|
+
roi = roi.zoom(zoom_factor)
|
|
244
|
+
slice_kwargs = roi_to_slice_kwargs(
|
|
245
|
+
roi=roi,
|
|
246
|
+
pixel_size=image.pixel_size,
|
|
247
|
+
dimensions=image.dimensions,
|
|
248
|
+
**slice_kwargs,
|
|
249
|
+
)
|
|
250
|
+
return set_masked_pipe(
|
|
251
|
+
array=image.zarr_array,
|
|
252
|
+
label_array=image._label.zarr_array,
|
|
253
|
+
label=label,
|
|
254
|
+
patch=patch,
|
|
255
|
+
dimensions_array=image.dimensions,
|
|
256
|
+
dimensions_label=image._label.dimensions,
|
|
257
|
+
axes_order=axes_order,
|
|
258
|
+
**slice_kwargs,
|
|
259
|
+
)
|