{ "cells": [ { "cell_type": "markdown", "id": "2d31db30-a623-4b57-b87b-aa4c456b1933", "metadata": {}, "source": [ "## Splitting touching objects\n", "A common use-case for the watershed algorithm is splitting touching objects. In this notebook we will split objects in binary images that have a roundish shape and touch each other. " ] }, { "cell_type": "code", "execution_count": 1, "id": "80d09227-5427-40b3-b477-9d11877c35cf", "metadata": {}, "outputs": [], "source": [ "from skimage.io import imread\n", "import napari_segment_blobs_and_things_with_membranes as nsbatwm\n", "import napari_simpleitk_image_processing as nsitk\n", "import stackview" ] }, { "cell_type": "markdown", "id": "4b0d6b44-0d78-467b-bed7-071f67819f56", "metadata": {}, "source": [ "Starting point for this is a binary image, e.g. made using [thresholding](image-segmentation:thresholding)." ] }, { "cell_type": "code", "execution_count": 2, "id": "87cb2de1-5fb3-443c-8048-c1803e524655", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
shape(70, 70)
dtypeuint8
size4.8 kB
min8
max255
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[ 19, 29, 44, ..., 88, 115, 113],\n", " [ 19, 29, 55, ..., 87, 101, 112],\n", " [ 25, 36, 61, ..., 90, 90, 106],\n", " ...,\n", " [ 20, 21, 20, ..., 57, 33, 40],\n", " [ 22, 25, 25, ..., 41, 34, 40],\n", " [ 20, 25, 18, ..., 41, 35, 39]], dtype=uint8)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nuclei = imread('../../data/mitosis_mod.tif')\n", "\n", "stackview.insight(nuclei)" ] }, { "cell_type": "code", "execution_count": 3, "id": "df9d6678-fb39-4bcb-9001-04c00264498b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "<__array_function__ internals>:180: RuntimeWarning: Converting input from bool to for compatibility.\n" ] }, { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nsbatwm made image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(70, 70)
dtypebool
size4.8 kB
minFalse
maxTrue
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " ...,\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False]])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "binary = nsbatwm.threshold_otsu(nuclei).astype(bool)\n", "\n", "binary" ] }, { "cell_type": "markdown", "id": "63e40577", "metadata": {}, "source": [ "We can then split the touching object by only taking the binary image into account. The underlying algorithm aims to produce similar results to [ImageJ's binary watershed algorithm](https://imagej.nih.gov/ij/docs/menus/process.html#watershed) and the implementation here also works in 3D." ] }, { "cell_type": "code", "execution_count": 4, "id": "a4740a57", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nsbatwm made image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(70, 70)
dtypebool
size4.8 kB
minFalse
maxTrue
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " ...,\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False]])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "split_objects = nsbatwm.split_touching_objects(binary)\n", "split_objects" ] }, { "cell_type": "markdown", "id": "87a98644-7bba-4d21-a2c0-75aaf16574e6", "metadata": {}, "source": [ "The `split_touching_objects` function also has a parameter `sigma` that allows controlling how aggressive objects should be split. To make more splits, enter a smaller number than 3.5 which is the default." ] }, { "cell_type": "code", "execution_count": 5, "id": "94006d68-6c1e-4723-a244-c697e672f3b0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nsbatwm made image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(70, 70)
dtypebool
size4.8 kB
minFalse
maxTrue
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " [False, False, False, ..., True, True, True],\n", " ...,\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "split_objects2 = nsbatwm.split_touching_objects(binary, sigma=2)\n", "split_objects2" ] }, { "cell_type": "markdown", "id": "8d3b4ab7-7a2a-4945-a13a-f39afaba8495", "metadata": {}, "source": [ "It is also possible to retrieve a label image as result. Note that in this case, the black line/gap between objects will not be present." ] }, { "cell_type": "code", "execution_count": 6, "id": "5ed59887-f13f-4ca9-bee3-b2fda27ecbc5", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "n-sitk made image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(70, 70)
dtypeuint32
size19.1 kB
min0
max13
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[0, 0, 0, ..., 2, 2, 2],\n", " [0, 0, 0, ..., 2, 2, 2],\n", " [0, 0, 0, ..., 2, 2, 2],\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": [ "touching_labels = nsitk.touching_objects_labeling(binary)\n", "touching_labels" ] }, { "cell_type": "code", "execution_count": null, "id": "a91eafee-498a-4a93-9c6a-7715ce7a9b6b", "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" } }, "nbformat": 4, "nbformat_minor": 5 }