Skip to content

Commit

Permalink
ENH: Add traitlet for volume rendering blend mode
Browse files Browse the repository at this point in the history
Closes #200

The itk-vtk-viewer bump also Closes #238
  • Loading branch information
thewtex committed Jan 15, 2020
1 parent b83d12a commit 1caad0e
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 55 deletions.
115 changes: 67 additions & 48 deletions itkwidgets/widget_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ class Viewer(ViewerParent):
default_value=0.2,
help="Volume rendering gradient opacity, from (0.0, 1.0]").tag(
sync=True)
blend = CaselessStrEnum(
('composite',
'max',
'min',
'average'),
default_value='composite',
help="Volume rendering blend mode").tag(sync=True)
roi = NDArray(dtype=np.float64, default_value=np.zeros((2, 3), dtype=np.float64),
help="Region of interest: [[lower_x, lower_y, lower_z), (upper_x, upper_y, upper_z]]")\
.tag(sync=True, **array_serialization)\
Expand Down Expand Up @@ -553,11 +560,15 @@ def roi_slice(self):


def view(image=None, # noqa: C901
gradient_opacity=0.22, cmap=cm.viridis, slicing_planes=False,
select_roi=False, shadow=True, interpolation=True,
point_sets=[], point_set_colors=[], point_set_opacities=[
], point_set_representations=[], # point_set_sizes=[],
geometries=[], geometry_colors=[], geometry_opacities=[],
cmap=cm.viridis,
select_roi=False,
interpolation=True,
gradient_opacity=0.22, slicing_planes=False, shadow=True, blend='composite',
point_sets=[],
point_set_colors=[], point_set_opacities=[], point_set_representations=[],
# point_set_sizes=[],
geometries=[],
geometry_colors=[], geometry_opacities=[],
ui_collapsed=False, rotate=False, annotations=True, mode='v',
**kwargs):
"""View the image and/or point sets and/or geometries.
Expand All @@ -580,37 +591,69 @@ def view(image=None, # noqa: C901
Parameters
----------
General Interface
^^^^^^^^^^^^^^^^^
ui_collapsed : bool, optional, default: False
Collapse the native widget user interface.
rotate : bool, optional, default: False
Continuously rotate the camera around the scene in volume rendering
mode.
annotations : bool, optional, default: True
Display annotations describing orientation and the value of a
mouse-position-based data probe.
mode: 'x', 'y', 'z', or 'v', optional, default: 'v'
Only relevant for 3D scenes.
Viewing mode:
'x': x-plane
'y': y-plane
'z': z-plane
'v': volume rendering
camera: 3x3 numpy float32 array, optional
Camera parameters:
[[position_x, position_y, position_z],
[focal_point_x, focal_point_y, focal_point_z],
[view_up_x, view_up_y, view_up_z]]
Images
^^^^^^
image : array_like, itk.Image, or vtk.vtkImageData
The 2D or 3D image to visualize.
gradient_opacity: float, optional, default: 0.22
Gradient opacity for the volume rendering, in the range (0.0, 1.0].
vmin: float, optional, default: None
Value that maps to the minimum of image colormap. Defaults to minimum of
the image pixel buffer.
vmax: float, optional, default: None
Value that maps to the minimum of image colormap. Defaults to maximum of
the image pixel buffer.
cmap: string, optional, default: 'Viridis (matplotlib)'
Colormap. Some valid values available at itkwidgets.cm.*
slicing_planes: bool, optional, default: False
Enable slicing planes on the volume rendering.
select_roi: bool, optional, default: False
Enable an interactive region of interest widget for the image.
interpolation: bool, optional, default: True
Linear as opposed to nearest neighbor interpolation for image slices.
shadow: bool, optional, default: True
Use shadowing in the volume rendering.
gradient_opacity: float, optional, default: 0.22
Gradient opacity for composite volume rendering, in the range (0.0, 1.0].
vmin: float, optional, default: None
Value that maps to the minimum of image colormap. Defaults to minimum of
the image pixel buffer.
slicing_planes: bool, optional, default: False
Enable slicing planes on the volume rendering.
vmax: float, optional, default: None
Value that maps to the minimum of image colormap. Defaults to maximum of
the image pixel buffer.
shadow: bool, optional, default: True
Use shadowing with composite volume rendering.
blend: 'composite', 'max', 'min', or 'average', optional, default: 'composite'
Volume rendering blend mode.
Point Sets
^^^^^^^^^^
Expand Down Expand Up @@ -641,34 +684,6 @@ def view(image=None, # noqa: C901
geometry_opacities: list of floats, optional, default: [1.0,]*n
Opacity for the point sets, in the range (0.0, 1.0].
General Interface
^^^^^^^^^^^^^^^^^
ui_collapsed : bool, optional, default: False
Collapse the native widget user interface.
rotate : bool, optional, default: False
Continuously rotate the camera around the scene in volume rendering
mode.
annotations : bool, optional, default: True
Display annotations describing orientation and the value of a
mouse-position-based data probe.
mode: 'x', 'y', 'z', or 'v', optional, default: 'v'
Only relevant for 3D images.
Viewing mode:
'x': x-plane
'y': y-plane
'z': z-plane
'v': volume rendering
camera: 3x3 numpy float32 array, optional
Camera parameters:
[[position_x, position_y, position_z],
[focal_point_x, focal_point_y, focal_point_z],
[view_up_x, view_up_y, view_up_z]]
Other Parameters
----------------
Expand Down Expand Up @@ -765,8 +780,12 @@ def view(image=None, # noqa: C901
if image is None and len(images): # only one image is rendered
image = images[0]

viewer = Viewer(image=image, interpolation=interpolation, cmap=cmap, shadow=shadow,
select_roi=select_roi, slicing_planes=slicing_planes, gradient_opacity=gradient_opacity,
viewer = Viewer(image=image,
cmap=cmap,
select_roi=select_roi,
interpolation=interpolation,
gradient_opacity=gradient_opacity, slicing_planes=slicing_planes,
shadow=shadow, blend=blend,
point_sets=point_sets,
point_set_colors=point_set_colors,
point_set_opacities=point_set_opacities,
Expand Down
51 changes: 51 additions & 0 deletions js/lib/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const ViewerModel = widgets.DOMWidgetModel.extend({
shadow: true,
slicing_planes: false,
gradient_opacity: 0.2,
blend: 'composite',
roi: new Float64Array([0., 0., 0., 0., 0., 0.]),
_largest_roi: new Float64Array([0., 0., 0., 0., 0., 0.]),
select_roi: false,
Expand Down Expand Up @@ -494,6 +495,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
this.shadow_changed()
this.slicing_planes_changed()
this.gradient_opacity_changed()
this.blend_changed()
}
this.ui_collapsed_changed()
this.rotate_changed()
Expand Down Expand Up @@ -583,6 +585,31 @@ const ViewerView = widgets.DOMWidgetView.extend({
}
this.model.itkVtkViewer.subscribeToggleCroppingPlanes(onToggleCroppingPlanes)

const onBlendModeChanged = (blend) => {
let pythonMode = null
switch(blend) {
case 0:
pythonMode = 'composite'
break
case 1:
pythonMode = 'max'
break
case 2:
pythonMode = 'min'
break
case 3:
pythonMode = 'average'
break
default:
throw new Error('Unknown blend mode')
}
if (pythonMode !== this.model.get('blend')) {
this.model.set('blend', pythonMode)
this.model.save_changes()
}
}
this.model.itkVtkViewer.subscribeBlendModeChanged(onBlendModeChanged)

if (!this.model.use2D) {
const onViewModeChanged = (mode) => {
let pythonMode = null;
Expand Down Expand Up @@ -680,6 +707,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
this.model.on('change:shadow', this.shadow_changed, this)
this.model.on('change:slicing_planes', this.slicing_planes_changed, this)
this.model.on('change:gradient_opacity', this.gradient_opacity_changed, this)
this.model.on('change:blend', this.blend_changed, this)
this.model.on('change:select_roi', this.select_roi_changed, this)
this.model.on('change:_scale_factors', this.scale_factors_changed, this)
this.model.on('change:point_sets', this.point_sets_changed, this)
Expand Down Expand Up @@ -1019,6 +1047,29 @@ const ViewerView = widgets.DOMWidgetView.extend({
}
},

blend_changed: function() {
const blend = this.model.get('blend')
if (this.model.hasOwnProperty('itkVtkViewer') && !this.model.use2D) {
switch (blend) {
case 'composite':
this.model.itkVtkViewer.setBlendMode(0)
break
case 'max':
this.model.itkVtkViewer.setBlendMode(1)
break
case 'min':
this.model.itkVtkViewer.setBlendMode(2)
break
case 'average':
this.model.itkVtkViewer.setBlendMode(3)
break
default:
throw new Error('Unexpected blend mode')
}

}
},

select_roi_changed: function() {
const select_roi = this.model.get('select_roi')
if (this.model.hasOwnProperty('itkVtkViewer')) {
Expand Down
12 changes: 6 additions & 6 deletions js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"copy-webpack-plugin": "^4.5.1",
"css-element-queries": "^1.0.2",
"itk": "^10.2.0",
"itk-vtk-viewer": "^9.10.3",
"itk-vtk-viewer": "^9.10.4",
"jupyter-dataserializers": "^2.1.0",
"mobx": "^5.13.0",
"vtk.js": "^13.0.0"
Expand Down

0 comments on commit 1caad0e

Please sign in to comment.