ngio 0.2.0a1__tar.gz → 0.2.0a2__tar.gz
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-0.2.0a1 → ngio-0.2.0a2}/PKG-INFO +1 -1
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/notebooks/image.ipynb +67 -58
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/notebooks/processing.ipynb +34 -34
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_pyramid.py +1 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/images/image.py +8 -2
- ngio-0.2.0a2/src/ngio/images/label.py +236 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/images/omezarr_container.py +27 -4
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/utils/_datasets.py +1 -1
- ngio-0.2.0a1/src/ngio/images/label.py +0 -96
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.copier-answers.yml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.gitattributes +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.github/ISSUE_TEMPLATE.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.github/TEST_FAIL_TEMPLATE.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.github/dependabot.yml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.github/workflows/build_docs.yml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.github/workflows/ci.yml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.gitignore +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/.pre-commit-config.yaml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/LICENSE +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/README.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/_typos.toml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/api/core.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/getting-started.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/index.md +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/docs/notebooks/basic_usage.ipynb +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/mkdocs.yml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/pyproject.toml +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_array_pipe.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_axes_transforms.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_common_types.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_dimensions.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_roi.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_slicer.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/common/_zoom.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/hcs/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/images/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/images/abstract_image.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/images/create.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/_generic_handlers.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/_meta_handlers.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_axes.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_channels.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_dataset.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/v04/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/ome_zarr_meta/v04/_v04_spec_utils.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/_validators.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/_abstract_backend.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/_anndata_utils.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/_anndata_v1.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/_json_v1.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/backends/_table_backends.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/tables_container.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/v1/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/v1/_feature_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/v1/_generic_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/v1/_masking_roi_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/tables/v1/_roi_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/utils/__init__.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/utils/_errors.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/utils/_logger.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/src/ngio/utils/_zarr_utils.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/conftest.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/data/meta_v04/base_ome_zarr_image_meta.json +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/data/meta_v04/base_ome_zarr_image_meta_wrong_axis_order.json +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/data/meta_v04/base_ome_zarr_label_meta.json +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/common/test_dimensions.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/common/test_pyramid.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/common/test_roi.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/images/test_omezarr_container.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_backends.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_feature_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_generic_table.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_masking_roi_table_v1.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_roi_table_v1.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_table_group.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/tables/test_validators.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/test_ome_zarr_meta/test_image_handler.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/test_ome_zarr_meta/test_unit_ngio_specs.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/test_ome_zarr_meta/test_unit_v04_utils.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/utils/test_download_datasets.py +0 -0
- {ngio-0.2.0a1 → ngio-0.2.0a2}/tests/unit/utils/test_zarr_utils.py +0 -0
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"source": [
|
|
18
18
|
"import matplotlib.pyplot as plt\n",
|
|
19
19
|
"\n",
|
|
20
|
-
"from ngio
|
|
20
|
+
"from ngio import open_omezarr_container\n",
|
|
21
21
|
"from ngio.utils import download_ome_zarr_dataset\n",
|
|
22
22
|
"\n",
|
|
23
23
|
"hcs_path = download_ome_zarr_dataset(\"CardiomyocyteSmallMip\")\n",
|
|
24
24
|
"image_path = hcs_path / \"B\" / \"03\" / \"0\"\n",
|
|
25
|
-
"
|
|
25
|
+
"omezarr = open_omezarr_container(image_path)"
|
|
26
26
|
]
|
|
27
27
|
},
|
|
28
28
|
{
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"source": [
|
|
32
32
|
"## Images\n",
|
|
33
33
|
"\n",
|
|
34
|
-
"Images can be loaded from a `
|
|
34
|
+
"Images can be loaded from a `OmeZarrContainer` object."
|
|
35
35
|
]
|
|
36
36
|
},
|
|
37
37
|
{
|
|
@@ -40,11 +40,10 @@
|
|
|
40
40
|
"metadata": {},
|
|
41
41
|
"outputs": [],
|
|
42
42
|
"source": [
|
|
43
|
-
"image =
|
|
43
|
+
"image = omezarr.get_image()\n",
|
|
44
44
|
"\n",
|
|
45
45
|
"print(\"Image information:\")\n",
|
|
46
46
|
"print(f\"{image.shape=}\")\n",
|
|
47
|
-
"print(f\"{image.axes_names=}\")\n",
|
|
48
47
|
"print(f\"{image.pixel_size=}\")\n",
|
|
49
48
|
"print(f\"{image.channel_labels=}\")\n",
|
|
50
49
|
"print(f\"{image.dimensions=}\")"
|
|
@@ -71,18 +70,14 @@
|
|
|
71
70
|
"metadata": {},
|
|
72
71
|
"outputs": [],
|
|
73
72
|
"source": [
|
|
74
|
-
"#
|
|
75
|
-
"dask_array = image.on_disk_dask_array\n",
|
|
76
|
-
"dask_array"
|
|
73
|
+
"image.get_array(mode=\"dask\") # this call is lazy"
|
|
77
74
|
]
|
|
78
75
|
},
|
|
79
76
|
{
|
|
80
77
|
"cell_type": "markdown",
|
|
81
78
|
"metadata": {},
|
|
82
79
|
"source": [
|
|
83
|
-
"
|
|
84
|
-
"\n",
|
|
85
|
-
"Since in principle the images can have different axes order. A safer way to access the image data is to use the `.get_array()` method, which will return the image data in canonical order (TCZYX)."
|
|
80
|
+
"Images can be queried for any axes, in any order"
|
|
86
81
|
]
|
|
87
82
|
},
|
|
88
83
|
{
|
|
@@ -91,11 +86,13 @@
|
|
|
91
86
|
"metadata": {},
|
|
92
87
|
"outputs": [],
|
|
93
88
|
"source": [
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
89
|
+
"print(\"On disk shape: \", image.shape)\n",
|
|
90
|
+
"\n",
|
|
91
|
+
"# Axes order can be specified\n",
|
|
92
|
+
"# if an axis is not present in the array, it will be added as a singleton dimension\n",
|
|
93
|
+
"array = image.get_array(axes_order=[\"x\", \"t\", \"c\", \"y\", \"z\"], mode=\"dask\")\n",
|
|
97
94
|
"\n",
|
|
98
|
-
"print(
|
|
95
|
+
"print(\"Array shape: \", array.shape)"
|
|
99
96
|
]
|
|
100
97
|
},
|
|
101
98
|
{
|
|
@@ -113,13 +110,14 @@
|
|
|
113
110
|
"metadata": {},
|
|
114
111
|
"outputs": [],
|
|
115
112
|
"source": [
|
|
116
|
-
"roi_table =
|
|
117
|
-
"roi
|
|
113
|
+
"roi_table = omezarr.get_table(\"FOV_ROI_table\", check_type=\"roi_table\")\n",
|
|
114
|
+
"# Get a roi by name\n",
|
|
115
|
+
"roi = roi_table.get(\"FOV_1\")\n",
|
|
118
116
|
"print(f\"{roi=}\")\n",
|
|
119
117
|
"\n",
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
")\n",
|
|
118
|
+
"# .get_roi works exactly like .get_array\n",
|
|
119
|
+
"# the only difference is that x, y, z, axes are queried from the roi object\n",
|
|
120
|
+
"image_roi_1 = image.get_roi(roi=roi, c=0, mode=\"dask\")\n",
|
|
123
121
|
"image_roi_1"
|
|
124
122
|
]
|
|
125
123
|
},
|
|
@@ -136,21 +134,21 @@
|
|
|
136
134
|
"metadata": {},
|
|
137
135
|
"outputs": [],
|
|
138
136
|
"source": [
|
|
139
|
-
"image_2 =
|
|
137
|
+
"image_2 = omezarr.get_image(path=\"2\")\n",
|
|
140
138
|
"# Two images at different resolutions\n",
|
|
141
139
|
"print(f\"{image.pixel_size=}\")\n",
|
|
142
140
|
"print(f\"{image_2.pixel_size=}\")\n",
|
|
143
141
|
"\n",
|
|
144
142
|
"# Get roi for higher resolution image\n",
|
|
145
|
-
"image_1_roi_1 = image.
|
|
143
|
+
"image_1_roi_1 = image.get_roi(roi=roi, c=0, mode=\"dask\")\n",
|
|
146
144
|
"\n",
|
|
147
145
|
"# Get roi for lower resolution image\n",
|
|
148
|
-
"image_2_roi_1 = image_2.
|
|
146
|
+
"image_2_roi_1 = image_2.get_roi(roi=roi, c=0, mode=\"dask\")\n",
|
|
149
147
|
"\n",
|
|
150
148
|
"# Plot the two images side by side\n",
|
|
151
149
|
"fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
|
|
152
|
-
"axs[0].imshow(image_1_roi_1[0], cmap=\"gray\")\n",
|
|
153
|
-
"axs[1].imshow(image_2_roi_1[0], cmap=\"gray\")\n",
|
|
150
|
+
"axs[0].imshow(image_1_roi_1[0, 0], cmap=\"gray\")\n",
|
|
151
|
+
"axs[1].imshow(image_2_roi_1[0, 0], cmap=\"gray\")\n",
|
|
154
152
|
"plt.show()"
|
|
155
153
|
]
|
|
156
154
|
},
|
|
@@ -180,17 +178,26 @@
|
|
|
180
178
|
"\n",
|
|
181
179
|
"\n",
|
|
182
180
|
"# Load the image from disk and show the edited image\n",
|
|
183
|
-
"nuclei =
|
|
181
|
+
"nuclei = omezarr.get_label(\"nuclei\", path=\"0\")\n",
|
|
184
182
|
"fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
|
|
185
|
-
"
|
|
186
|
-
"axs[
|
|
183
|
+
"\n",
|
|
184
|
+
"axs[0].imshow(image.get_array()[0, 0], cmap=\"gray\")\n",
|
|
185
|
+
"axs[1].imshow(nuclei.get_array()[0])\n",
|
|
187
186
|
"for ax in axs:\n",
|
|
188
187
|
" ax.axis(\"off\")\n",
|
|
189
188
|
"plt.tight_layout()\n",
|
|
190
189
|
"plt.show()\n",
|
|
191
190
|
"\n",
|
|
192
191
|
"# Add back the original slice to the image\n",
|
|
193
|
-
"image.set_array(patch=small_slice, x=slice(1000, 2000), y=slice(1000, 2000))"
|
|
192
|
+
"image.set_array(patch=small_slice, x=slice(1000, 2000), y=slice(1000, 2000))\n",
|
|
193
|
+
"\n",
|
|
194
|
+
"fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
|
|
195
|
+
"axs[0].imshow(image.get_array()[0, 0], cmap=\"gray\")\n",
|
|
196
|
+
"axs[1].imshow(nuclei.get_array()[0])\n",
|
|
197
|
+
"for ax in axs:\n",
|
|
198
|
+
" ax.axis(\"off\")\n",
|
|
199
|
+
"plt.tight_layout()\n",
|
|
200
|
+
"plt.show()"
|
|
194
201
|
]
|
|
195
202
|
},
|
|
196
203
|
{
|
|
@@ -209,15 +216,16 @@
|
|
|
209
216
|
"outputs": [],
|
|
210
217
|
"source": [
|
|
211
218
|
"# Create a a new label object and set it to a simple segmentation\n",
|
|
212
|
-
"new_label =
|
|
219
|
+
"new_label = omezarr.derive_label(\"new_label_2\", overwrite=True)\n",
|
|
213
220
|
"\n",
|
|
214
|
-
"simple_segmentation = image.
|
|
215
|
-
"
|
|
221
|
+
"simple_segmentation = image.get_array(c=0) > 100\n",
|
|
222
|
+
"simple_segmentation = simple_segmentation[0]\n",
|
|
223
|
+
"new_label.set_array(simple_segmentation)\n",
|
|
216
224
|
"\n",
|
|
217
225
|
"# make a subplot with two image show side by side\n",
|
|
218
226
|
"fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
|
|
219
|
-
"axs[0].imshow(image.
|
|
220
|
-
"axs[1].imshow(new_label.
|
|
227
|
+
"axs[0].imshow(image.get_array()[0, 0], cmap=\"gray\")\n",
|
|
228
|
+
"axs[1].imshow(new_label.get_array()[0], cmap=\"gray\")\n",
|
|
221
229
|
"for ax in axs:\n",
|
|
222
230
|
" ax.axis(\"off\")\n",
|
|
223
231
|
"plt.tight_layout()\n",
|
|
@@ -241,15 +249,15 @@
|
|
|
241
249
|
"metadata": {},
|
|
242
250
|
"outputs": [],
|
|
243
251
|
"source": [
|
|
244
|
-
"label_0 =
|
|
245
|
-
"label_2 =
|
|
252
|
+
"label_0 = omezarr.get_label(\"new_label\", path=\"0\")\n",
|
|
253
|
+
"label_2 = omezarr.get_label(\"new_label\", path=\"2\")\n",
|
|
246
254
|
"\n",
|
|
247
|
-
"label_before_consolidation = label_2.
|
|
255
|
+
"label_before_consolidation = label_2.zarr_array[...]\n",
|
|
248
256
|
"\n",
|
|
249
257
|
"# Consolidate the label\n",
|
|
250
258
|
"label_0.consolidate()\n",
|
|
251
259
|
"\n",
|
|
252
|
-
"label_after_consolidation = label_2.
|
|
260
|
+
"label_after_consolidation = label_2.zarr_array[...]\n",
|
|
253
261
|
"\n",
|
|
254
262
|
"\n",
|
|
255
263
|
"# make a subplot with two image show side by side\n",
|
|
@@ -281,42 +289,43 @@
|
|
|
281
289
|
"import numpy as np\n",
|
|
282
290
|
"import pandas as pd\n",
|
|
283
291
|
"\n",
|
|
284
|
-
"
|
|
292
|
+
"from ngio.tables import FeatureTable\n",
|
|
293
|
+
"\n",
|
|
294
|
+
"print(f\"List of all tables: {omezarr.list_tables()}\")\n",
|
|
285
295
|
"\n",
|
|
286
296
|
"\n",
|
|
287
|
-
"nuclei =
|
|
297
|
+
"nuclei = omezarr.get_label(\"nuclei\", path=\"0\")\n",
|
|
298
|
+
"roi_table = omezarr.get_table(\"FOV_ROI_table\", check_type=\"roi_table\")\n",
|
|
288
299
|
"\n",
|
|
289
300
|
"# Create a table with random features for each nuclei in each ROI\n",
|
|
290
301
|
"list_of_records = []\n",
|
|
291
|
-
"for roi in roi_table.rois:\n",
|
|
292
|
-
" nuclei_in_roi = nuclei.
|
|
302
|
+
"for roi in roi_table.rois():\n",
|
|
303
|
+
" nuclei_in_roi = nuclei.get_roi(roi, mode=\"numpy\")\n",
|
|
293
304
|
" for nuclei_id in np.unique(nuclei_in_roi)[1:]:\n",
|
|
294
305
|
" list_of_records.append(\n",
|
|
295
306
|
" {\n",
|
|
296
307
|
" \"label\": nuclei_id,\n",
|
|
297
308
|
" \"feat1\": np.random.rand(),\n",
|
|
298
309
|
" \"feat2\": np.random.rand(),\n",
|
|
299
|
-
" \"ROI\": roi.
|
|
310
|
+
" \"ROI\": roi.name,\n",
|
|
300
311
|
" }\n",
|
|
301
312
|
" )\n",
|
|
302
313
|
"\n",
|
|
303
314
|
"feat_df = pd.DataFrame.from_records(list_of_records)\n",
|
|
304
315
|
"\n",
|
|
305
|
-
"
|
|
306
|
-
"
|
|
307
|
-
"
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
"feat_table.
|
|
317
|
-
"feat_table.
|
|
318
|
-
"\n",
|
|
319
|
-
"feat_table.table"
|
|
316
|
+
"feat_table = FeatureTable(feat_df, reference_label=\"nuclei\")\n",
|
|
317
|
+
"\n",
|
|
318
|
+
"omezarr.add_table(\"new_feature_table\", feat_table, overwrite=True)"
|
|
319
|
+
]
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"cell_type": "code",
|
|
323
|
+
"execution_count": null,
|
|
324
|
+
"metadata": {},
|
|
325
|
+
"outputs": [],
|
|
326
|
+
"source": [
|
|
327
|
+
"feat_table = omezarr.get_table(\"new_feature_table\")\n",
|
|
328
|
+
"feat_table.dataframe"
|
|
320
329
|
]
|
|
321
330
|
},
|
|
322
331
|
{
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"source": [
|
|
36
36
|
"import matplotlib.pyplot as plt\n",
|
|
37
37
|
"\n",
|
|
38
|
-
"from ngio
|
|
38
|
+
"from ngio import open_omezarr_container\n",
|
|
39
39
|
"from ngio.utils import download_ome_zarr_dataset\n",
|
|
40
40
|
"\n",
|
|
41
41
|
"hcs_path = download_ome_zarr_dataset(\"CardiomyocyteTiny\")\n",
|
|
42
42
|
"image_path = hcs_path / \"B\" / \"03\" / \"0\"\n",
|
|
43
|
-
"
|
|
43
|
+
"omezarr = open_omezarr_container(image_path)"
|
|
44
44
|
]
|
|
45
45
|
},
|
|
46
46
|
{
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"metadata": {},
|
|
57
57
|
"outputs": [],
|
|
58
58
|
"source": [
|
|
59
|
-
"
|
|
59
|
+
"mip_omezarr = omezarr.derive_image(\n",
|
|
60
60
|
" \"data/20200812-CardiomyocyteDifferentiation14-Cycle1.zarr/B/03/0_mip\",\n",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
61
|
+
" shape=(1, 1, 2160, 5120),\n",
|
|
62
|
+
" overwrite=True,\n",
|
|
63
63
|
")"
|
|
64
64
|
]
|
|
65
65
|
},
|
|
@@ -78,32 +78,32 @@
|
|
|
78
78
|
"outputs": [],
|
|
79
79
|
"source": [
|
|
80
80
|
"# Get the source imag\n",
|
|
81
|
-
"source_image =
|
|
81
|
+
"source_image = omezarr.get_image()\n",
|
|
82
82
|
"print(\"Source image loaded with shape:\", source_image.shape)\n",
|
|
83
83
|
"\n",
|
|
84
84
|
"# Get the MIP image\n",
|
|
85
|
-
"mip_image =
|
|
85
|
+
"mip_image = mip_omezarr.get_image()\n",
|
|
86
86
|
"print(\"MIP image loaded with shape:\", mip_image.shape)\n",
|
|
87
87
|
"\n",
|
|
88
88
|
"# Get a ROI table\n",
|
|
89
|
-
"roi_table =
|
|
90
|
-
"print(\"ROI table loaded with\", len(roi_table.rois), \"ROIs\")\n",
|
|
89
|
+
"roi_table = omezarr.get_table(\"FOV_ROI_table\", check_type=\"roi_table\")\n",
|
|
90
|
+
"print(\"ROI table loaded with\", len(roi_table.rois()), \"ROIs\")\n",
|
|
91
91
|
"\n",
|
|
92
92
|
"# For each ROI in the table\n",
|
|
93
93
|
"# - get the data from the source image\n",
|
|
94
94
|
"# - calculate the MIP\n",
|
|
95
95
|
"# - set the data in the MIP image\n",
|
|
96
|
-
"for roi in roi_table.rois:\n",
|
|
97
|
-
" print(f\" - Processing ROI {roi.
|
|
98
|
-
" patch = source_image.
|
|
96
|
+
"for roi in roi_table.rois():\n",
|
|
97
|
+
" print(f\" - Processing ROI {roi.name}\")\n",
|
|
98
|
+
" patch = source_image.get_roi(roi)\n",
|
|
99
99
|
" mip_patch = patch.max(axis=1, keepdims=True)\n",
|
|
100
|
-
" mip_image.
|
|
100
|
+
" mip_image.set_roi(patch=mip_patch, roi=roi)\n",
|
|
101
101
|
"\n",
|
|
102
102
|
"print(\"MIP image saved\")\n",
|
|
103
103
|
"\n",
|
|
104
104
|
"plt.figure(figsize=(5, 5))\n",
|
|
105
105
|
"plt.title(\"Mip\")\n",
|
|
106
|
-
"plt.imshow(mip_image.
|
|
106
|
+
"plt.imshow(mip_image.zarr_array[0, 0, :, :], cmap=\"gray\")\n",
|
|
107
107
|
"plt.axis(\"off\")\n",
|
|
108
108
|
"plt.tight_layout()\n",
|
|
109
109
|
"plt.show()"
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"outputs": [],
|
|
127
127
|
"source": [
|
|
128
128
|
"# Get the MIP image at a lower resolution\n",
|
|
129
|
-
"mip_image_2 =
|
|
129
|
+
"mip_image_2 = mip_omezarr.get_image(path=\"2\")\n",
|
|
130
130
|
"\n",
|
|
131
131
|
"image_before_consolidation = mip_image_2.get_array(c=0, z=0)\n",
|
|
132
132
|
"\n",
|
|
@@ -137,9 +137,9 @@
|
|
|
137
137
|
"\n",
|
|
138
138
|
"fig, axs = plt.subplots(2, 1, figsize=(10, 5))\n",
|
|
139
139
|
"axs[0].set_title(\"Before consolidation\")\n",
|
|
140
|
-
"axs[0].imshow(image_before_consolidation, cmap=\"gray\")\n",
|
|
140
|
+
"axs[0].imshow(image_before_consolidation[0, 0], cmap=\"gray\")\n",
|
|
141
141
|
"axs[1].set_title(\"After consolidation\")\n",
|
|
142
|
-
"axs[1].imshow(image_after_consolidation, cmap=\"gray\")\n",
|
|
142
|
+
"axs[1].imshow(image_after_consolidation[0, 0], cmap=\"gray\")\n",
|
|
143
143
|
"for ax in axs:\n",
|
|
144
144
|
" ax.axis(\"off\")\n",
|
|
145
145
|
"plt.tight_layout()\n",
|
|
@@ -162,18 +162,17 @@
|
|
|
162
162
|
"metadata": {},
|
|
163
163
|
"outputs": [],
|
|
164
164
|
"source": [
|
|
165
|
-
"
|
|
165
|
+
"from ngio.tables import RoiTable\n",
|
|
166
166
|
"\n",
|
|
167
167
|
"roi_list = []\n",
|
|
168
|
-
"for roi in roi_table.rois:\n",
|
|
169
|
-
" print(f\" - Processing ROI {roi.
|
|
168
|
+
"for roi in roi_table.rois():\n",
|
|
169
|
+
" print(f\" - Processing ROI {roi.name}\")\n",
|
|
170
170
|
" roi.z_length = 1 # In the MIP image, the z dimension is 1\n",
|
|
171
171
|
" roi_list.append(roi)\n",
|
|
172
172
|
"\n",
|
|
173
|
-
"mip_roi_table
|
|
174
|
-
"mip_roi_table.consolidate()\n",
|
|
173
|
+
"mip_roi_table = RoiTable(rois=roi_list)\n",
|
|
175
174
|
"\n",
|
|
176
|
-
"
|
|
175
|
+
"mip_omezarr.add_table(\"FOV_ROI_table\", mip_roi_table)"
|
|
177
176
|
]
|
|
178
177
|
},
|
|
179
178
|
{
|
|
@@ -226,7 +225,7 @@
|
|
|
226
225
|
"metadata": {},
|
|
227
226
|
"outputs": [],
|
|
228
227
|
"source": [
|
|
229
|
-
"nuclei_image =
|
|
228
|
+
"nuclei_image = mip_omezarr.derive_label(name=\"nuclei\", overwrite=True)"
|
|
230
229
|
]
|
|
231
230
|
},
|
|
232
231
|
{
|
|
@@ -243,30 +242,31 @@
|
|
|
243
242
|
"outputs": [],
|
|
244
243
|
"source": [
|
|
245
244
|
"# Get the source imag\n",
|
|
246
|
-
"source_image =
|
|
245
|
+
"source_image = mip_omezarr.get_image()\n",
|
|
247
246
|
"print(\"Source image loaded with shape:\", source_image.shape)\n",
|
|
248
247
|
"\n",
|
|
249
248
|
"# Get a ROI table\n",
|
|
250
|
-
"roi_table =
|
|
251
|
-
"print(\"ROI table loaded with\", len(roi_table.rois), \"ROIs\")\n",
|
|
249
|
+
"roi_table = mip_omezarr.get_table(\"FOV_ROI_table\", check_type=\"roi_table\")\n",
|
|
250
|
+
"print(\"ROI table loaded with\", len(roi_table.rois()), \"ROIs\")\n",
|
|
252
251
|
"\n",
|
|
253
252
|
"# Find the DAPI channel\n",
|
|
254
|
-
"dapi_idx = source_image.
|
|
253
|
+
"dapi_idx = source_image.channel_labels.index(\"DAPI\")\n",
|
|
255
254
|
"\n",
|
|
256
255
|
"# For each ROI in the table\n",
|
|
257
256
|
"# - get the data from the source image\n",
|
|
258
257
|
"# - calculate the Segmentation\n",
|
|
259
258
|
"# - set the data in segmentation image\n",
|
|
260
259
|
"max_label = 0\n",
|
|
261
|
-
"for roi in roi_table.rois:\n",
|
|
262
|
-
" print(f\" - Processing ROI {roi.
|
|
263
|
-
" patch = source_image.
|
|
260
|
+
"for roi in roi_table.rois():\n",
|
|
261
|
+
" print(f\" - Processing ROI {roi.name}\")\n",
|
|
262
|
+
" patch = source_image.get_roi(roi, c=dapi_idx)\n",
|
|
264
263
|
" segmentation = otsu_threshold_segmentation(patch, max_label)\n",
|
|
265
264
|
"\n",
|
|
266
265
|
" # Add the max label of the previous segmentation to avoid overlapping labels\n",
|
|
266
|
+
" segmentation = segmentation[0]\n",
|
|
267
267
|
" max_label = segmentation.max()\n",
|
|
268
268
|
"\n",
|
|
269
|
-
" nuclei_image.
|
|
269
|
+
" nuclei_image.set_roi(patch=segmentation, roi=roi)\n",
|
|
270
270
|
"\n",
|
|
271
271
|
"# Consolidate the segmentation image\n",
|
|
272
272
|
"nuclei_image.consolidate()\n",
|
|
@@ -274,9 +274,9 @@
|
|
|
274
274
|
"print(\"Segmentation image saved\")\n",
|
|
275
275
|
"fig, axs = plt.subplots(2, 1, figsize=(10, 5))\n",
|
|
276
276
|
"axs[0].set_title(\"MIP\")\n",
|
|
277
|
-
"axs[0].imshow(source_image.
|
|
277
|
+
"axs[0].imshow(source_image.zarr_array[0, 0], cmap=\"gray\")\n",
|
|
278
278
|
"axs[1].set_title(\"Nuclei segmentation\")\n",
|
|
279
|
-
"axs[1].imshow(nuclei_image.
|
|
279
|
+
"axs[1].imshow(nuclei_image.zarr_array[0], cmap=rand_cmap, interpolation=\"nearest\")\n",
|
|
280
280
|
"for ax in axs:\n",
|
|
281
281
|
" ax.axis(\"off\")\n",
|
|
282
282
|
"plt.tight_layout()\n",
|
|
@@ -236,6 +236,8 @@ class ImagesContainer:
|
|
|
236
236
|
ref_path: str | None = None,
|
|
237
237
|
shape: Collection[int] | None = None,
|
|
238
238
|
chunks: Collection[int] | None = None,
|
|
239
|
+
xy_scaling_factor: float = 2.0,
|
|
240
|
+
z_scaling_factor: float = 1.0,
|
|
239
241
|
overwrite: bool = False,
|
|
240
242
|
) -> "ImagesContainer":
|
|
241
243
|
"""Create an OME-Zarr image from a numpy array."""
|
|
@@ -245,6 +247,8 @@ class ImagesContainer:
|
|
|
245
247
|
ref_path=ref_path,
|
|
246
248
|
shape=shape,
|
|
247
249
|
chunks=chunks,
|
|
250
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
251
|
+
z_scaling_factor=z_scaling_factor,
|
|
248
252
|
overwrite=overwrite,
|
|
249
253
|
)
|
|
250
254
|
|
|
@@ -314,6 +318,8 @@ def derive_image_container(
|
|
|
314
318
|
ref_path: str | None = None,
|
|
315
319
|
shape: Collection[int] | None = None,
|
|
316
320
|
chunks: Collection[int] | None = None,
|
|
321
|
+
xy_scaling_factor: float = 2.0,
|
|
322
|
+
z_scaling_factor: float = 1.0,
|
|
317
323
|
overwrite: bool = False,
|
|
318
324
|
) -> ImagesContainer:
|
|
319
325
|
"""Create an OME-Zarr image from a numpy array."""
|
|
@@ -347,8 +353,8 @@ def derive_image_container(
|
|
|
347
353
|
z_spacing=ref_image.pixel_size.z,
|
|
348
354
|
time_spacing=ref_image.pixel_size.t,
|
|
349
355
|
levels=ref_meta.levels,
|
|
350
|
-
xy_scaling_factor=
|
|
351
|
-
z_scaling_factor=
|
|
356
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
357
|
+
z_scaling_factor=z_scaling_factor,
|
|
352
358
|
time_unit=ref_image.pixel_size.time_unit,
|
|
353
359
|
space_unit=ref_image.pixel_size.space_unit,
|
|
354
360
|
axes_names=ref_image.dataset.axes_mapper.on_disk_axes_names,
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""A module for handling label images in OME-NGFF files."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Collection
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
from ngio.images.abstract_image import AbstractImage, consolidate_image
|
|
7
|
+
from ngio.images.create import _create_empty_label
|
|
8
|
+
from ngio.images.image import Image
|
|
9
|
+
from ngio.ome_zarr_meta import (
|
|
10
|
+
ImplementedLabelMetaHandlers,
|
|
11
|
+
LabelMetaHandler,
|
|
12
|
+
NgioLabelMeta,
|
|
13
|
+
)
|
|
14
|
+
from ngio.ome_zarr_meta.ngio_specs import SpaceUnits, TimeUnits
|
|
15
|
+
from ngio.utils import (
|
|
16
|
+
NgioValidationError,
|
|
17
|
+
NgioValueError,
|
|
18
|
+
StoreOrGroup,
|
|
19
|
+
ZarrGroupHandler,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Label(AbstractImage[LabelMetaHandler]):
|
|
24
|
+
"""Placeholder class for a label."""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
group_handler: ZarrGroupHandler,
|
|
29
|
+
path: str,
|
|
30
|
+
meta_handler: LabelMetaHandler | None,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Initialize the Image at a single level.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
group_handler: The Zarr group handler.
|
|
36
|
+
path: The path to the image in the omezarr file.
|
|
37
|
+
meta_handler: The image metadata handler.
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
if meta_handler is None:
|
|
41
|
+
meta_handler = ImplementedLabelMetaHandlers().find_meta_handler(
|
|
42
|
+
group_handler
|
|
43
|
+
)
|
|
44
|
+
super().__init__(
|
|
45
|
+
group_handler=group_handler, path=path, meta_handler=meta_handler
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def meta(self) -> NgioLabelMeta:
|
|
50
|
+
"""Return the metadata."""
|
|
51
|
+
return self._meta_handler.meta
|
|
52
|
+
|
|
53
|
+
def consolidate(
|
|
54
|
+
self,
|
|
55
|
+
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Consolidate the label on disk."""
|
|
58
|
+
consolidate_image(self, mode=mode, order=0)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class LabelsContainer:
|
|
62
|
+
"""A class to handle the /labels group in an OME-NGFF file."""
|
|
63
|
+
|
|
64
|
+
def __init__(self, group_handler: ZarrGroupHandler) -> None:
|
|
65
|
+
"""Initialize the LabelGroupHandler."""
|
|
66
|
+
self._group_handler = group_handler
|
|
67
|
+
|
|
68
|
+
# Validate the group
|
|
69
|
+
# Either contains a labels attribute or is empty
|
|
70
|
+
attrs = self._group_handler.load_attrs()
|
|
71
|
+
if len(attrs) == 0:
|
|
72
|
+
# It's an empty group
|
|
73
|
+
pass
|
|
74
|
+
elif "labels" in attrs and isinstance(attrs["labels"], list):
|
|
75
|
+
# It's a valid group
|
|
76
|
+
pass
|
|
77
|
+
else:
|
|
78
|
+
raise NgioValidationError(
|
|
79
|
+
f"Invalid /labels group. "
|
|
80
|
+
f"Expected a single labels attribute with a list of label names. "
|
|
81
|
+
f"Found: {attrs}"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def list(self) -> list[str]:
|
|
85
|
+
"""Create the /labels group if it doesn't exist."""
|
|
86
|
+
attrs = self._group_handler.load_attrs()
|
|
87
|
+
return attrs.get("labels", [])
|
|
88
|
+
|
|
89
|
+
def get(self, name: str, path: str) -> Label:
|
|
90
|
+
"""Get a label from the group."""
|
|
91
|
+
group_handler = self._group_handler.derive_handler(name)
|
|
92
|
+
return Label(group_handler, path, None)
|
|
93
|
+
|
|
94
|
+
def derive(
|
|
95
|
+
self,
|
|
96
|
+
name: str,
|
|
97
|
+
ref_image: Image,
|
|
98
|
+
shape: Collection[int] | None = None,
|
|
99
|
+
chunks: Collection[int] | None = None,
|
|
100
|
+
dtype: str = "uint16",
|
|
101
|
+
xy_scaling_factor=2.0,
|
|
102
|
+
z_scaling_factor=1.0,
|
|
103
|
+
overwrite: bool = False,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Add a label to the group."""
|
|
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
|
+
)
|
|
112
|
+
|
|
113
|
+
label_group = self._group_handler.get_group(name, create_mode=True)
|
|
114
|
+
|
|
115
|
+
_derive_label(
|
|
116
|
+
ref_image=ref_image,
|
|
117
|
+
store=label_group,
|
|
118
|
+
shape=shape,
|
|
119
|
+
chunks=chunks,
|
|
120
|
+
dtype=dtype,
|
|
121
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
122
|
+
z_scaling_factor=z_scaling_factor,
|
|
123
|
+
overwrite=overwrite,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if name not in existing_labels:
|
|
127
|
+
existing_labels.append(name)
|
|
128
|
+
self._group_handler.write_attrs({"labels": existing_labels})
|
|
129
|
+
|
|
130
|
+
def new(
|
|
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."""
|
|
149
|
+
existing_labels = self.list()
|
|
150
|
+
if name in existing_labels and not overwrite:
|
|
151
|
+
raise NgioValueError(
|
|
152
|
+
f"Table '{name}' already exists in the group. "
|
|
153
|
+
"Use overwrite=True to replace it."
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
label_group = self._group_handler.get_group(name, create_mode=True)
|
|
157
|
+
|
|
158
|
+
_create_empty_label(
|
|
159
|
+
store=label_group,
|
|
160
|
+
shape=shape,
|
|
161
|
+
xy_pixelsize=xy_pixelsize,
|
|
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,
|
|
169
|
+
axes_names=axes_names,
|
|
170
|
+
chunks=chunks,
|
|
171
|
+
dtype=dtype,
|
|
172
|
+
overwrite=overwrite,
|
|
173
|
+
version=version,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if name not in existing_labels:
|
|
177
|
+
existing_labels.append(name)
|
|
178
|
+
self._group_handler.write_attrs({"labels": existing_labels})
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _derive_label(
|
|
182
|
+
ref_image: Image,
|
|
183
|
+
store: StoreOrGroup,
|
|
184
|
+
shape: Collection[int] | None = None,
|
|
185
|
+
chunks: Collection[int] | None = None,
|
|
186
|
+
dtype: str = "uint16",
|
|
187
|
+
xy_scaling_factor=2.0,
|
|
188
|
+
z_scaling_factor=1.0,
|
|
189
|
+
overwrite: bool = False,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Create an OME-Zarr image from a numpy array."""
|
|
192
|
+
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
|
+
|
|
203
|
+
if shape is None:
|
|
204
|
+
shape = shape_ref
|
|
205
|
+
|
|
206
|
+
if chunks is None:
|
|
207
|
+
chunks = chunks_ref
|
|
208
|
+
|
|
209
|
+
if len(shape) != len(shape_ref):
|
|
210
|
+
raise NgioValidationError(
|
|
211
|
+
"The shape of the new image does not match the reference image."
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
if len(chunks) != len(chunks_ref):
|
|
215
|
+
raise NgioValidationError(
|
|
216
|
+
"The chunks of the new image does not match the reference image."
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
_ = _create_empty_label(
|
|
220
|
+
store=store,
|
|
221
|
+
shape=shape,
|
|
222
|
+
xy_pixelsize=ref_image.pixel_size.x,
|
|
223
|
+
z_spacing=ref_image.pixel_size.z,
|
|
224
|
+
time_spacing=ref_image.pixel_size.t,
|
|
225
|
+
levels=ref_meta.levels,
|
|
226
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
227
|
+
z_scaling_factor=z_scaling_factor,
|
|
228
|
+
time_unit=ref_image.pixel_size.time_unit,
|
|
229
|
+
space_unit=ref_image.pixel_size.space_unit,
|
|
230
|
+
axes_names=axes_names_ref,
|
|
231
|
+
chunks=chunks,
|
|
232
|
+
dtype=dtype,
|
|
233
|
+
overwrite=overwrite,
|
|
234
|
+
version=ref_meta.version,
|
|
235
|
+
)
|
|
236
|
+
return None
|
|
@@ -175,6 +175,8 @@ class OmeZarrContainer:
|
|
|
175
175
|
ref_path: str | None = None,
|
|
176
176
|
shape: Collection[int] | None = None,
|
|
177
177
|
chunks: Collection[int] | None = None,
|
|
178
|
+
xy_scaling_factor: float = 2.0,
|
|
179
|
+
z_scaling_factor: float = 1.0,
|
|
178
180
|
copy_tables: bool = False,
|
|
179
181
|
copy_labels: bool = False,
|
|
180
182
|
overwrite: bool = False,
|
|
@@ -191,6 +193,8 @@ class OmeZarrContainer:
|
|
|
191
193
|
ref_path=ref_path,
|
|
192
194
|
shape=shape,
|
|
193
195
|
chunks=chunks,
|
|
196
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
197
|
+
z_scaling_factor=z_scaling_factor,
|
|
194
198
|
overwrite=overwrite,
|
|
195
199
|
)
|
|
196
200
|
return OmeZarrContainer(
|
|
@@ -281,15 +285,34 @@ class OmeZarrContainer:
|
|
|
281
285
|
raise NgioValidationError("No labels found in the image.")
|
|
282
286
|
return self._labels_container.get(name=name, path=path)
|
|
283
287
|
|
|
284
|
-
def derive_label(
|
|
288
|
+
def derive_label(
|
|
289
|
+
self,
|
|
290
|
+
name: str,
|
|
291
|
+
ref_image: Image | None = None,
|
|
292
|
+
shape: Collection[int] | None = None,
|
|
293
|
+
chunks: Collection[int] | None = None,
|
|
294
|
+
dtype: str = "uint16",
|
|
295
|
+
xy_scaling_factor=2.0,
|
|
296
|
+
z_scaling_factor=1.0,
|
|
297
|
+
overwrite: bool = False,
|
|
298
|
+
) -> Label:
|
|
285
299
|
"""Derive a label from an image."""
|
|
286
300
|
if self._labels_container is None:
|
|
287
301
|
raise NgioValidationError("No labels found in the image.")
|
|
288
302
|
|
|
289
|
-
ref_image
|
|
290
|
-
|
|
291
|
-
|
|
303
|
+
if ref_image is None:
|
|
304
|
+
ref_image = self.get_image()
|
|
305
|
+
self._labels_container.derive(
|
|
306
|
+
name=name,
|
|
307
|
+
ref_image=ref_image,
|
|
308
|
+
shape=shape,
|
|
309
|
+
chunks=chunks,
|
|
310
|
+
dtype=dtype,
|
|
311
|
+
xy_scaling_factor=xy_scaling_factor,
|
|
312
|
+
z_scaling_factor=z_scaling_factor,
|
|
313
|
+
overwrite=overwrite,
|
|
292
314
|
)
|
|
315
|
+
return self.get_label(name, path="0")
|
|
293
316
|
|
|
294
317
|
|
|
295
318
|
def open_omezarr_container(
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""A module for handling label images in OME-NGFF files."""
|
|
2
|
-
|
|
3
|
-
from typing import Literal
|
|
4
|
-
|
|
5
|
-
from ngio.images.abstract_image import AbstractImage, consolidate_image
|
|
6
|
-
from ngio.ome_zarr_meta import (
|
|
7
|
-
ImplementedLabelMetaHandlers,
|
|
8
|
-
LabelMetaHandler,
|
|
9
|
-
NgioLabelMeta,
|
|
10
|
-
)
|
|
11
|
-
from ngio.utils import (
|
|
12
|
-
NgioValidationError,
|
|
13
|
-
ZarrGroupHandler,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Label(AbstractImage[LabelMetaHandler]):
|
|
18
|
-
"""Placeholder class for a label."""
|
|
19
|
-
|
|
20
|
-
def __init__(
|
|
21
|
-
self,
|
|
22
|
-
group_handler: ZarrGroupHandler,
|
|
23
|
-
path: str,
|
|
24
|
-
meta_handler: LabelMetaHandler | None,
|
|
25
|
-
) -> None:
|
|
26
|
-
"""Initialize the Image at a single level.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
group_handler: The Zarr group handler.
|
|
30
|
-
path: The path to the image in the omezarr file.
|
|
31
|
-
meta_handler: The image metadata handler.
|
|
32
|
-
|
|
33
|
-
"""
|
|
34
|
-
if meta_handler is None:
|
|
35
|
-
meta_handler = ImplementedLabelMetaHandlers().find_meta_handler(
|
|
36
|
-
group_handler
|
|
37
|
-
)
|
|
38
|
-
super().__init__(
|
|
39
|
-
group_handler=group_handler, path=path, meta_handler=meta_handler
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def meta(self) -> NgioLabelMeta:
|
|
44
|
-
"""Return the metadata."""
|
|
45
|
-
return self._meta_handler.meta
|
|
46
|
-
|
|
47
|
-
def consolidate(
|
|
48
|
-
self,
|
|
49
|
-
mode: Literal["dask", "numpy", "coarsen"] = "dask",
|
|
50
|
-
) -> None:
|
|
51
|
-
"""Consolidate the label on disk."""
|
|
52
|
-
consolidate_image(self, mode=mode, order=0)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class LabelsContainer:
|
|
56
|
-
"""A class to handle the /labels group in an OME-NGFF file."""
|
|
57
|
-
|
|
58
|
-
def __init__(self, group_handler: ZarrGroupHandler) -> None:
|
|
59
|
-
"""Initialize the LabelGroupHandler."""
|
|
60
|
-
self._group_handler = group_handler
|
|
61
|
-
|
|
62
|
-
# Validate the group
|
|
63
|
-
# Either contains a labels attribute or is empty
|
|
64
|
-
attrs = self._group_handler.load_attrs()
|
|
65
|
-
if len(attrs) == 0:
|
|
66
|
-
# It's an empty group
|
|
67
|
-
pass
|
|
68
|
-
elif "labels" in attrs and isinstance(attrs["labels"], list):
|
|
69
|
-
# It's a valid group
|
|
70
|
-
pass
|
|
71
|
-
else:
|
|
72
|
-
raise NgioValidationError(
|
|
73
|
-
f"Invalid /labels group. "
|
|
74
|
-
f"Expected a single labels attribute with a list of label names. "
|
|
75
|
-
f"Found: {attrs}"
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
def list(self) -> list[str]:
|
|
79
|
-
"""Create the /labels group if it doesn't exist."""
|
|
80
|
-
attrs = self._group_handler.load_attrs()
|
|
81
|
-
return attrs.get("labels", [])
|
|
82
|
-
|
|
83
|
-
def get(self, name: str, path: str) -> Label:
|
|
84
|
-
"""Get a label from the group."""
|
|
85
|
-
group_handler = self._group_handler.derive_handler(name)
|
|
86
|
-
return Label(group_handler, path, None)
|
|
87
|
-
|
|
88
|
-
def derive(
|
|
89
|
-
self,
|
|
90
|
-
name: str,
|
|
91
|
-
reference_image: AbstractImage,
|
|
92
|
-
overwrite: bool = False,
|
|
93
|
-
**kwargs,
|
|
94
|
-
) -> Label:
|
|
95
|
-
"""Derive a label from an image."""
|
|
96
|
-
raise NotImplementedError
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ngio-0.2.0a1 → ngio-0.2.0a2}/tests/data/meta_v04/base_ome_zarr_image_meta_wrong_axis_order.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|