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)
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: Roi(t=None->None, z=0.0->1.0, y=0.0->351.0, x=0.0->832.0)
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 |