Note
Go to the end to download the full example code.
Rendering Planes through 3D Data#
Controls: * 1 - toggle between volume rendering methods * 2 - toggle between volume rendering modes (‘volume’, ‘plane’) * [] - shift plane along plane normal * {} - decrease/increase plane thickness * Spacebar - stop/start animation
x/y/z/o - set plane normal along x/y/z or [1,1,1] oblique axis
import sys
import numpy as np
from vispy import app, scene, io
from vispy.visuals.transforms import STTransform
# Read volume
vol = np.load(io.load_data_file('volume/stent.npz'))['arr_0']
# Prepare canvas
canvas = scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
# Create the volume visual for plane rendering
plane = scene.visuals.Volume(
vol,
parent=view.scene,
raycasting_mode='plane',
method='mip',
plane_thickness=3.0,
plane_position=(128, 60, 64),
plane_normal=(1, 0, 0),
)
volume = scene.visuals.Volume(
vol,
parent=view.scene,
raycasting_mode='volume',
method='mip',
)
volume.set_gl_state('additive')
volume.opacity = 0.25
# Create a camera
cam = scene.cameras.TurntableCamera(
parent=view.scene, fov=60.0, azimuth=-42.0, elevation=30.0
)
view.camera = cam
# Create an XYZAxis visual
axis = scene.visuals.XYZAxis(parent=view)
s = STTransform(translate=(50, 50), scale=(50, 50, 50, 1))
affine = s.as_matrix()
axis.transform = affine
def update_axis_visual():
"""Sync XYZAxis visual with camera angles"""
axis.transform.reset()
axis.transform.rotate(cam.roll, (0, 0, 1))
axis.transform.rotate(cam.elevation, (1, 0, 0))
axis.transform.rotate(cam.azimuth, (0, 1, 0))
axis.transform.scale((50, 50, 0.001))
axis.transform.translate((50., 50.))
axis.update()
update_axis_visual()
@canvas.events.mouse_move.connect
def on_mouse_move(event):
if event.button == 1 and event.is_dragging:
update_axis_visual()
# Implement key presses
@canvas.events.key_press.connect
def on_key_press(event):
if event.text == '1':
methods = ['mip', 'average']
method = methods[(methods.index(plane.method) + 1) % 2]
print("Volume render method: %s" % method)
plane.method = method
elif event.text == '2':
modes = ['volume', 'plane']
if plane.raycasting_mode == modes[0]:
plane.raycasting_mode = modes[1]
print(modes[1])
else:
plane.raycasting_mode = modes[0]
print(modes[0])
elif event.text != '' and event.text in '{}':
t = -1 if event.text == '{' else 1
plane.plane_thickness += t
plane.plane_thickness += t
print(f"plane thickness: {plane.plane_thickness}")
elif event.text != '' and event.text in '[]':
shift = plane.plane_normal / np.linalg.norm(plane.plane_normal)
if event.text == '[':
plane.plane_position -= 2 * shift
elif event.text == ']':
plane.plane_position += 2 * shift
print(f"plane position: {plane.plane_position}")
elif event.text == 'x':
plane.plane_normal = [0, 0, 1]
elif event.text == 'y':
plane.plane_normal = [0, 1, 0]
elif event.text == 'z':
plane.plane_normal = [1, 0, 0]
elif event.text == 'o':
plane.plane_normal = [1, 1, 1]
elif event.text == ' ':
if timer.running:
timer.stop()
else:
timer.start()
def move_plane(event):
z_pos = plane.plane_position[0]
if z_pos < 32:
plane.plane_position = plane.plane_position + [1, 0, 0]
elif 32 < z_pos <= 220:
plane.plane_position = plane.plane_position - [1, 0, 0]
else:
plane.plane_position = (220, 64, 64)
timer = app.Timer('auto', connect=move_plane, start=True)
if __name__ == '__main__':
canvas.show()
print(__doc__)
if sys.flags.interactive == 0:
plane.plane_position = (220, 64, 64)
app.run()
Total running time of the script: (0 minutes 27.731 seconds)