Skip to content

Commit

Permalink
ENH: Add support for itk.PointBasedSpatialObject's
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Feb 12, 2020
1 parent 57aa595 commit 9ef6b16
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ examples/cow.vtk
examples/Bunny.vtp
examples/uGridEx.vtk
examples/input.tiff
examples/Normal071-VascularNetwork.tre

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 @@ -56,6 +56,7 @@ Interactive Jupyter_ widgets to visualize images, point sets, and meshes.

- NumPy array point sets
- `itk.PointSet <https://itk.org/Doxygen/html/classitk_1_1PointSet.html>`_
- `itk.PointBasedSpatialObject <https://itk.org/Doxygen/html/classitk_1_1PointBasedSpatialObject.html>`_
- `vtk.vtkPolyData <https://vtk.org/doc/nightly/html/classvtkPolyData.html>`_ point sets
- `pyvista.PolyData <https://docs.pyvista.org/core/points.html>`_ point sets

Expand Down Expand Up @@ -114,6 +115,7 @@ Data types:
- `Binder: NumPy array for image with anisotropic spacing <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/ImageWithAnisotropicPixelSpacing.ipynb>`_
- `Binder: NumPy array point sets <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/NumPyArrayPointSet.ipynb>`_
- `Binder: ITK Mesh <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/Mesh.ipynb>`_
- `Binder: ITK PointBasedSpatialObject <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/PointBasedSpatialObject.ipynb>`_
- `Binder: skan segmentation skeleton <https://mybinder.org/v2/gh/InsightSoftwareConsortium/itkwidgets/master?urlpath=lab/tree/examples/SegmentationSkeleton.ipynb>`_

Tasks:
Expand Down Expand Up @@ -250,6 +252,7 @@ After installation, try the following examples that demonstrate how to visualize
- `pyvista UniformGrid <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/pyvista.UniformGrid.ipynb>`_
- `NumPy array point sets <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/NumPyArrayPointSet.ipynb>`_
- `ITK Mesh <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/Mesh.ipynb>`_
- `ITK PointBasedSpatialObject <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/PointBasedSpatialObject.ipynb>`_
- `VTK vtkPolyData <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/vtkPolyData.ipynb>`_
- `VTK vtkUnstructuredGrid <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/vtkUnstructuredGrid.ipynb>`_
- `pyvista PolyData <https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/examples/pyvista.PolyData.ipynb>`_
Expand Down
113 changes: 113 additions & 0 deletions examples/PointBasedSpatialObject.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"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"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from urllib.request import urlretrieve\n",
"import os\n",
"\n",
"import itk\n",
"\n",
"from itkwidgets import view"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Example data from ITKTubeTK: https://github.com/KitwareMedical/ITKTubeTK\n",
"\n",
"tubes_file = \"Normal071-VascularNetwork.tre\"\n",
"if not os.path.exists(tubes_file):\n",
" url = 'https://data.kitware.com/api/v1/item/5e1b3727af2e2eed35f5c48a/download'\n",
" urlretrieve(url, tubes_file)\n",
" \n",
"mra_file = \"Normal071-MRA.mha\"\n",
"if not os.path.exists(mra_file):\n",
" url = 'https://data.kitware.com/api/v1/item/5e1b3721af2e2eed35f5c482/download'\n",
" urlretrieve(url, mra_file)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"PixelType = itk.F\n",
"Dimension = 3\n",
" \n",
"# Read tre file\n",
"tubesReader = itk.SpatialObjectReader[Dimension].New()\n",
"tubesReader.SetFileName(tubes_file)\n",
"tubesReader.Update()\n",
"tubes = tubesReader.GetGroup()\n",
"\n",
"# Read mra image\n",
"mra = itk.imread(mra_file, PixelType)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0f0c8f7c10aa406e9a1f19a63a6f21ce",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, point_set_colors=array([[0.8392157, 0. , 0. ]], dtype…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(point_sets=tubes)"
]
}
],
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
71 changes: 45 additions & 26 deletions itkwidgets/_transform_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,33 @@ def _vtk_data_attributes_to_vtkjs(attributes):
vtkjs_attributes["arrays"] = arrays
return vtkjs_attributes

