{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%gui qt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Volume Rendering\n\nExample volume rendering\n\nControls:\n\n* 1 - toggle camera between first person (fly), regular 3D (turntable) and\n arcball\n* 2 - toggle between volume rendering methods\n* 3 - toggle between stent-CT / brain-MRI image\n* 4 - toggle between colormaps\n* 5 - toggle between interpolation methods\n* 0 - reset cameras\n* [] - decrease/increase isosurface threshold\n\nWith fly camera:\n\n* WASD or arrow keys - move around\n* SPACE - brake\n* FC - move up-down\n* IJKL or mouse - look around\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from itertools import cycle\n\nimport numpy as np\n\nfrom vispy import app, scene, io\nfrom vispy.color import get_colormaps, BaseColormap\nfrom vispy.visuals.transforms import STTransform\n\n# Read volume\nvol1 = np.load(io.load_data_file('volume/stent.npz'))['arr_0']\nvol2 = np.load(io.load_data_file('brain/mri.npz'))['data']\nvol2 = np.flipud(np.rollaxis(vol2, 1))\n\n# Prepare canvas\ncanvas = scene.SceneCanvas(keys='interactive', size=(800, 600), show=True)\ncanvas.measure_fps()\n\n# Set up a viewbox to display the image with interactive pan/zoom\nview = canvas.central_widget.add_view()\n\n# Create the volume visuals, only one is visible\nvolume1 = scene.visuals.Volume(vol1, parent=view.scene, threshold=0.225)\nvolume1.transform = scene.STTransform(translate=(64, 64, 0))\nvolume2 = scene.visuals.Volume(vol2, parent=view.scene, threshold=0.2)\nvolume2.visible = False\n\n# Create three cameras (Fly, Turntable and Arcball)\nfov = 60.\ncam1 = scene.cameras.FlyCamera(parent=view.scene, fov=fov, name='Fly')\ncam2 = scene.cameras.TurntableCamera(parent=view.scene, fov=fov,\n name='Turntable')\ncam3 = scene.cameras.ArcballCamera(parent=view.scene, fov=fov, name='Arcball')\nview.camera = cam2 # Select turntable at first\n\n# Create an XYZAxis visual\naxis = scene.visuals.XYZAxis(parent=view)\ns = STTransform(translate=(50, 50), scale=(50, 50, 50, 1))\naffine = s.as_matrix()\naxis.transform = affine\n\n\n# create colormaps that work well for translucent and additive volume rendering\nclass TransFire(BaseColormap):\n glsl_map = \"\"\"\n vec4 translucent_fire(float t) {\n return vec4(pow(t, 0.5), t, t*t, max(0, t*1.05 - 0.05));\n }\n \"\"\"\n\n\nclass TransGrays(BaseColormap):\n glsl_map = \"\"\"\n vec4 translucent_grays(float t) {\n return vec4(t, t, t, t*0.05);\n }\n \"\"\"\n\n# Setup colormap iterators\nopaque_cmaps = cycle(get_colormaps())\ntranslucent_cmaps = cycle([TransFire(), TransGrays()])\nopaque_cmap = next(opaque_cmaps)\ntranslucent_cmap = next(translucent_cmaps)\n\ninterp_methods = cycle(volume1.interpolation_methods)\ninterp = next(interp_methods)\n\n\n# Implement axis connection with cam2\n@canvas.events.mouse_move.connect\ndef on_mouse_move(event):\n if event.button == 1 and event.is_dragging:\n axis.transform.reset()\n\n axis.transform.rotate(cam2.roll, (0, 0, 1))\n axis.transform.rotate(cam2.elevation, (1, 0, 0))\n axis.transform.rotate(cam2.azimuth, (0, 1, 0))\n\n axis.transform.scale((50, 50, 0.001))\n axis.transform.translate((50., 50.))\n axis.update()\n\n\n# Implement key presses\n@canvas.events.key_press.connect\ndef on_key_press(event):\n global opaque_cmap, translucent_cmap\n if event.text == '1':\n cam_toggle = {cam1: cam2, cam2: cam3, cam3: cam1}\n view.camera = cam_toggle.get(view.camera, cam2)\n print(view.camera.name + ' camera')\n if view.camera is cam2:\n axis.visible = True\n else:\n axis.visible = False\n elif event.text == '2':\n methods = ['mip', 'translucent', 'iso', 'additive']\n method = methods[(methods.index(volume1.method) + 1) % 4]\n print(\"Volume render method: %s\" % method)\n cmap = opaque_cmap if method in ['mip', 'iso'] else translucent_cmap\n volume1.method = method\n volume1.cmap = cmap\n volume2.method = method\n volume2.cmap = cmap\n elif event.text == '3':\n volume1.visible = not volume1.visible\n volume2.visible = not volume1.visible\n elif event.text == '4':\n if volume1.method in ['mip', 'iso']:\n cmap = opaque_cmap = next(opaque_cmaps)\n else:\n cmap = translucent_cmap = next(translucent_cmaps)\n volume1.cmap = cmap\n volume2.cmap = cmap\n elif event.text == '5':\n interp = next(interp_methods)\n volume1.interpolation = interp\n volume2.interpolation = interp\n print(f\"Interpolation method: {interp}\")\n elif event.text == '0':\n cam1.set_range()\n cam3.set_range()\n elif event.text != '' and event.text in '[]':\n s = -0.025 if event.text == '[' else 0.025\n volume1.threshold += s\n volume2.threshold += s\n th = volume1.threshold if volume1.visible else volume2.threshold\n print(\"Isosurface threshold: %0.3f\" % th)\n\n# for testing performance\n# @canvas.connect\n# def on_draw(ev):\n# canvas.update()\n\nif __name__ == '__main__':\n print(__doc__)\n app.run()" ] } ], "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.9.19" } }, "nbformat": 4, "nbformat_minor": 0 }