Skip to content

Commit

Permalink
ENH: Support skan.csr.Skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Jan 15, 2020
1 parent f2c6b8b commit ec066cd
Show file tree
Hide file tree
Showing 4 changed files with 276 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ examples/General_EduRes_Heart_BloodVessels_0.jpg
examples/cow.vtk
examples/Bunny.vtp
examples/uGridEx.vtk
examples/input.tiff

js/lib/ZstdDecompress/web-build/
.pytest_cache/
Expand Down
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ point sets, and meshes.
- pyvista.UnstructuredGrid
- vtkplotter.Actor
- vtkplotter.Assembly
- skan.csr.Skeleton

- Exquisite volume rendering
- Tri-plane volume slicing
Expand Down Expand Up @@ -123,6 +124,7 @@ Tasks:
- `Binder: Select a region of interest <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/SelectRegionOfInterest.ipynb>`_
- `Binder: Specify camera parameters <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/SpecifyCameraParameters.ipynb>`_
- `Binder: Specify a colormap <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/SpecifyAColormap.ipynb>`_
- `Binder: Visualize a segmentation skeleton <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/SegmentationSkeleton.ipynb>`_

Installation
------------
Expand Down Expand Up @@ -263,6 +265,7 @@ or how to:
- `Select a region of interest <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/SelectRegionOfInterest.ipynb>`_
- `Specify camera parameters <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/SpecifyCameraParameters.ipynb>`_
- `Specify a colormap <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/SpecifyAColormap.ipynb>`_
- `Visualization segmentation skeleton <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/SegmentationSkeleton.ipynb>`_


Troubleshooting
Expand Down
221 changes: 221 additions & 0 deletions examples/SegmentationSkeleton.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Install dependencies for this example\n",
"# Note: This does not include itkwidgets, itself\n",
"import sys\n",
"!{sys.executable} -m pip install itk-io scikit-image skan pandas numba"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from urllib.request import urlretrieve\n",
"import os\n",
"from skimage import data\n",
"\n",
"import itk\n",
"import skan\n",
"from skimage.util import img_as_float64, invert\n",
"from skimage.morphology import skeletonize\n",
"import numpy as np\n",
"\n",
"from itkwidgets import view, cm"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "80e1cd86fdb24327874163e5bca1148a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(annotations=False, cmap='gray_Matlab', geometries=[], gradient_opacity=0.22, interpolation=False, point…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image = invert(data.horse())\n",
"view(image.astype(np.uint8),\n",
" ui_collapsed=True, annotations=False,\n",
" interpolation=False, cmap=cm.gray)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"skeleton = skeletonize(image)\n",
"skeleton_csr = skan.csr.Skeleton(skeleton)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e7c2699edd604adbafd510a684292650",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(annotations=False, cmap='gray_Matlab', geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': '…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(image.astype(np.uint8), geometries=skeleton_csr,\n",
" ui_collapsed=True, annotations=False,\n",
" interpolate=False, cmap=cm.gray)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Download 3D data\n",
"file_name = 'input.tiff'\n",
"if not os.path.exists(file_name):\n",
" url = 'https://data.kitware.com/api/v1/item/5e1ea82eaf2e2eed35033055/download'\n",
" urlretrieve(url, file_name)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "fda4764e751a4220b32c2dc1733a3aed",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, point_sets=[], rendered_image=<itkImagePython.itkImageF3; proxy o…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"image = itk.imread(file_name, itk.F)\n",
"view(image, ui_collapsed=True, shadow=False)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Normalize for skimage\n",
"image_arr = itk.array_from_image(image)\n",
"image_arr = img_as_float64(image_arr)\n",
"image_arr = image_arr / image_arr.max()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"skeleton = skeletonize(image_arr)\n",
"skeleton_csr = skan.csr.Skeleton(skeleton, spacing=list(itk.spacing(image))[::-1])"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "72e4c8ab26e8498091b25d48286ed25d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(annotations=False, camera=array([[ 4.6124218e+01, 9.3229523e+01, 2.7596173e+02],\n",
" [ 4.9500000e+…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(image_arr, geometries=skeleton_csr,\n",
" ui_collapsed=True, shadow=False, annotations=False,\n",
" camera=[[ 4.6124218e+01, 9.3229523e+01, 2.7596173e+02],\n",
" [ 4.9500000e+01, 4.9500000e+01, 7.5000000e+00],\n",
" [-6.0824049e-01, 7.8217846e-01, -1.3505679e-01]])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}
51 changes: 51 additions & 0 deletions itkwidgets/_transform_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def is_arraylike(arr):
hasattr(arr, '__array__') and \
hasattr(arr, 'ndim')

# from IPython.core.debugger import set_trace

have_imagej = False
try:
Expand All @@ -35,6 +36,12 @@ def is_arraylike(arr):
have_simpleitk = True
except ImportError:
pass
have_skan = False
try:
import skan
have_skan = True
except ImportError:
pass

_itk_pixel_to_vtkjs_type_components = {
itk.SC: ('Int8Array', 1),
Expand Down Expand Up @@ -413,6 +420,50 @@ def to_geometry(geometry_like): # noqa: C901
'values': cell_data}
geometry[cell_type] = cells

return geometry
elif have_skan and isinstance(geometry_like, skan.csr.Skeleton):

geometry = {'vtkClass': 'vtkPolyData'}

number_of_points = geometry_like.coordinates.shape[0]
dimension = geometry_like.coordinates.shape[1]

points_data = -5.0e-6 * \
np.ones((number_of_points, 3), dtype=np.float64)
points_data[:, :dimension] = np.flip(geometry_like.coordinates[:, :dimension], 1)
points_data = points_data.astype(np.float32).ravel()
points = {'vtkClass': 'vtkPoints',
'name': '_points',
'numberOfComponents': 3,
'dataType': 'Float32Array',
'size': points_data.size,
'values': points_data}
geometry['points'] = points

verts_data = np.empty((0,), dtype=np.uint32)
lines_data = np.empty((0,), dtype=np.uint32)
for path in geometry_like.paths_list():
path_number_of_points = len(path)
verts = np.ones((2 * path_number_of_points,), dtype=np.uint32)
verts[1::2] = np.array(path, dtype=np.uint32)
verts_data = np.concatenate((verts_data, verts))

lines = 2 * \
np.ones((3 * (path_number_of_points - 1),), dtype=np.uint32)
lines[1::3] = np.array(path[:-1], dtype=np.uint32)
lines[2::3] = np.array(path[1:], dtype=np.uint32)
lines_data = np.concatenate((lines_data, lines))

for cell_type, cell_data in [
('verts', verts_data), ('lines', lines_data)]:
cells = {'vtkClass': 'vtkCellArray',
'name': '_' + cell_type,
'numberOfComponents': 1,
'size': cell_data.size,
'dataType': 'Uint32Array',
'values': cell_data}
geometry[cell_type] = cells

return geometry
elif have_vtk and isinstance(geometry_like, vtk.vtkPolyData):
from vtk.util.numpy_support import vtk_to_numpy
Expand Down

0 comments on commit ec066cd

Please sign in to comment.