def _numpy_array_to_point_set(point_set_like):
point_values = np.asarray(point_set_like).astype(np.float32)
if len(
point_values.shape) > 1 and point_values.shape[1] == 2 or point_values.shape[1] == 3:
if point_values.shape[1] == 2:
point_values = np.hstack(
(point_values, -5.0e-6 * np.ones((point_values.shape[0], 1)))).astype(np.float32)
point_set = {'vtkClass': 'vtkPolyData'}
points = {'vtkClass': 'vtkPoints',
'name': '_points',
'numberOfComponents': 3,
'dataType': 'Float32Array',
'size': point_values.size,
'values': point_values}
point_set['points'] = points
vert_values = np.ones((point_values.size * 2,), dtype=np.uint32)
vert_values[1::2] = np.arange(point_values.size)
verts = {'vtkClass': 'vtkCellArray',
'name': '_verts',
'numberOfComponents': 1,
'dataType': 'Uint32Array',
'size': vert_values.size,
'values': vert_values}
point_set['verts'] = verts
return point_set
else:
return None

def to_itk_image(image_like):
if is_arraylike(image_like):
Expand Down Expand Up @@ -226,33 +253,25 @@ def to_point_set(point_set_like): # noqa: C901
point_set['pointData'] = point_data

return point_set
elif isinstance(point_set_like, itk.GroupSpatialObject):
children = point_set_like.GetChildren()

point_set = {'vtkClass': 'vtkPolyData'}

points_list = []
for ii in range(len(children)):
child = children[ii]
down_casted = itk.down_cast(child)
if isinstance(down_casted, itk.PointBasedSpatialObject):
n_points = down_casted.GetNumberOfPoints()
for ii in range(n_points):
point = down_casted.GetPoint(ii)
point.SetSpatialObject(down_casted)
position = point.GetPositionInWorldSpace()
points_list.append(list(position))
return _numpy_array_to_point_set(points_list)
elif is_arraylike(point_set_like):
point_values = np.asarray(point_set_like).astype(np.float32)
if len(
point_values.shape) > 1 and point_values.shape[1] == 2 or point_values.shape[1] == 3:
if point_values.shape[1] == 2:
point_values = np.hstack(
(point_values, -5.0e-6 * np.ones((point_values.shape[0], 1)))).astype(np.float32)
point_set = {'vtkClass': 'vtkPolyData'}
points = {'vtkClass': 'vtkPoints',
'name': '_points',
'numberOfComponents': 3,
'dataType': 'Float32Array',
'size': point_values.size,
'values': point_values}
point_set['points'] = points
vert_values = np.ones((point_values.size * 2,), dtype=np.uint32)
vert_values[1::2] = np.arange(point_values.size)
verts = {'vtkClass': 'vtkCellArray',
'name': '_verts',
'numberOfComponents': 1,
'dataType': 'Uint32Array',
'size': vert_values.size,
'values': vert_values}
point_set['verts'] = verts
return point_set
else:
return None
return _numpy_array_to_point_set(point_set_like)
elif have_vtk and isinstance(point_set_like, vtk.vtkPolyData):
from vtk.util.numpy_support import vtk_to_numpy
point_set = {'vtkClass': 'vtkPolyData'}
Expand Down
2 changes: 1 addition & 1 deletion js/lib/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
const viewProxy = this.model.itkVtkViewer.getViewProxy()
const representation = viewProxy.getRepresentations()[0];
const shadow = this.model.get('shadow')
representation.setUseShadow(shadow);
!!representation && representation.setUseShadow(shadow);
break
default:
throw new Error('Unknown view mode')
Expand Down

0 comments on commit 9ef6b16

Please sign in to comment.