ngio 0.1.6__py3-none-any.whl → 0.2.0a1__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 +31 -5
- ngio/common/__init__.py +44 -0
- ngio/common/_array_pipe.py +160 -0
- ngio/common/_axes_transforms.py +63 -0
- ngio/common/_common_types.py +5 -0
- ngio/common/_dimensions.py +113 -0
- ngio/common/_pyramid.py +222 -0
- ngio/{core/roi.py → common/_roi.py} +22 -23
- ngio/common/_slicer.py +97 -0
- ngio/{pipes/_zoom_utils.py → common/_zoom.py} +2 -78
- ngio/hcs/__init__.py +60 -0
- ngio/images/__init__.py +23 -0
- ngio/images/abstract_image.py +240 -0
- ngio/images/create.py +251 -0
- ngio/images/image.py +383 -0
- ngio/images/label.py +96 -0
- ngio/images/omezarr_container.py +512 -0
- ngio/ome_zarr_meta/__init__.py +35 -0
- ngio/ome_zarr_meta/_generic_handlers.py +320 -0
- ngio/ome_zarr_meta/_meta_handlers.py +142 -0
- ngio/ome_zarr_meta/ngio_specs/__init__.py +63 -0
- ngio/ome_zarr_meta/ngio_specs/_axes.py +481 -0
- ngio/ome_zarr_meta/ngio_specs/_channels.py +378 -0
- ngio/ome_zarr_meta/ngio_specs/_dataset.py +134 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +5 -0
- ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +434 -0
- ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +84 -0
- ngio/ome_zarr_meta/v04/__init__.py +11 -0
- ngio/ome_zarr_meta/v04/_meta_handlers.py +54 -0
- ngio/ome_zarr_meta/v04/_v04_spec_utils.py +412 -0
- ngio/tables/__init__.py +21 -5
- ngio/tables/_validators.py +192 -0
- ngio/tables/backends/__init__.py +8 -0
- ngio/tables/backends/_abstract_backend.py +71 -0
- ngio/tables/backends/_anndata_utils.py +194 -0
- ngio/tables/backends/_anndata_v1.py +75 -0
- ngio/tables/backends/_json_v1.py +56 -0
- ngio/tables/backends/_table_backends.py +102 -0
- ngio/tables/tables_container.py +300 -0
- ngio/tables/v1/__init__.py +6 -5
- ngio/tables/v1/_feature_table.py +161 -0
- ngio/tables/v1/_generic_table.py +99 -182
- ngio/tables/v1/_masking_roi_table.py +175 -0
- ngio/tables/v1/_roi_table.py +226 -0
- ngio/utils/__init__.py +23 -10
- ngio/utils/_datasets.py +51 -0
- ngio/utils/_errors.py +10 -4
- ngio/utils/_zarr_utils.py +378 -0
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/METADATA +18 -39
- ngio-0.2.0a1.dist-info/RECORD +53 -0
- ngio/core/__init__.py +0 -7
- ngio/core/dimensions.py +0 -122
- ngio/core/image_handler.py +0 -228
- ngio/core/image_like_handler.py +0 -549
- ngio/core/label_handler.py +0 -410
- ngio/core/ngff_image.py +0 -387
- ngio/core/utils.py +0 -287
- ngio/io/__init__.py +0 -19
- ngio/io/_zarr.py +0 -88
- ngio/io/_zarr_array_utils.py +0 -0
- ngio/io/_zarr_group_utils.py +0 -60
- ngio/iterators/__init__.py +0 -1
- ngio/ngff_meta/__init__.py +0 -27
- ngio/ngff_meta/fractal_image_meta.py +0 -1267
- ngio/ngff_meta/meta_handler.py +0 -92
- ngio/ngff_meta/utils.py +0 -235
- ngio/ngff_meta/v04/__init__.py +0 -6
- ngio/ngff_meta/v04/specs.py +0 -158
- ngio/ngff_meta/v04/zarr_utils.py +0 -376
- ngio/pipes/__init__.py +0 -7
- ngio/pipes/_slicer_transforms.py +0 -176
- ngio/pipes/_transforms.py +0 -33
- ngio/pipes/data_pipe.py +0 -52
- ngio/tables/_ad_reader.py +0 -80
- ngio/tables/_utils.py +0 -301
- ngio/tables/tables_group.py +0 -252
- ngio/tables/v1/feature_tables.py +0 -182
- ngio/tables/v1/masking_roi_tables.py +0 -243
- ngio/tables/v1/roi_tables.py +0 -285
- ngio/utils/_common_types.py +0 -5
- ngio/utils/_pydantic_utils.py +0 -52
- ngio-0.1.6.dist-info/RECORD +0 -44
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/WHEEL +0 -0
- {ngio-0.1.6.dist-info → ngio-0.2.0a1.dist-info}/licenses/LICENSE +0 -0
ngio/core/image_like_handler.py
DELETED
|
@@ -1,549 +0,0 @@
|
|
|
1
|
-
"""Generic class to handle Image-like data in a OME-NGFF file."""
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Any, Literal
|
|
5
|
-
|
|
6
|
-
import dask.array as da
|
|
7
|
-
import numpy as np
|
|
8
|
-
import zarr
|
|
9
|
-
from dask.delayed import Delayed
|
|
10
|
-
|
|
11
|
-
from ngio.core.dimensions import Dimensions
|
|
12
|
-
from ngio.core.roi import WorldCooROI
|
|
13
|
-
from ngio.io import AccessModeLiteral, StoreOrGroup, open_group_wrapper
|
|
14
|
-
from ngio.ngff_meta import (
|
|
15
|
-
Dataset,
|
|
16
|
-
ImageLabelMeta,
|
|
17
|
-
PixelSize,
|
|
18
|
-
SpaceUnits,
|
|
19
|
-
get_ngff_image_meta_handler,
|
|
20
|
-
)
|
|
21
|
-
from ngio.pipes import DataTransformPipe, NaiveSlicer, RoiSlicer, on_disk_zoom
|
|
22
|
-
from ngio.utils import ngio_logger
|
|
23
|
-
from ngio.utils._common_types import ArrayLike
|
|
24
|
-
|
|
25
|
-
try:
|
|
26
|
-
from dask.distributed import Lock
|
|
27
|
-
except ImportError:
|
|
28
|
-
Lock = None # type: ignore
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class ImageLike:
|
|
32
|
-
"""A class to handle OME-NGFF images stored in Zarr format.
|
|
33
|
-
|
|
34
|
-
This class provides methods to access image data and ROI tables.
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
_virtual_pixel_size: PixelSize | None
|
|
38
|
-
|
|
39
|
-
def __init__(
|
|
40
|
-
self,
|
|
41
|
-
store: StoreOrGroup,
|
|
42
|
-
path: str | None = None,
|
|
43
|
-
idx: int | None = None,
|
|
44
|
-
pixel_size: PixelSize | None = None,
|
|
45
|
-
highest_resolution: bool = False,
|
|
46
|
-
strict: bool = True,
|
|
47
|
-
meta_mode: Literal["image", "label"] = "image",
|
|
48
|
-
cache: bool = True,
|
|
49
|
-
mode: AccessModeLiteral = "r+",
|
|
50
|
-
_label_group: Any = None,
|
|
51
|
-
) -> None:
|
|
52
|
-
"""Initialize the MultiscaleHandler in read mode.
|
|
53
|
-
|
|
54
|
-
Note: Only one of `path`, `idx`, 'pixel_size' or 'highest_resolution'
|
|
55
|
-
should be provided.
|
|
56
|
-
|
|
57
|
-
store (StoreOrGroup): The Zarr store or group containing the image data.
|
|
58
|
-
path (str | None): The path to the level.
|
|
59
|
-
idx (int | None): The index of the level.
|
|
60
|
-
pixel_size (PixelSize | None): The pixel size of the level.
|
|
61
|
-
highest_resolution (bool): Whether to get the highest resolution level.
|
|
62
|
-
strict (bool): Whether to raise an error where a pixel size is not found
|
|
63
|
-
to match the requested "pixel_size".
|
|
64
|
-
meta_mode (str): The mode of the metadata handler.
|
|
65
|
-
cache (bool): Whether to cache the metadata.
|
|
66
|
-
_label_group (LabelGroup): The group containing the label data (internal use).
|
|
67
|
-
"""
|
|
68
|
-
if not strict:
|
|
69
|
-
ngio_logger.warning("Strict mode is not fully supported yet.")
|
|
70
|
-
|
|
71
|
-
self._mode = mode
|
|
72
|
-
if not isinstance(store, zarr.Group):
|
|
73
|
-
store = open_group_wrapper(store=store, mode=self._mode)
|
|
74
|
-
|
|
75
|
-
self._group = store
|
|
76
|
-
|
|
77
|
-
self._metadata_handler = get_ngff_image_meta_handler(
|
|
78
|
-
store=store, meta_mode=meta_mode, cache=cache
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
# Find the level / resolution index
|
|
82
|
-
metadata = self._metadata_handler.load_meta()
|
|
83
|
-
dataset = metadata.get_dataset(
|
|
84
|
-
path=path,
|
|
85
|
-
idx=idx,
|
|
86
|
-
pixel_size=pixel_size,
|
|
87
|
-
highest_resolution=highest_resolution,
|
|
88
|
-
strict=strict,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
if pixel_size is not None:
|
|
92
|
-
pixel_size.virtual = True
|
|
93
|
-
self._virtual_pixel_size = pixel_size
|
|
94
|
-
else:
|
|
95
|
-
self._virtual_pixel_size = None
|
|
96
|
-
|
|
97
|
-
self._init_dataset(dataset)
|
|
98
|
-
self._dask_lock = None
|
|
99
|
-
|
|
100
|
-
self._label_group = _label_group
|
|
101
|
-
|
|
102
|
-
def _init_dataset(self, dataset: Dataset) -> None:
|
|
103
|
-
"""Set the dataset of the image.
|
|
104
|
-
|
|
105
|
-
This method is for internal use only.
|
|
106
|
-
"""
|
|
107
|
-
self._dataset = dataset
|
|
108
|
-
self._array = self._group.get(self._dataset.path, None)
|
|
109
|
-
|
|
110
|
-
if self._array is None:
|
|
111
|
-
raise ValueError(f"Dataset {self._dataset.path} not found in the group.")
|
|
112
|
-
|
|
113
|
-
self._diminesions = Dimensions(
|
|
114
|
-
on_disk_shape=self._array.shape,
|
|
115
|
-
axes_names=self._dataset.axes_names,
|
|
116
|
-
axes_order=self._dataset.axes_order,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
def _debug_set_new_dataset(
|
|
120
|
-
self,
|
|
121
|
-
new_dataset: Dataset,
|
|
122
|
-
) -> None:
|
|
123
|
-
"""Debug method to change the the dataset metadata.
|
|
124
|
-
|
|
125
|
-
This methods allow to change dataset after initialization.
|
|
126
|
-
This allow to skip the OME-NGFF metadata validation.
|
|
127
|
-
This method is for testing/debug purposes only.
|
|
128
|
-
|
|
129
|
-
DO NOT USE THIS METHOD IN PRODUCTION CODE.
|
|
130
|
-
"""
|
|
131
|
-
self._init_dataset(new_dataset)
|
|
132
|
-
|
|
133
|
-
# Method to get the metadata of the image
|
|
134
|
-
@property
|
|
135
|
-
def group(self) -> zarr.Group:
|
|
136
|
-
"""Return the Zarr group containing the image data."""
|
|
137
|
-
return self._group
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
def root_path(self) -> str:
|
|
141
|
-
"""Return the path to the root group."""
|
|
142
|
-
return str(self._group.store.path)
|
|
143
|
-
|
|
144
|
-
@property
|
|
145
|
-
def group_path(self) -> str:
|
|
146
|
-
"""Return the path to the group."""
|
|
147
|
-
root = self.root_path
|
|
148
|
-
if root.endswith("/"):
|
|
149
|
-
root = root[:-1]
|
|
150
|
-
return f"{root}/{self._group.path}"
|
|
151
|
-
|
|
152
|
-
@property
|
|
153
|
-
def array_path(self) -> str:
|
|
154
|
-
"""Return the path to the array."""
|
|
155
|
-
group = self.group_path
|
|
156
|
-
if group.endswith("/"):
|
|
157
|
-
group = group[:-1]
|
|
158
|
-
return f"{group}/{self.path}"
|
|
159
|
-
|
|
160
|
-
@property
|
|
161
|
-
def metadata(self) -> ImageLabelMeta:
|
|
162
|
-
"""Return the metadata of the image."""
|
|
163
|
-
return self._metadata_handler.load_meta()
|
|
164
|
-
|
|
165
|
-
@property
|
|
166
|
-
def dataset(self) -> Dataset:
|
|
167
|
-
"""Return the dataset of the image."""
|
|
168
|
-
return self._dataset
|
|
169
|
-
|
|
170
|
-
@property
|
|
171
|
-
def path(self) -> str:
|
|
172
|
-
"""Return the path of the dataset (relative to the root group)."""
|
|
173
|
-
return self.dataset.path
|
|
174
|
-
|
|
175
|
-
@property
|
|
176
|
-
def axes_names(self) -> list[str]:
|
|
177
|
-
"""Return the names of the axes in the image."""
|
|
178
|
-
return self.dataset.axes_names
|
|
179
|
-
|
|
180
|
-
@property
|
|
181
|
-
def space_axes_names(self) -> list[str]:
|
|
182
|
-
"""Return the names of the space axes in the image."""
|
|
183
|
-
return self.dataset.space_axes_names
|
|
184
|
-
|
|
185
|
-
@property
|
|
186
|
-
def space_axes_unit(self) -> SpaceUnits:
|
|
187
|
-
"""Return the units of the space axes in the image."""
|
|
188
|
-
return self.dataset.space_axes_unit
|
|
189
|
-
|
|
190
|
-
@property
|
|
191
|
-
def pixel_size(self) -> PixelSize:
|
|
192
|
-
"""Return the pixel resolution of the image."""
|
|
193
|
-
if self._virtual_pixel_size is not None:
|
|
194
|
-
return self._virtual_pixel_size
|
|
195
|
-
|
|
196
|
-
return self.dataset.pixel_size
|
|
197
|
-
|
|
198
|
-
# Utility methods to get the image dimensionality
|
|
199
|
-
@property
|
|
200
|
-
def dimensions(self) -> Dimensions:
|
|
201
|
-
"""Return an object representation the dimensions of the image."""
|
|
202
|
-
return self._diminesions
|
|
203
|
-
|
|
204
|
-
@property
|
|
205
|
-
def shape(self) -> tuple[int, ...]:
|
|
206
|
-
"""Return the shape of the image in canonical order (TCZYX)."""
|
|
207
|
-
return self.dimensions.shape
|
|
208
|
-
|
|
209
|
-
@property
|
|
210
|
-
def is_time_series(self) -> bool:
|
|
211
|
-
"""Return whether the image is a time series."""
|
|
212
|
-
return self.dimensions.is_time_series
|
|
213
|
-
|
|
214
|
-
@property
|
|
215
|
-
def is_2d(self) -> bool:
|
|
216
|
-
"""Return whether the image is 2D."""
|
|
217
|
-
return self.dimensions.is_2d
|
|
218
|
-
|
|
219
|
-
@property
|
|
220
|
-
def is_2d_time_series(self) -> bool:
|
|
221
|
-
"""Return whether the image is a 2D time series."""
|
|
222
|
-
return self.dimensions.is_2d_time_series
|
|
223
|
-
|
|
224
|
-
@property
|
|
225
|
-
def is_3d(self) -> bool:
|
|
226
|
-
"""Return whether the image is 3D."""
|
|
227
|
-
return self.dimensions.is_3d
|
|
228
|
-
|
|
229
|
-
@property
|
|
230
|
-
def is_3d_time_series(self) -> bool:
|
|
231
|
-
"""Return whether the image is a 3D time series."""
|
|
232
|
-
return self.dimensions.is_3d_time_series
|
|
233
|
-
|
|
234
|
-
@property
|
|
235
|
-
def is_multi_channels(self) -> bool:
|
|
236
|
-
"""Return whether the image has multiple channels."""
|
|
237
|
-
return self.dimensions.is_multi_channels
|
|
238
|
-
|
|
239
|
-
# Methods to get the image data as is on disk
|
|
240
|
-
@property
|
|
241
|
-
def on_disk_array(self) -> zarr.Array:
|
|
242
|
-
"""Return the image data as a Zarr array."""
|
|
243
|
-
return self._array
|
|
244
|
-
|
|
245
|
-
@property
|
|
246
|
-
def on_disk_dask_array(self) -> da.core.Array:
|
|
247
|
-
"""Return the image data as a Dask array."""
|
|
248
|
-
return da.from_zarr(self.on_disk_array) # type: ignore
|
|
249
|
-
|
|
250
|
-
@property
|
|
251
|
-
def on_disk_shape(self) -> tuple[int, ...]:
|
|
252
|
-
"""Return the shape of the image."""
|
|
253
|
-
return self.dimensions.on_disk_shape
|
|
254
|
-
|
|
255
|
-
def find_axis(self, axis_name: str) -> int | None:
|
|
256
|
-
"""Return the index of the given axis name."""
|
|
257
|
-
return self.dimensions.find_axis(axis_name)
|
|
258
|
-
|
|
259
|
-
# Methods to get the image data in the canonical order
|
|
260
|
-
def init_lock(self, lock_id: str | None = None) -> None:
|
|
261
|
-
"""Set the lock for the Dask array."""
|
|
262
|
-
if Lock is None:
|
|
263
|
-
raise ImportError(
|
|
264
|
-
"Lock is not available. Please install dask[distributed]."
|
|
265
|
-
)
|
|
266
|
-
# Unique zarr array identifier
|
|
267
|
-
array_path = (
|
|
268
|
-
Path(self._group.store.path) / self._group.path / self._dataset.path
|
|
269
|
-
)
|
|
270
|
-
lock_id = f"Zarr_IO_Lock_{array_path}" if lock_id is None else lock_id
|
|
271
|
-
self._dask_lock = Lock(lock_id)
|
|
272
|
-
|
|
273
|
-
def _get_pipe(
|
|
274
|
-
self,
|
|
275
|
-
data_pipe: DataTransformPipe,
|
|
276
|
-
mode: Literal["numpy", "dask"] = "numpy",
|
|
277
|
-
) -> ArrayLike:
|
|
278
|
-
"""Return the data transform pipe."""
|
|
279
|
-
if mode == "numpy":
|
|
280
|
-
return data_pipe.get(data=self.on_disk_array)
|
|
281
|
-
elif mode == "dask":
|
|
282
|
-
return data_pipe.get(data=self.on_disk_dask_array)
|
|
283
|
-
else:
|
|
284
|
-
raise ValueError(f"Invalid mode {mode}")
|
|
285
|
-
|
|
286
|
-
def _set_pipe(
|
|
287
|
-
self,
|
|
288
|
-
data_pipe: DataTransformPipe,
|
|
289
|
-
patch: ArrayLike,
|
|
290
|
-
) -> None:
|
|
291
|
-
"""Set the data transform pipe."""
|
|
292
|
-
if isinstance(patch, np.ndarray):
|
|
293
|
-
data_pipe.set(data=self.on_disk_array, patch=patch)
|
|
294
|
-
|
|
295
|
-
elif isinstance(patch, (da.core.Array, Delayed)): # noqa: UP038
|
|
296
|
-
if self._dask_lock is None:
|
|
297
|
-
return data_pipe.set(data=self.on_disk_array, patch=patch)
|
|
298
|
-
|
|
299
|
-
array = self.on_disk_array
|
|
300
|
-
with self._dask_lock:
|
|
301
|
-
data_pipe.set(data=array, patch=patch)
|
|
302
|
-
else:
|
|
303
|
-
raise ValueError(
|
|
304
|
-
f"Invalid patch type {type(patch)}. "
|
|
305
|
-
"Supported types are np.ndarray and da.core.Array"
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
def _build_roi_pipe(
|
|
309
|
-
self,
|
|
310
|
-
roi: WorldCooROI,
|
|
311
|
-
t: int | slice | None = None,
|
|
312
|
-
c: int | slice | None = None,
|
|
313
|
-
preserve_dimensions: bool = False,
|
|
314
|
-
) -> DataTransformPipe:
|
|
315
|
-
"""Build the data transform pipe for a region of interest (ROI)."""
|
|
316
|
-
roi_coo = roi.to_raster_coo(
|
|
317
|
-
pixel_size=self.dataset.pixel_size, dimensions=self.dimensions
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
slicer = RoiSlicer(
|
|
321
|
-
on_disk_axes_name=self.dataset.on_disk_axes_names,
|
|
322
|
-
axes_order=self.dataset.axes_order,
|
|
323
|
-
roi=roi_coo,
|
|
324
|
-
t=t,
|
|
325
|
-
c=c,
|
|
326
|
-
preserve_dimensions=preserve_dimensions,
|
|
327
|
-
)
|
|
328
|
-
return DataTransformPipe(slicer=slicer)
|
|
329
|
-
|
|
330
|
-
def _build_naive_pipe(
|
|
331
|
-
self,
|
|
332
|
-
x: int | slice | None = None,
|
|
333
|
-
y: int | slice | None = None,
|
|
334
|
-
z: int | slice | None = None,
|
|
335
|
-
t: int | slice | None = None,
|
|
336
|
-
c: int | slice | None = None,
|
|
337
|
-
preserve_dimensions: bool = False,
|
|
338
|
-
) -> DataTransformPipe:
|
|
339
|
-
"""Build the data transform pipe for a naive slice."""
|
|
340
|
-
slicer = NaiveSlicer(
|
|
341
|
-
on_disk_axes_name=self.dataset.on_disk_axes_names,
|
|
342
|
-
axes_order=self.dataset.axes_order,
|
|
343
|
-
x=x,
|
|
344
|
-
y=y,
|
|
345
|
-
z=z,
|
|
346
|
-
t=t,
|
|
347
|
-
c=c,
|
|
348
|
-
preserve_dimensions=preserve_dimensions,
|
|
349
|
-
)
|
|
350
|
-
return DataTransformPipe(slicer=slicer)
|
|
351
|
-
|
|
352
|
-
def _get_array_from_roi(
|
|
353
|
-
self,
|
|
354
|
-
roi: WorldCooROI,
|
|
355
|
-
t: int | slice | None = None,
|
|
356
|
-
c: int | slice | None = None,
|
|
357
|
-
mode: Literal["numpy", "dask"] = "numpy",
|
|
358
|
-
preserve_dimensions: bool = False,
|
|
359
|
-
) -> ArrayLike | tuple[ArrayLike, DataTransformPipe]:
|
|
360
|
-
"""Return the image data from a region of interest (ROI).
|
|
361
|
-
|
|
362
|
-
Args:
|
|
363
|
-
roi (WorldCooROI): The region of interest.
|
|
364
|
-
t (int | slice | None): The time index or slice.
|
|
365
|
-
c (int | slice | None): The channel index or slice.
|
|
366
|
-
mode (str): The mode to return the data.
|
|
367
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
368
|
-
"""
|
|
369
|
-
data_pipe = self._build_roi_pipe(
|
|
370
|
-
roi=roi, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
371
|
-
)
|
|
372
|
-
return_array = self._get_pipe(data_pipe=data_pipe, mode=mode)
|
|
373
|
-
return return_array
|
|
374
|
-
|
|
375
|
-
def _set_array_from_roi(
|
|
376
|
-
self,
|
|
377
|
-
patch: ArrayLike,
|
|
378
|
-
roi: WorldCooROI,
|
|
379
|
-
t: int | slice | None = None,
|
|
380
|
-
c: int | slice | None = None,
|
|
381
|
-
preserve_dimensions: bool = False,
|
|
382
|
-
) -> None:
|
|
383
|
-
"""Set the image data from a region of interest (ROI).
|
|
384
|
-
|
|
385
|
-
Args:
|
|
386
|
-
patch (ArrayLike): The patch to set.
|
|
387
|
-
roi (WorldCooROI): The region of interest.
|
|
388
|
-
t (int | slice | None): The time index or slice.
|
|
389
|
-
c (int | slice | None): The channel index or slice.
|
|
390
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
391
|
-
"""
|
|
392
|
-
data_pipe = self._build_roi_pipe(
|
|
393
|
-
roi=roi, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
394
|
-
)
|
|
395
|
-
self._set_pipe(data_pipe=data_pipe, patch=patch)
|
|
396
|
-
|
|
397
|
-
def _get_array(
|
|
398
|
-
self,
|
|
399
|
-
x: int | slice | None = None,
|
|
400
|
-
y: int | slice | None = None,
|
|
401
|
-
z: int | slice | None = None,
|
|
402
|
-
t: int | slice | None = None,
|
|
403
|
-
c: int | slice | None = None,
|
|
404
|
-
mode: Literal["numpy", "dask"] = "numpy",
|
|
405
|
-
preserve_dimensions: bool = False,
|
|
406
|
-
) -> ArrayLike:
|
|
407
|
-
"""Return the image data.
|
|
408
|
-
|
|
409
|
-
Args:
|
|
410
|
-
x (int | slice | None): The x index or slice.
|
|
411
|
-
y (int | slice | None): The y index or slice.
|
|
412
|
-
z (int | slice | None): The z index or slice.
|
|
413
|
-
t (int | slice | None): The time index or slice.
|
|
414
|
-
c (int | slice | None): The channel index or slice.
|
|
415
|
-
mode (str): The mode to return the data.
|
|
416
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
417
|
-
"""
|
|
418
|
-
data_pipe = self._build_naive_pipe(
|
|
419
|
-
x=x, y=y, z=z, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
420
|
-
)
|
|
421
|
-
return self._get_pipe(data_pipe=data_pipe, mode=mode)
|
|
422
|
-
|
|
423
|
-
def _set_array(
|
|
424
|
-
self,
|
|
425
|
-
patch: ArrayLike,
|
|
426
|
-
x: int | slice | None = None,
|
|
427
|
-
y: int | slice | None = None,
|
|
428
|
-
z: int | slice | None = None,
|
|
429
|
-
t: int | slice | None = None,
|
|
430
|
-
c: int | slice | None = None,
|
|
431
|
-
preserve_dimensions: bool = False,
|
|
432
|
-
) -> None:
|
|
433
|
-
"""Set the image data in the zarr array.
|
|
434
|
-
|
|
435
|
-
Args:
|
|
436
|
-
patch (ArrayLike): The patch to set.
|
|
437
|
-
x (int | slice | None): The x index or slice.
|
|
438
|
-
y (int | slice | None): The y index or slice.
|
|
439
|
-
z (int | slice | None): The z index or slice.
|
|
440
|
-
t (int | slice | None): The time index or slice.
|
|
441
|
-
c (int | slice | None): The channel index or slice.
|
|
442
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
443
|
-
"""
|
|
444
|
-
data_pipe = self._build_naive_pipe(
|
|
445
|
-
x=x, y=y, z=z, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
446
|
-
)
|
|
447
|
-
self._set_pipe(data_pipe=data_pipe, patch=patch)
|
|
448
|
-
|
|
449
|
-
def _get_array_masked(
|
|
450
|
-
self,
|
|
451
|
-
roi: WorldCooROI,
|
|
452
|
-
t: int | slice | None = None,
|
|
453
|
-
c: int | slice | None = None,
|
|
454
|
-
mask_mode: Literal["bbox", "mask"] = "bbox",
|
|
455
|
-
mode: Literal["numpy"] = "numpy",
|
|
456
|
-
preserve_dimensions: bool = False,
|
|
457
|
-
) -> ArrayLike:
|
|
458
|
-
"""Return the image data from a region of interest (ROI).
|
|
459
|
-
|
|
460
|
-
Args:
|
|
461
|
-
roi (WorldCooROI): The region of interest.
|
|
462
|
-
t (int | slice | None): The time index or slice.
|
|
463
|
-
c (int | slice | None): The channel index or slice.
|
|
464
|
-
mask_mode (str): Masking mode
|
|
465
|
-
mode (str): The mode to return the data.
|
|
466
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
467
|
-
"""
|
|
468
|
-
label_name = roi.infos.get("label_name", None)
|
|
469
|
-
if label_name is None:
|
|
470
|
-
raise ValueError("The label name must be provided in the ROI infos.")
|
|
471
|
-
|
|
472
|
-
data_pipe = self._build_roi_pipe(
|
|
473
|
-
roi=roi, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
474
|
-
)
|
|
475
|
-
|
|
476
|
-
if mask_mode == "bbox":
|
|
477
|
-
return self._get_pipe(data_pipe=data_pipe, mode=mode)
|
|
478
|
-
|
|
479
|
-
label = self._label_group.get_label(label_name, pixel_size=self.pixel_size)
|
|
480
|
-
|
|
481
|
-
mask = label.mask(
|
|
482
|
-
roi,
|
|
483
|
-
t=t,
|
|
484
|
-
mode=mode,
|
|
485
|
-
)
|
|
486
|
-
array = self._get_pipe(data_pipe=data_pipe, mode=mode)
|
|
487
|
-
where_func = np.where if mode == "numpy" else da.where
|
|
488
|
-
return where_func(mask, array, 0)
|
|
489
|
-
|
|
490
|
-
def _set_array_masked(
|
|
491
|
-
self,
|
|
492
|
-
patch: ArrayLike,
|
|
493
|
-
roi: WorldCooROI,
|
|
494
|
-
t: int | slice | None = None,
|
|
495
|
-
c: int | slice | None = None,
|
|
496
|
-
preserve_dimensions: bool = False,
|
|
497
|
-
) -> None:
|
|
498
|
-
"""Set the image data from a region of interest (ROI).
|
|
499
|
-
|
|
500
|
-
Args:
|
|
501
|
-
patch (ArrayLike): The patch to set.
|
|
502
|
-
roi (WorldCooROI): The region of interest.
|
|
503
|
-
t (int | slice | None): The time index or slice.
|
|
504
|
-
c (int | slice | None): The channel index or slice.
|
|
505
|
-
preserve_dimensions (bool): Whether to preserve the dimensions of the data.
|
|
506
|
-
"""
|
|
507
|
-
data_pipe = self._build_roi_pipe(
|
|
508
|
-
roi=roi, t=t, c=c, preserve_dimensions=preserve_dimensions
|
|
509
|
-
)
|
|
510
|
-
self._set_pipe(data_pipe=data_pipe, patch=patch)
|
|
511
|
-
|
|
512
|
-
def _consolidate(self, order: Literal[0, 1, 2] = 1) -> None:
|
|
513
|
-
"""Consolidate the Zarr array."""
|
|
514
|
-
processed_paths = [self]
|
|
515
|
-
|
|
516
|
-
todo_image = [
|
|
517
|
-
ImageLike(store=self.group, path=_path)
|
|
518
|
-
for _path in self.metadata.levels_paths
|
|
519
|
-
if _path != self.path
|
|
520
|
-
]
|
|
521
|
-
|
|
522
|
-
while todo_image:
|
|
523
|
-
dist_matrix = np.zeros((len(processed_paths), len(todo_image)))
|
|
524
|
-
for i, image in enumerate(todo_image):
|
|
525
|
-
for j, processed_image in enumerate(processed_paths):
|
|
526
|
-
dist_matrix[j, i] = np.sqrt(
|
|
527
|
-
np.sum(
|
|
528
|
-
[
|
|
529
|
-
(s1 - s2) ** 2
|
|
530
|
-
for s1, s2 in zip(
|
|
531
|
-
image.shape, processed_image.shape, strict=False
|
|
532
|
-
)
|
|
533
|
-
]
|
|
534
|
-
)
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
source, target = np.unravel_index(dist_matrix.argmin(), dist_matrix.shape)
|
|
538
|
-
|
|
539
|
-
source_image = processed_paths[source]
|
|
540
|
-
target_image = todo_image.pop(target)
|
|
541
|
-
|
|
542
|
-
on_disk_zoom(
|
|
543
|
-
source=source_image.on_disk_array,
|
|
544
|
-
target=target_image.on_disk_array,
|
|
545
|
-
order=order,
|
|
546
|
-
)
|
|
547
|
-
|
|
548
|
-
# compute the transformation
|
|
549
|
-
processed_paths.append(target_image)
|