{ "cells": [ { "cell_type": "markdown", "id": "dca63629", "metadata": {}, "source": [ "# Interactive functions in Jupyter Lab\n", "\n", "In this notebook we demonstate interactive functions using [stackview](https://github.com/haesleinhuepf/stackview/) in combination with [pyclesperanto_prototype](https://github.com/clEsperanto/pyclesperanto_prototype). Interactive image stack viewing in jupyter notebooks based on \n", "[ipycanvas](https://ipycanvas.readthedocs.io/) and \n", "[ipywidgets](https://ipywidgets.readthedocs.io/en/latest/). \n", "\n", "Note: This notebook is not fully rendered in the Jupyter book and on github. You need to run it locally to see how it works." ] }, { "cell_type": "markdown", "id": "79a8abbc", "metadata": {}, "source": [ "## Usage\n", "First we test the installation by importing the two libraries and scikit-image for loading image data." ] }, { "cell_type": "code", "execution_count": 1, "id": "ca154076", "metadata": {}, "outputs": [], "source": [ "import stackview\n", "import pyclesperanto_prototype as cle\n", "from skimage.io import imread" ] }, { "cell_type": "markdown", "id": "b9f91fcf-243b-4b8d-af0b-29c4649907c4", "metadata": {}, "source": [ "Starting point is a 3D image dataset provided as numpy array. " ] }, { "cell_type": "code", "execution_count": 2, "id": "2f21ee1d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(100, 256, 256)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_stack = cle.imread('../../data/Lund_000500_resampled-cropped.tif')\n", "\n", "image_stack.shape" ] }, { "cell_type": "markdown", "id": "684f3268-6388-40fa-b633-ca65e4763e57", "metadata": {}, "source": [ "`cle`-images are visualized in jupyer notebooks with a static view. In case the dataset is 3D, we see a maximum-intensity projection." ] }, { "cell_type": "code", "execution_count": 3, "id": "cd9be4e3-89b1-4105-9b66-54af398b4811", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(100, 256, 256)
dtypefloat32
size25.0 MB
min125.0
max680.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[[144., 142., 145., ..., 140., 138., 137.],\n", " [145., 142., 143., ..., 141., 139., 138.],\n", " [142., 139., 141., ..., 140., 139., 142.],\n", " ...,\n", " [256., 252., 260., ..., 308., 287., 273.],\n", " [253., 249., 253., ..., 319., 298., 278.],\n", " [256., 255., 253., ..., 322., 296., 273.]],\n", "\n", " [[143., 140., 145., ..., 139., 139., 137.],\n", " [145., 139., 144., ..., 140., 140., 138.],\n", " [143., 140., 142., ..., 141., 140., 141.],\n", " ...,\n", " [255., 255., 263., ..., 314., 292., 274.],\n", " [255., 250., 251., ..., 328., 302., 277.],\n", " [257., 253., 250., ..., 329., 298., 272.]],\n", "\n", " [[143., 139., 145., ..., 139., 139., 137.],\n", " [145., 138., 145., ..., 139., 141., 137.],\n", " [143., 140., 142., ..., 142., 141., 141.],\n", " ...,\n", " [254., 257., 265., ..., 316., 293., 272.],\n", " [255., 251., 250., ..., 330., 302., 274.],\n", " [257., 251., 248., ..., 332., 298., 270.]],\n", "\n", " ...,\n", "\n", " [[137., 138., 140., ..., 128., 127., 129.],\n", " [140., 140., 137., ..., 131., 127., 129.],\n", " [140., 138., 138., ..., 129., 130., 133.],\n", " ...,\n", " [177., 182., 181., ..., 160., 161., 161.],\n", " [179., 185., 186., ..., 162., 157., 158.],\n", " [181., 179., 184., ..., 158., 157., 160.]],\n", "\n", " [[136., 138., 141., ..., 127., 127., 129.],\n", " [139., 139., 136., ..., 131., 127., 129.],\n", " [140., 137., 138., ..., 127., 128., 134.],\n", " ...,\n", " [175., 179., 179., ..., 158., 159., 159.],\n", " [177., 182., 184., ..., 162., 155., 158.],\n", " [180., 174., 180., ..., 158., 157., 158.]],\n", "\n", " [[136., 136., 139., ..., 129., 129., 129.],\n", " [137., 137., 135., ..., 130., 128., 128.],\n", " [138., 135., 136., ..., 128., 130., 132.],\n", " ...,\n", " [174., 176., 177., ..., 159., 157., 157.],\n", " [179., 180., 180., ..., 160., 154., 156.],\n", " [178., 174., 177., ..., 158., 156., 157.]]], dtype=float32)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "image_stack" ] }, { "cell_type": "markdown", "id": "b011a13c-b3d8-4ef7-93fa-92f5ce287d62", "metadata": {}, "source": [ "## Slicing\n", "\n", "We can explore the dataset interactively using `stackview.slice`." ] }, { "cell_type": "code", "execution_count": 4, "id": "d4507842-3fe6-47fc-acc9-470507d0c2bd", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "0b8b774eb9644457bc7af29a6c1cac4c", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), IntSlider(value=50, con…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "stackview.slice(image_stack)" ] }, { "cell_type": "markdown", "id": "5732a5ff-f5c6-4e11-94b5-7d6b1f7e5de1", "metadata": {}, "source": [ "We can also hover with our mouse over the dataset and read out pixel intensities using `stackview.picker`." ] }, { "cell_type": "code", "execution_count": 5, "id": "19c95531-0952-4d92-9107-2cad1bb26223", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "161bea7853de484db48000d0790706d3", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), IntSlider(value=50, con…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "stackview.picker(image_stack)" ] }, { "cell_type": "markdown", "id": "7eb9cdaf-c4a9-45b6-a139-12fbe4849885", "metadata": {}, "source": [ "## Curtain\n", "\n", "To compare the original image with a modified version, e.g. after background subtraction, we can use `stackview.curtain`." ] }, { "cell_type": "code", "execution_count": 6, "id": "bd7d1317", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e65322d7fdcd4d10806a4446290d2a3a", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), IntSlider(value=50, con…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "background_subtracted = cle.top_hat_box(image_stack, radius_x=10, radius_y=10)\n", "\n", "stackview.curtain(image_stack, background_subtracted)" ] }, { "cell_type": "markdown", "id": "18ea8070", "metadata": {}, "source": [ "## Interaction\n", "\n", "You can also use `sliceview.interact` to explore parameters of functions interactively." ] }, { "cell_type": "code", "execution_count": 7, "id": "41b75598", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ebc09569563e406691a62edcf194d73d", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(FloatSlider(value=2.0, continuous_update=False, description='spot_sigma', max=20.0, min=…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "3eedf71b328042b8b9527452dbd9bcaa", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), IntSlider(value=50, con…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "stackview.interact(cle.voronoi_otsu_labeling, background_subtracted)" ] }, { "cell_type": "markdown", "id": "c42efe8b-7633-4c90-801f-67e7d912b724", "metadata": {}, "source": [ "This may also make sense with custom functions. When writing those it is important to use type-annotations." ] }, { "cell_type": "code", "execution_count": 8, "id": "11f6e31e", "metadata": {}, "outputs": [], "source": [ "def my_custom_segmentation(image, background_subtraction_radius: int = 10, spot_sigma:float = 1, outline_sigma:float = 1, show_labels: bool = True):\n", " background_subtraction_radius = abs(background_subtraction_radius)\n", " spot_sigma = abs(spot_sigma)\n", " outline_sigma = abs(outline_sigma)\n", " \n", " background_subtracted = cle.top_hat_box(image, radius_x=10, radius_y=10)\n", "\n", " label_image = cle.voronoi_otsu_labeling(background_subtracted, spot_sigma=spot_sigma, outline_sigma=outline_sigma)\n", " \n", " edge_image = cle.detect_label_edges(label_image)\n", " \n", " if show_labels:\n", " return label_image\n", " else:\n", " return edge_image * 255 + image " ] }, { "cell_type": "code", "execution_count": 9, "id": "91ea85ee-1609-4741-9ff3-acbd5c7e2139", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "7409ea65c4fe4b0abbda6e1e6aa4a022", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=10, continuous_update=False, description='background_subtraction_radius'…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ae2fb8749c964e10b9a1d3434fcf60b6", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(VBox(children=(ImageWidget(height=256, width=256),)),)), IntSlider(value=50, con…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "stackview.interact(my_custom_segmentation, image_stack)" ] }, { "cell_type": "markdown", "id": "45988939-881e-430b-876a-aa784ab4b35a", "metadata": {}, "source": [ "## Exercise\n", "Load the blobs image and setup a custom segmentation workflow for segmenting the blobs. Use `stackview.interact` to tune the parameters for the segmentation ([spoiler](https://github.com/haesleinhuepf/stackview/blob/main/docs/demo.ipynb))." ] }, { "cell_type": "code", "execution_count": 10, "id": "bd1beef7-97ff-4dda-9bc8-37b7d1aaece8", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(254, 256)
dtypefloat32
size254.0 kB
min8.0
max248.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[ 40., 32., 24., ..., 216., 200., 200.],\n", " [ 56., 40., 24., ..., 232., 216., 216.],\n", " [ 64., 48., 24., ..., 240., 232., 232.],\n", " ...,\n", " [ 72., 80., 80., ..., 48., 48., 48.],\n", " [ 80., 80., 80., ..., 48., 48., 48.],\n", " [ 96., 88., 80., ..., 48., 48., 48.]], dtype=float32)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice_image = cle.imread('../../data/blobs.tif')\n", "slice_image" ] }, { "cell_type": "code", "execution_count": null, "id": "09628af9-0423-4c8a-9fad-421ffd705425", "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 }