{ "cells": [ { "cell_type": "markdown", "id": "ff11395c-5b0c-4df8-8b20-a5ab712d31ff", "metadata": {}, "source": [ "# Oberfl\u00e4chen erstellen\n", "In diesem Notebook erstellen wir eine Oberfl\u00e4che (Mesh) aus einem 3D-Datensatz eines simulierten 3D-Bin\u00e4rbilddatensatzes." ] }, { "cell_type": "code", "execution_count": 1, "id": "a43114eb-755f-485d-b602-4d0b6f5330da", "metadata": {}, "outputs": [], "source": [ "import napari_process_points_and_surfaces as nppas\n", "import pyclesperanto_prototype as cle\n", "import vedo\n", "\n", "from branchoid import branchoid" ] }, { "cell_type": "code", "execution_count": 2, "id": "0bec9a3c-4553-40e9-b51e-3a4d666cb855", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
shape(100, 100, 100)
dtypeuint8
size976.6 kB
min0
max1
\n", "\n", "
" ], "text/plain": [ "StackViewNDArray([[[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " ...,\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "binary_image = branchoid()\n", "binary_image" ] }, { "cell_type": "markdown", "id": "e2491f7f-9650-4797-ae2e-7ee2bd64dfb7", "metadata": {}, "source": [ "## Oberfl\u00e4chen generieren\n", "Zuerst generieren wir eine Oberfl\u00e4che aus dem Bin\u00e4rbild. In diesem Fall nehmen wir _alle_ Pixel mit Nicht-Null-Werten und verwandeln sie in eine Oberfl\u00e4che." ] }, { "cell_type": "code", "execution_count": 3, "id": "8fb1ee00-5458-407b-addf-fc79297d9143", "metadata": {}, "outputs": [], "source": [ "surface = nppas.all_labels_to_surface(binary_image)" ] }, { "cell_type": "markdown", "id": "7affb339-e0a8-48d8-949c-f16083e0c154", "metadata": {}, "source": [ "Das resultierende Objekt wird in Jupyter Notebooks so visualisiert:" ] }, { "cell_type": "code", "execution_count": 4, "id": "286341c1-8d10-4554-a709-68288eaa0f28", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nppas.SurfaceTuple
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
origin (z/y/x)[0. 0. 0.]
center of mass(z/y/x)50.000,46.575,42.589
scale(z/y/x)1.000,1.000,1.000
bounds (z/y/x)25.500...74.500
2.500...88.500
2.500...83.500
average size31.277
number of vertices19040
number of faces38076
\n", "\n", "
" ], "text/plain": [ "(array([[25.5, 44. , 47. ],\n", " [26. , 43.5, 47. ],\n", " [26. , 44. , 46.5],\n", " ...,\n", " [74.5, 56. , 51. ],\n", " [74.5, 56. , 52. ],\n", " [74.5, 56. , 53. ]], dtype=float32),\n", " array([[ 2, 1, 0],\n", " [ 4, 3, 0],\n", " [ 4, 0, 1],\n", " ...,\n", " [19038, 18870, 18872],\n", " [19038, 18872, 19039],\n", " [19039, 18872, 18852]], dtype=int64))" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "surface" ] }, { "cell_type": "markdown", "id": "3e55e713-e535-4f11-b19b-589b84505889", "metadata": {}, "source": [ "Technisch gesehen handelt es sich um ein Tupel." ] }, { "cell_type": "code", "execution_count": 5, "id": "ec3216dc-2ff6-460f-97c9-397eeff4c2e2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(surface, tuple)" ] }, { "cell_type": "markdown", "id": "46a04221-c759-45be-a69f-90d738f92297", "metadata": {}, "source": [ "Das Tupel enth\u00e4lt Vertices und Faces." ] }, { "cell_type": "code", "execution_count": 6, "id": "9dbbb259-d444-428b-84b7-ed471dbaa9e3", "metadata": {}, "outputs": [], "source": [ "vertices, faces = surface" ] }, { "cell_type": "markdown", "id": "f7cbfd62-c8c4-4f90-96a0-e09084396021", "metadata": {}, "source": [ "Vertices sind Listen von Listen von Z/Y/X-Koordinaten im 3D-Raum." ] }, { "cell_type": "code", "execution_count": 7, "id": "9af4fe17-5988-4006-8aa5-588eaef129d6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[25.5, 44. , 47. ],\n", " [26. , 43.5, 47. ],\n", " [26. , 44. , 46.5],\n", " ...,\n", " [74.5, 56. , 51. ],\n", " [74.5, 56. , 52. ],\n", " [74.5, 56. , 53. ]], dtype=float32)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vertices" ] }, { "cell_type": "markdown", "id": "b2c9e671-f65f-441f-93f7-8e31077dc98f", "metadata": {}, "source": [ "Faces sind Listen von Listen von Indizes. Jedes Dreieck hat drei Punktkoordinaten, die wie folgt indiziert sind:" ] }, { "cell_type": "code", "execution_count": 8, "id": "02561534-d60b-4d78-855d-515acdf7d9a5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 2, 1, 0],\n", " [ 4, 3, 0],\n", " [ 4, 0, 1],\n", " ...,\n", " [19038, 18870, 18872],\n", " [19038, 18872, 19039],\n", " [19039, 18872, 18852]], dtype=int64)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "faces" ] }, { "cell_type": "markdown", "id": "2de7d766-c833-4775-8cf2-c8757dd0c434", "metadata": {}, "source": [ "## Oberfl\u00e4chen aus einzelnen Labels\n", "Wenn wir ein Labelbild als Ausgangspunkt haben, k\u00f6nnen wir auch einzelne Objekte in Oberfl\u00e4chen umwandeln." ] }, { "cell_type": "code", "execution_count": 9, "id": "6932814b-452e-4d71-8038-2ec78c928f56", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "cle._ image
\n", "\n", "\n", "\n", "\n", "\n", "
shape(100, 100, 100)
dtypeuint32
size3.8 MB
min0.0
max2.0
\n", "\n", "
" ], "text/plain": [ "cl.OCLArray([[[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " ...,\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " ...,\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0]],\n", "\n", " [[0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\n", " [0, 0, 0, ..., 0, 0, 0],\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": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels = cle.voronoi_otsu_labeling(binary_image, spot_sigma=6)\n", "labels" ] }, { "cell_type": "code", "execution_count": 10, "id": "79e8ca48-ecc9-435f-9edf-862c636aa0a0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nppas.SurfaceTuple
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
origin (z/y/x)[0. 0. 0.]
center of mass(z/y/x)50.000,53.374,48.714
scale(z/y/x)1.000,1.000,1.000
bounds (z/y/x)25.000...75.000
25.000...89.000
12.000...84.000
average size28.026
number of vertices8278
number of faces16552
\n", "\n", "
" ], "text/plain": [ "(array([[26., 42., 49.],\n", " [26., 43., 48.],\n", " [25., 43., 49.],\n", " ...,\n", " [75., 57., 49.],\n", " [75., 57., 50.],\n", " [75., 57., 51.]], dtype=float32),\n", " array([[ 0, 1, 2],\n", " [ 3, 4, 2],\n", " [ 2, 4, 0],\n", " ...,\n", " [8094, 8276, 8095],\n", " [8095, 8276, 8277],\n", " [8095, 8277, 8083]], dtype=int64))" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nppas.largest_label_to_surface(labels)" ] }, { "cell_type": "code", "execution_count": 11, "id": "31beeea3-9184-4fad-8910-595794f34db9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nppas.SurfaceTuple
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
origin (z/y/x)[0. 0. 0.]
center of mass(z/y/x)50.000,18.136,18.136
scale(z/y/x)1.000,1.000,1.000
bounds (z/y/x)36.000...64.000
2.000...38.000
2.000...38.000
average size15.361
number of vertices2472
number of faces4952
\n", "\n", "
" ], "text/plain": [ "(array([[37., 10., 15.],\n", " [37., 11., 14.],\n", " [36., 11., 15.],\n", " ...,\n", " [64., 21., 15.],\n", " [64., 21., 16.],\n", " [64., 21., 17.]], dtype=float32),\n", " array([[ 0, 1, 2],\n", " [ 3, 4, 2],\n", " [ 2, 4, 0],\n", " ...,\n", " [2375, 2470, 2376],\n", " [2376, 2470, 2471],\n", " [2376, 2471, 2367]], dtype=int64))" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nppas.label_to_surface(labels, label_id=1)" ] }, { "cell_type": "code", "execution_count": 12, "id": "5a797ea5-1e25-4449-90df-7270a3e9aa85", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "\n", "nppas.SurfaceTuple
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
origin (z/y/x)[0. 0. 0.]
center of mass(z/y/x)50.000,53.374,48.714
scale(z/y/x)1.000,1.000,1.000
bounds (z/y/x)25.000...75.000
25.000...89.000
12.000...84.000
average size28.026
number of vertices8278
number of faces16552
\n", "\n", "
" ], "text/plain": [ "(array([[26., 42., 49.],\n", " [26., 43., 48.],\n", " [25., 43., 49.],\n", " ...,\n", " [75., 57., 49.],\n", " [75., 57., 50.],\n", " [75., 57., 51.]], dtype=float32),\n", " array([[ 0, 1, 2],\n", " [ 3, 4, 2],\n", " [ 2, 4, 0],\n", " ...,\n", " [8094, 8276, 8095],\n", " [8095, 8276, 8277],\n", " [8095, 8277, 8083]], dtype=int64))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nppas.label_to_surface(labels, label_id=2)" ] }, { "cell_type": "markdown", "id": "402d4776-697d-4fa9-8956-352176d878a8", "metadata": {}, "source": [ "## Oberfl\u00e4chen mit vedo erstellen\n", "\n", "Vedo bietet auch Funktionen zum Erstellen von Oberfl\u00e4chen wie `iso_surface()`." ] }, { "cell_type": "code", "execution_count": 13, "id": "9dad1e20-9d4f-4967-8b3c-6fbab650b810", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "
\n", "\n", "
\n", "vedo.mesh.Mesh\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
bounds
(x/y/z)
25.33 ... 74.67
2.333 ... 88.67
2.333 ... 83.67
center of mass (50.0, 46.6, 42.6)
average size 31.358
nr. points / faces 19040 / 38076
point data array input_scalars
\n", "
" ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "volume = vedo.Volume(binary_image)\n", "\n", "iso_surface = volume.isosurface()\n", "iso_surface" ] }, { "cell_type": "markdown", "id": "0c910826-35c3-4b2f-baf2-e93e117d5207", "metadata": {}, "source": [ "Die resultierende Datenstruktur ist ein vedo Mesh. Sie k\u00f6nnen auch auf dessen Punkte und Fl\u00e4chen zugreifen." ] }, { "cell_type": "code", "execution_count": 14, "id": "59f05510-b48a-41d8-b58b-4298cabcb0ea", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[49. , 11. , 2.3333333],\n", " [50. , 11. , 2.3333333],\n", " [51. , 11. , 2.3333333],\n", " ...,\n", " [50. , 55. , 83.666664 ],\n", " [51. , 55. , 83.666664 ],\n", " [52. , 55. , 83.666664 ]], dtype=float32)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iso_surface.points()" ] }, { "cell_type": "code", "execution_count": 15, "id": "2adc890b-3599-4f7a-a685-e173725d6842", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[0, 92, 104],\n", " [0, 1, 93],\n", " [92, 0, 93],\n", " [1, 2, 94],\n", " [93, 1, 94],\n", " [94, 2, 105],\n", " [3, 106, 118],\n", " [3, 4, 107],\n", " [106, 3, 107],\n", " [104, 107, 4]]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "iso_surface.faces()[:10]" ] }, { "cell_type": "markdown", "id": "d05b6220-a4fc-40ae-b306-5c08b9a84405", "metadata": {}, "source": [ "## \u00dcbung\n", "Laden Sie den `skimage.data.cells3d` Datensatz, extrahieren Sie den zweiten Kanal und erstellen Sie ein Oberfl\u00e4chennetz aus den Zellkernen." ] }, { "cell_type": "code", "execution_count": null, "id": "5ddae3fa-21d0-45f0-92e8-8a38f8ec1bd1", "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 }