{ "cells": [ { "cell_type": "markdown", "id": "50f6743a-03a3-43b5-8e8a-5bb32ff41f6f", "metadata": {}, "source": [ "# Merging labels according to edge-to-edge-distances\n", "In this notebook we will merge labels in a label image according to their edge-to-edge distances to each other. Labels close-by will be merged.\n", "\n", "See also\n", "* [Image.sc discussion](https://forum.image.sc/t/measure-distances-between-labels/79125)\n", "* [Merging labels using napari-accelerated-pixel-and-object-classifiers](https://github.com/haesleinhuepf/napari-accelerated-pixel-and-object-classification#merging-objects)" ] }, { "cell_type": "code", "execution_count": 1, "id": "626d0d82-dbbb-4092-bf57-80eda98de375", "metadata": {}, "outputs": [], "source": [ "import pyclesperanto_prototype as cle\n", "from skimage.io import imread\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "f6585d60-e431-4902-bed9-901afcf4f6ba", "metadata": {}, "source": [ "For demonstration purposes, we use a modified version of the labels derived from the blobs example-image. We artificially introduce gaps between them." ] }, { "cell_type": "code", "execution_count": 2, "id": "878e3c57-593c-4ad3-9c3c-096f1eef2c6b", "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
max47.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 0, 0, 0, ..., 45, 45, 45],\n", " [ 0, 0, 0, ..., 45, 45, 45],\n", " [ 0, 0, 0, ..., 45, 45, 45],\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": [ "image = imread(\"../../data/blobs.tif\")\n", "image[:, 80:150] = 0\n", "image[80:130, 100:] = 0\n", "\n", "image = cle.asarray(image)\n", "labels = cle.voronoi_otsu_labeling(image, spot_sigma=4, outline_sigma=3)\n", "labels" ] }, { "cell_type": "markdown", "id": "457c3bd0-1641-4021-affb-06b22649b324", "metadata": {}, "source": [ "First, we dilate the labels by half of the maximum distance the edges are allowed to have." ] }, { "cell_type": "code", "execution_count": 3, "id": "20258bd4-9f74-479e-a7bd-1d5399a6ef21", "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
max47.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 0, 0, 0, ..., 45, 45, 45],\n", " [ 0, 0, 0, ..., 45, 45, 45],\n", " [ 0, 0, 0, ..., 45, 45, 45],\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": [ "maximum_distance = 12\n", "\n", "dilated_labels = cle.dilate_labels(labels, radius=maximum_distance/2)\n", "dilated_labels" ] }, { "cell_type": "markdown", "id": "e07254cf-accc-425e-af51-d992f481d1fc", "metadata": {}, "source": [ "We then merge the labels if the touch." ] }, { "cell_type": "code", "execution_count": 4, "id": "7298aa54-71b4-46f6-bff3-6eb22547d329", "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
max5.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[0, 0, 0, ..., 4, 4, 4],\n", " [0, 0, 0, ..., 4, 4, 4],\n", " [0, 0, 0, ..., 4, 4, 4],\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": [ "merged_dilated_labels = cle.merge_touching_labels(dilated_labels)\n", "merged_dilated_labels" ] }, { "cell_type": "markdown", "id": "d850ccfc-eaee-4647-ac52-3fbfaac5b1c9", "metadata": {}, "source": [ "Afterwards, we mask the merged labels with the original label's shape. We also convert the result of this operation to 32-bit integer, so that the visualization as label-image works." ] }, { "cell_type": "code", "execution_count": 5, "id": "b41bd861-c9fb-4e81-b20a-91cc8920e379", "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
max5.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[0, 0, 0, ..., 4, 4, 4],\n", " [0, 0, 0, ..., 4, 4, 4],\n", " [0, 0, 0, ..., 4, 4, 4],\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": [ "merged_labels = (merged_dilated_labels * (labels > 0)).astype(np.uint32)\n", "merged_labels" ] }, { "cell_type": "code", "execution_count": null, "id": "cf56cb38-aaaa-4e79-b762-21e87ec78045", "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 }