{ "cells": [ { "cell_type": "markdown", "id": "8e4ba882-7c37-4d6d-9bd6-700ae0a4e173", "metadata": {}, "source": [ "## Label image refinement\n", "Similar to refining binary images it is also possible to refine label images. This notebook shows how to do this.\n", "\n", "See also\n", "* [scikit-image's Expand segmentation labels without overlap tutorial](https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_expand_labels.html)" ] }, { "cell_type": "code", "execution_count": 1, "id": "0029748b", "metadata": {}, "outputs": [], "source": [ "import pyclesperanto_prototype as cle\n", "from skimage.data import cells3d\n", "import matplotlib.pyplot as plt\n", "from skimage.morphology import closing, disk\n", "from skimage.io import imread\n", "from skimage.filters.rank import maximum\n", "from skimage.segmentation import expand_labels\n", "from skimage.measure import label\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "fd88b935-18fa-4e92-bd57-ba3fdbb0afd3", "metadata": {}, "source": [ "As a starting point, let's assume an algorithm produced this label image." ] }, { "cell_type": "code", "execution_count": 2, "id": "7f10d620-25af-42e6-8034-02b8760ead39", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(256, 256)
dtypeuint32
size256.0 kB
min1.0
max25.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " ...,\n", " [24, 24, 24, ..., 25, 25, 25],\n", " [24, 24, 24, ..., 25, 25, 25],\n", " [24, 24, 24, ..., 25, 25, 25]], dtype=uint32)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "label_image = cle.asarray(imread(\"../../data/membrane_2d_labels.tif\")).astype(np.uint32)\n", "label_image" ] }, { "cell_type": "markdown", "id": "0c589c3c-1753-4f33-927f-12327b4697bd", "metadata": {}, "source": [ "## Morphological opening labels\n", "Similar to morphological opening on binary images, we can also modify this label image. Note: this operation introduces gaps between labels if the radius is large neough." ] }, { "cell_type": "code", "execution_count": 3, "id": "49e95235-6ff9-4207-8775-ae13e0ba7dad", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(256, 256)
dtypeuint32
size256.0 kB
min0.0
max25.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " ...,\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0]], dtype=uint32)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "opened_labels = cle.opening_labels(label_image, radius=5)\n", "opened_labels" ] }, { "cell_type": "markdown", "id": "1e0a0d76-a901-4669-a84e-0e4d6482bdb4", "metadata": {}, "source": [ "## Smoothing labels\n", "If these introduced gaps are not wanted, the alternative is to use this function:" ] }, { "cell_type": "code", "execution_count": 4, "id": "af83c434-b0e3-4c25-84e6-ee04d02b7922", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(256, 256)
dtypeuint32
size256.0 kB
min1.0
max25.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " ...,\n", " [24, 24, 24, ..., 21, 21, 21],\n", " [24, 24, 24, ..., 25, 21, 21],\n", " [24, 24, 24, ..., 25, 25, 21]], dtype=uint32)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smoothed_labels = cle.smooth_labels(label_image, radius = 5)\n", "smoothed_labels" ] }, { "cell_type": "markdown", "id": "507f41d8-4523-4840-bc2a-0f47fcafdc96", "metadata": {}, "source": [ "To get a better understanding of what the algorithm does, it may make sense to tune the `radius` parameter interactively. This will not work in the github-rendering of this notebook, you need to run it in Jupyter lab and have [stackview](https://pypi.org/project/stackview/) installed." ] }, { "cell_type": "code", "execution_count": 5, "id": "9cdf3c84-b5ad-4131-b7ec-85156c042c9b", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "5655885662ef48c7b2ab3ffdd7630661", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=0, description='radius', max=20), Output()), _dom_classes=('widget-inter…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "549aa2f131c849f28fd9cf66443fc753", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), Label(value='smooth_lab…" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import stackview\n", "stackview.interact(cle.smooth_labels, label_image, continuous_update=True)" ] }, { "cell_type": "markdown", "id": "45e4c2b3-1d2f-49d9-8ef3-4f27a4d8ecfe", "metadata": {}, "source": [ "## Eroding and dilating labels\n", "Under the hood, the functions shown above use label erosion and dilation. These operations are defined analogously to binary erosion and dilation with the difference that labels cannot overwrite each other." ] }, { "cell_type": "code", "execution_count": 6, "id": "ec5bc86a-4af1-44c7-8812-1fd53e4876cd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(256, 256)
dtypeuint32
size256.0 kB
min0.0
max25.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 0, 0, 0],\n", " [ 1, 1, 1, ..., 0, 0, 0],\n", " ...,\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0]], dtype=uint32)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eroded_labels = cle.erode_labels(label_image, radius=5)\n", "eroded_labels" ] }, { "cell_type": "code", "execution_count": 7, "id": "a1e5038f-caf8-4b15-8857-fbd870de29ad", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(256, 256)
dtypeuint32
size256.0 kB
min0.0
max25.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " [ 1, 1, 1, ..., 5, 5, 5],\n", " ...,\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0],\n", " [24, 24, 24, ..., 0, 0, 0]], dtype=uint32)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dilated_eroded_labels = cle.dilate_labels(eroded_labels, radius=5)\n", "dilated_eroded_labels" ] }, { "cell_type": "markdown", "id": "77f9e8c0-b285-4aa1-bb01-635067ac13b7", "metadata": {}, "source": [ "## Exercise\n", "Use labeling post-processing operations to modify this labeling result. Goal: Make small objects disappear while all other objects more or less keep their size and shape:" ] }, { "cell_type": "code", "execution_count": 8, "id": "7ad8fdf8-debc-4e39-8d9b-99a041221ae5", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(254, 256)
dtypeuint32
size254.0 kB
min0.0
max64.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[0, 0, 0, ..., 5, 5, 5],\n", " [0, 0, 0, ..., 5, 5, 5],\n", " [0, 0, 0, ..., 5, 5, 5],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]], dtype=uint32)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "blobs_labels = cle.asarray(imread(\"../../data/blobs_labels.tif\")).astype(np.uint32)\n", "blobs_labels" ] }, { "cell_type": "code", "execution_count": null, "id": "ecb495b4-cd68-4c67-acfb-b3e4e4b661ee", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 5 }