{
"cells": [
{
"cell_type": "markdown",
"id": "8e4ba882-7c37-4d6d-9bd6-700ae0a4e173",
"metadata": {},
"source": [
"## Label image refinement\n",
"Similar to morphological operations on binary imagges, 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",
"import numpy as np\n",
"from skimage.io import imread"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6656d5ca-daf5-4fab-af81-4d789a647ee8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 13.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[ 0, 0, 0, ..., 13, 13, 13],\n",
" [ 0, 0, 0, ..., 13, 13, 13],\n",
" [ 0, 0, 0, ..., 13, 13, 13],\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": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"label_image = cle.gauss_otsu_labeling(imread(\"../../data/mitosis_mod.tif\"), outline_sigma=0)\n",
"label_image"
]
},
{
"cell_type": "markdown",
"id": "a87b767c-a145-4f7c-b57a-18317332d03f",
"metadata": {},
"source": [
"## Eroding labels\n",
"When eroding labels, we need to be careful that objects might split into two. This could be intentional, e.g. to differentiate touching nuclei like in the example above."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "f4055854-7bcc-4801-b4d4-a619d8891e32",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 9.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[0, 0, 0, ..., 0, 9, 9],\n",
" [0, 0, 0, ..., 0, 9, 9],\n",
" [0, 0, 0, ..., 0, 0, 9],\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": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eroded_label_image = cle.erode_labels(label_image,\n",
" radius=2,\n",
" relabel_islands=False)\n",
"eroded_label_image"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "3dc03bc2-6620-46fa-96ca-462b61e56cf6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 10.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[ 0, 0, 0, ..., 0, 10, 10],\n",
" [ 0, 0, 0, ..., 0, 10, 10],\n",
" [ 0, 0, 0, ..., 0, 0, 10],\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": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eroded_label_image2 = cle.erode_labels(label_image,\n",
" radius=2,\n",
" relabel_islands=True)\n",
"eroded_label_image2"
]
},
{
"cell_type": "markdown",
"id": "ebf221cc-053e-46d3-9231-d076fe8745d2",
"metadata": {},
"source": [
"## Dilating labels\n",
"We can then dilate the labels again to come back to their original size approximately. This might also be useful in case segmented objects are too small in general."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "8fe52a86-2d94-46f9-9ed0-104fbfaa7822",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 10.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[ 0, 0, 0, ..., 10, 10, 10],\n",
" [ 0, 0, 0, ..., 10, 10, 10],\n",
" [ 0, 0, 2, ..., 10, 10, 10],\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": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dilated_label_image = cle.dilate_labels(eroded_label_image2, \n",
" radius=2)\n",
"dilated_label_image"
]
},
{
"cell_type": "markdown",
"id": "edef6274-eb5a-464d-9bdc-286482ee0183",
"metadata": {},
"source": [
"## Opening and closing labels\n",
"Opening and closing for label images is similar like for binary images. The only difference is that when labels touch, they cannot expand anymore.\n",
"\n",
"Note that opening labels may make small labels disappear."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "70597b80-7510-474c-bca2-00b0c0c95edc",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 9.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[0, 0, 0, ..., 9, 9, 9],\n",
" [0, 0, 0, ..., 9, 9, 9],\n",
" [0, 0, 2, ..., 9, 9, 9],\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": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"opened_label_image = cle.opening_labels(label_image,\n",
" radius=2)\n",
"opened_label_image"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b4075c1e-48ee-4b79-abae-6ae19d27a6d1",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (70, 70) | \n",
"dtype | uint32 | \n",
"size | 19.1 kB | \n",
"min | 0.0 | max | 13.0 | \n",
" \n",
"\n",
" | \n",
"
\n",
"
"
],
"text/plain": [
"cl.OCLArray([[ 0, 0, 0, ..., 13, 13, 13],\n",
" [ 0, 0, 0, ..., 13, 13, 13],\n",
" [ 0, 0, 0, ..., 13, 13, 13],\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": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"closed_label_image = cle.closing_labels(label_image,\n",
" radius=2)\n",
"closed_label_image"
]
},
{
"cell_type": "markdown",
"id": "47e1b07a-7c2d-4d66-841f-04b7ac3237e2",
"metadata": {},
"source": [
"## Exercise\n",
"Use the operations introduced above to make small objects disappear in this label image."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "b89c0347-8ae2-4d55-865d-43ac3d27286d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
" \n",
" | \n",
"\n",
"cle._ image \n",
"\n",
"shape | (254, 256) | \n",
"dtype | uint32 | \n",
"size | 254.0 kB | \n",
"min | 0.0 | max | 63.0 | \n",
" \n",
"\n",
" | \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": [
"label_blobs = cle.asarray(imread(\"../../data/blobs_labeled.tif\")).astype(np.uint32)\n",
"label_blobs"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "239603f3-3993-48d3-a618-616055e7c3c7",
"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.15"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}