In [1]:
Copied!
import numpy as np
import pandas as pd
from skimage import measure
def extract_features(image: np.ndarray, label: np.ndarray) -> pd.DataFrame:
"""Basic feature extraction using skimage.measure.regionprops_table."""
label = label.squeeze(-1) # Remove the channel axis if present
roi_feat_table = measure.regionprops_table(
label_image=label,
intensity_image=image,
properties=[
"label",
"area",
"mean_intensity",
"max_intensity",
"min_intensity",
],
)
return pd.DataFrame(roi_feat_table)
import numpy as np
import pandas as pd
from skimage import measure
def extract_features(image: np.ndarray, label: np.ndarray) -> pd.DataFrame:
"""Basic feature extraction using skimage.measure.regionprops_table."""
label = label.squeeze(-1) # Remove the channel axis if present
roi_feat_table = measure.regionprops_table(
label_image=label,
intensity_image=image,
properties=[
"label",
"area",
"mean_intensity",
"max_intensity",
"min_intensity",
],
)
return pd.DataFrame(roi_feat_table)
In [2]:
Copied!
from pathlib import Path
from ngio import open_ome_zarr_container
from ngio.utils import download_ome_zarr_dataset
# Download the dataset
download_dir = Path(".").absolute().parent.parent / "data"
hcs_path = download_ome_zarr_dataset("CardiomyocyteTinyMip", download_dir=download_dir)
image_path = hcs_path / "B" / "03" / "0"
# Open the ome-zarr container
ome_zarr = open_ome_zarr_container(image_path)
from pathlib import Path
from ngio import open_ome_zarr_container
from ngio.utils import download_ome_zarr_dataset
# Download the dataset
download_dir = Path(".").absolute().parent.parent / "data"
hcs_path = download_ome_zarr_dataset("CardiomyocyteTinyMip", download_dir=download_dir)
image_path = hcs_path / "B" / "03" / "0"
# Open the ome-zarr container
ome_zarr = open_ome_zarr_container(image_path)
/opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
Downloading data from 'https://zenodo.org/records/13305156/files/20200812-CardiomyocyteDifferentiation14-Cycle1_mip.zarr.zip' to file '/home/runner/work/ngio/ngio/data/20200812-CardiomyocyteDifferentiation14-Cycle1-tiny-mip.zarr.zip'.
Unzipping contents of '/home/runner/work/ngio/ngio/data/20200812-CardiomyocyteDifferentiation14-Cycle1-tiny-mip.zarr.zip' to '/home/runner/work/ngio/ngio/data/tmp'
Step 2: Setup the inputs¶
In [3]:
Copied!
from ngio.transforms import ZoomTransform
# First we will need the image object and the FOVs table
image = ome_zarr.get_image()
# Get the nuclei label
nuclei = ome_zarr.get_label("nuclei")
# In this example we the image is available at an higher resolution than the nuclei
print(f"Image dimensions: {image.dimensions}, pixel size: {image.pixel_size}")
print(f"Nuclei dimensions: {nuclei.dimensions}, pixel size: {nuclei.pixel_size}")
# We need to setup a transform to resample the nuclei to the image resolution
zoom_transform = ZoomTransform(
input_image=nuclei,
target_image=image,
order="nearest", # Nearest neighbor interpolation for labels
)
from ngio.transforms import ZoomTransform
# First we will need the image object and the FOVs table
image = ome_zarr.get_image()
# Get the nuclei label
nuclei = ome_zarr.get_label("nuclei")
# In this example we the image is available at an higher resolution than the nuclei
print(f"Image dimensions: {image.dimensions}, pixel size: {image.pixel_size}")
print(f"Nuclei dimensions: {nuclei.dimensions}, pixel size: {nuclei.pixel_size}")
# We need to setup a transform to resample the nuclei to the image resolution
zoom_transform = ZoomTransform(
input_image=nuclei,
target_image=image,
order="nearest", # Nearest neighbor interpolation for labels
)
Image dimensions: Dimensions(c: 1, z: 1, y: 2160, x: 5120), pixel size: x=0.1625 y=0.1625 z=1.0 t=1.0 space_unit='micrometer' time_unit=None Nuclei dimensions: Dimensions(z: 1, y: 540, x: 1280), pixel size: x=0.65 y=0.65 z=1.0 t=1.0 space_unit='micrometer' time_unit=None
Step 3: Use the FeatureExtractorIterator to create a feature table¶
In [4]:
Copied!
from ngio.experimental.iterators import FeatureExtractorIterator
from ngio.tables import FeatureTable
iterator = FeatureExtractorIterator(
input_image=image,
input_label=nuclei,
label_transforms=[zoom_transform],
axes_order=["y", "x", "c"],
)
feat_table = []
for image_data, label_data, roi in iterator.iter_as_numpy():
print(f"Processing ROI: {roi}")
roi_feat_table = extract_features(image=image_data, label=label_data)
feat_table.append(roi_feat_table)
# Concatenate all the dataframes into a single one
feat_table = pd.concat(feat_table)
feat_table = FeatureTable(table_data=feat_table, reference_label="nuclei")
ome_zarr.add_table("nuclei_regionprops", feat_table)
from ngio.experimental.iterators import FeatureExtractorIterator
from ngio.tables import FeatureTable
iterator = FeatureExtractorIterator(
input_image=image,
input_label=nuclei,
label_transforms=[zoom_transform],
axes_order=["y", "x", "c"],
)
feat_table = []
for image_data, label_data, roi in iterator.iter_as_numpy():
print(f"Processing ROI: {roi}")
roi_feat_table = extract_features(image=image_data, label=label_data)
feat_table.append(roi_feat_table)
# Concatenate all the dataframes into a single one
feat_table = pd.concat(feat_table)
feat_table = FeatureTable(table_data=feat_table, reference_label="nuclei")
ome_zarr.add_table("nuclei_regionprops", feat_table)
Processing ROI: name=None slices=[z: 0.0->1.0, y: 0.0->351.0, x: 0.0->832.0] label=None space='world'
/opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/anndata/_io/zarr.py:44: UserWarning: Writing zarr v2 data will no longer be the default in the next minor release. v3 data will be written by default. If you are explicitly setting this configuration, consider migrating to the zarr v3 file format. f = open_write_group(store)
Sanity Check: Read the Table back¶
In [5]:
Copied!
ome_zarr.get_table("nuclei_regionprops").lazy_frame.collect()
ome_zarr.get_table("nuclei_regionprops").lazy_frame.collect()
Out[5]:
shape: (1_497, 5)
| label | area | mean_intensity-0 | max_intensity-0 | min_intensity-0 |
|---|---|---|---|---|
| i64 | f64 | f64 | f64 | f64 |
| 1 | 1360.0 | 184.579412 | 268.0 | 125.0 |
| 2 | 2464.0 | 273.246753 | 461.0 | 132.0 |
| 3 | 1968.0 | 277.291667 | 429.0 | 143.0 |
| 4 | 5120.0 | 279.035156 | 413.0 | 118.0 |
| 5 | 288.0 | 243.315972 | 341.0 | 147.0 |
| … | … | … | … | … |
| 1493 | 1248.0 | 269.291667 | 385.0 | 108.0 |
| 1494 | 528.0 | 315.710227 | 475.0 | 128.0 |
| 1495 | 608.0 | 281.544408 | 377.0 | 122.0 |
| 1496 | 288.0 | 261.003472 | 356.0 | 122.0 |
| 1497 | 432.0 | 336.101852 | 454.0 | 172.0 |
In [ ]:
Copied!