{
"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",
"cle._ image \n",
"\n",
"shape | (100, 256, 256) | \n",
"dtype | float32 | \n",
"size | 25.0 MB | \n",
"min | 125.0 | max | 680.0 | \n",
" \n",
" \n",
" | \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",
"cle._ image \n",
"\n",
"shape | (254, 256) | \n",
"dtype | float32 | \n",
"size | 254.0 kB | \n",
"min | 8.0 | max | 248.0 | \n",
" \n",
" \n",
" | \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
}