{
"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",
"shape | (100, 100, 100) | \n",
"dtype | uint8 | \n",
"size | 976.6 kB | \n",
"min | 0 | max | 1 | \n",
" \n",
" \n",
" | \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",
"nppas.SurfaceTuple \n",
"\n",
"origin (z/y/x) | [0. 0. 0.] | \n",
"center of mass(z/y/x) | 50.000,46.575,42.589 | \n",
"scale(z/y/x) | 1.000,1.000,1.000 | \n",
"bounds (z/y/x) | 25.500...74.500 2.500...88.500 2.500...83.500 | \n",
"average size | 31.277 | \n",
"number of vertices | 19040 | \n",
"number of faces | 38076 | \n",
"\n",
" \n",
"\n",
" | \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",
"cle._ image \n",
"\n",
"shape | (100, 100, 100) | \n",
"dtype | uint32 | \n",
"size | 3.8 MB | \n",
"min | 0.0 | max | 2.0 | \n",
" \n",
"\n",
" | \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",
"nppas.SurfaceTuple \n",
"\n",
"origin (z/y/x) | [0. 0. 0.] | \n",
"center of mass(z/y/x) | 50.000,53.374,48.714 | \n",
"scale(z/y/x) | 1.000,1.000,1.000 | \n",
"bounds (z/y/x) | 25.000...75.000 25.000...89.000 12.000...84.000 | \n",
"average size | 28.026 | \n",
"number of vertices | 8278 | \n",
"number of faces | 16552 | \n",
"\n",
" \n",
"\n",
" | \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",
"nppas.SurfaceTuple \n",
"\n",
"origin (z/y/x) | [0. 0. 0.] | \n",
"center of mass(z/y/x) | 50.000,18.136,18.136 | \n",
"scale(z/y/x) | 1.000,1.000,1.000 | \n",
"bounds (z/y/x) | 36.000...64.000 2.000...38.000 2.000...38.000 | \n",
"average size | 15.361 | \n",
"number of vertices | 2472 | \n",
"number of faces | 4952 | \n",
"\n",
" \n",
"\n",
" | \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",
"nppas.SurfaceTuple \n",
"\n",
"origin (z/y/x) | [0. 0. 0.] | \n",
"center of mass(z/y/x) | 50.000,53.374,48.714 | \n",
"scale(z/y/x) | 1.000,1.000,1.000 | \n",
"bounds (z/y/x) | 25.000...75.000 25.000...89.000 12.000...84.000 | \n",
"average size | 28.026 | \n",
"number of vertices | 8278 | \n",
"number of faces | 16552 | \n",
"\n",
" \n",
"\n",
" | \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",
" bounds (x/y/z) | 25.33 ... 74.67 2.333 ... 88.67 2.333 ... 83.67 | \n",
" center of mass | (50.0, 46.6, 42.6) | \n",
" average size | 31.358 | \n",
" nr. points / faces | 19040 / 38076 | \n",
" point data array | input_scalars | \n",
"\n",
" \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
}