Difference between revisions of "Slicer3:Python"
Line 189: | Line 189: | ||
* Slides: Numpy indexing and example: [[media:PythonSlicerNumpy.pdf]] | * Slides: Numpy indexing and example: [[media:PythonSlicerNumpy.pdf]] | ||
* See [[Slicer3:Python:DemianExamples | Demian's Example Code]] | * See [[Slicer3:Python:DemianExamples | Demian's Example Code]] | ||
+ | |||
+ | Slicer Python breakout session in Salt Lake City, Winter Project Week 2009, by Luca Antiga. | ||
+ | * Slides: [[media:ProjectWeekBreakout2009_SlicerPython.pdf]] |
Revision as of 18:10, 11 February 2009
Home < Slicer3:PythonContents
Status of Python in Slicer
In post-3.2 Slicer3, Python support is currently disabled by default. However, it is easy to enable and should compile on all tested platform (Mac, Windows, Linux). Though matplotlib is still not properly interacting with Slicer3, NumPy and Python support should work well for all platforms. Python command line modules are well supported, as is building full GUI modules in Python.
Python for scientific computing
Python has a fairly comprehensive package for scientific computing called SciPy. Of main interest to Slicer users/developers is NumPy. NumPy provides most of the features of the Matlab image processing toolbox and numeric computations, but in an Open Source package. A compelling reason to use NumPy is the ease of interaction and integration with Slicer3.
Slicer3 and Python
Enabling Python in the Slicer Build
- Edit slicer_variables.tcl
- Change "set ::USE_PYTHON "off"" to "on"
- Optional: If you prefer to use your system Python installation, change set ::USE_SYSTEM_PYTHON "false" to "true"
- This will give an error under Linux and Windows, but it can be easily fixed by adding the system path for Python, just search for "if { $::USE_SYSTEM_PYTHON } {"
- Optional: installing SciPy
- Download the scipy egg for your platform
- Unzip the egg in any directory that is part of Slicer's Python path, eg Slicer3-build/lib/Slicer3/Plugins
- SciPy should now be available in Slicer's Python interpreter
Build Slicer3 using "getbuildtest.tcl", i.e.:
Macintosh:Slicer3 blezek$ Scripts/getbuildtest.tcl
A new menu command Python Interpreter should appear on the Window menu.
This command should bring up the Python Console window.
Basic Slicer/Python tutorial
Note: this is initial documentation only, and is subject to change as the API evolves.
The Slicer Python interpreter has access to all Python modules referenced by the environment variable PYTHONPATH as well as the Slicer internal module. The Slicer module also supports the interface between Slicer Volume Nodes and NumPy. It would be instructive for the reader to review the NumPy documentation. For serious users of NumPy, there is the Guide to NumPy by Travis Oliphant for purchase.
The main interface to Slicer from Python is through the Slicer Python module. From there, the Python user can access any of Slicer's global objects and MRML tree. For example:
>>> import Slicer >>> Slicer.slicer <Slicer.Slicer object at 0x9f325f0> >>> Slicer.slicer.MRMLScene.GetNumberOfNodesByClass ( 'vtkMRMLVolumeNode' ) 0 >>>
In this case, no 'vtkMRMLVolumeNode's were loaded into Slicer.
VTK objects may be easily constructed, as well as any other object available from the C++ Slicer API.
>>> a = Slicer.slicer.vtkPolyData() >>> help ( a ) Help on vtkPolyData in module Slicer object: class vtkPolyData(vtkPointSet) | Method resolution order: | vtkPolyData | vtkPointSet | vtkDataSet <output truncated>
VTK objects created in this manner conform as closely as possible to the VTK Python bindings, but must be created through the slicer object inside the Slicer module. Each object may be fully subclassed following the meta object pattern.
A few details on Python in Slicer
Although it is possible to use Slicer within Python, enabling Python in a Slicer build does not trigger Python wrapping of C++ classes. Instead, Python has access to the Slicer API through Tcl. Whenever a constructor for an object is invoked, e.g.
from Slicer import slicer surface = slicer.vtkPolyData()
to create a VTK object, or
modelNode = slicer.vtkMRMLModelNode()
to create a MRML node, the Python interpreter tells the Tcl interpreter to instantiate a vtkPolyData or vtkMRMLModelNode (this happens through the Tcl wrappers which are built as part of the basic Slicer) and makes it available to the Python interface. More in detail, Python asks Tcl to illustrate what is a vtkPolyData, what are the parent classes and the methods, creates the whole class hierarchy on the fly, and creates an instance of that object. When one calls an object's method, like
numberOfPoints = surface.GetNumberOfPoints()
the Python interpreter relies the call to the Tcl interpreter and returns the proper return value. Any object available to Tcl is the same object available to Python, and this allows for a great flexibility, as everything lives in a common space.
Writing modules (especially interactive modules) in Python can lead to quite a speed up in the development cycle, since the code is more concise, it requires less file shuffling and, more than anything, it doesn't need to be recompiled (in some cases you don't even need to exit Slicer).
More than this, enabling Python in Slicer opens up the possibility of accessing a very wide range of Python libraries, such as Numpy and Scipy, from within Slicer (interactively or in modules), making the Slicer use cases potentially explode.
NumPy tutorial
Python and NumPy give direct access to the volume data in Slicer by wrapping the image data in a NumPy array object through the .ToArray() method on the volume node. This tutorial assumes you have installed SciPy.
>>> # Access the image data directly >>> from Slicer import slicer >>> nodes = slicer.ListVolumeNodes() >>> t2 = nodes['T2.hdr'] >>> data = t2.GetImageData().ToArray() >>> print data [[[ 0 0 0 ..., 0 0 0] [ 0 0 1 ..., 0 1 0] [ 0 0 0 ..., 0 0 0] ..., [ 0 8 0 ..., 0 1 2] [ 0 0 0 ..., 4 1 2] [ 0 0 2 ..., 6 0 2]] <<< Some output truncated >>> [[ 0 0 0 ..., 0 0 0] [ 0 0 0 ..., 0 0 0] [ 0 0 0 ..., 0 0 0] ..., [ 0 3 3 ..., 0 0 8] [ 0 6 0 ..., 5 3 13] [ 0 5 1 ..., 9 3 8]]] >>> # Load the image filtering package from scipy >>> import scipy.ndimage >>> # Filter into a new array >>> temp = scipy.ndimage.gaussian_filter ( data, 2.0 ) >>> # Copy back into Slicer >>> data[:] = temp[:] >>> t2.Modified()
Before:
After:
The NumPy command line module
In order to speed up experimentation, a Numpy command line module is available.
It takes in input one or two volume nodes and an output volume node, plus a path to a Python script residing in a text file.
Upon execution, input volume nodes are converted to ndarray variables named iarray and iarray2. The user simply has to put Numpy/Scipy code in the text file, taking care that the output array is stored in a variable named oarray. For example, the file could look like
import scipy.ndimage oarray = scipy.ndimage.gaussian_filter ( iarray, 2.0 )
The module will take care of taking the content of oarray and storing it in the output volume node (note: differently from the example above, and more in line with Slicer practices, the result of processing is stored in a different output volume, which is selected from the node selector).
To rerun different NumPy code on the input image, simply edit the script file, save it and rerun the module.
Matplotlib plotting functionality
Matplotlib may be used from within Slicer, but currently (on the Mac) the Tk backend locks up and crashes Slicer. However, Matplotlib may still be used through one of the non-GUI backends. More details can be found on the MatPlotLib pages.
import matplotlib matplotlib.use ( 'Agg' ) from pylab import *
t1 = arange(0.0, 5.0, 0.1) t2 = arange(0.0, 5.0, 0.02) t3 = arange(0.0, 2.0, 0.01) subplot(211) plot(t1, cos(2*pi*t1)*exp(-t1), 'bo', t2, cos(2*pi*t2)*exp(-t2), 'k') grid(True) title('A tale of 2 subplots') ylabel('Damped') subplot(212) plot(t3, cos(2*pi*t3), 'r--') grid(True) xlabel('time (s)') ylabel('Undamped') savefig ( 'MatplotlibExample.png' )
Where to go from here
Far from exhaustive, this documentation is intended to whet the appitite of researchers who love the power of Matlab, but feel trapped inside, unable to break out and deploy applications. This Python interface to Slicer is intended to help! Here are some selected resources to begin to understand the power of what the combined NumPy - Slicer package offers.
Python Language Information
Numpy and Scipy Information
- NumPy documentation
- Comprehensive Guide to NumPy by the current maintainer
- Old NumPy documentation (pdf)
- SciPy Documentation
- MatPlotLib
Writing Slicer Modules in Python
Painless Development in Slicer3 with Python, talk given by Demian Wassermann at the LMI, sept. 2008
- Slides: Introduction to Slicer3 with Python: media:PythonSlicer.pdf
- Slides: Numpy indexing and example: media:PythonSlicerNumpy.pdf
- See Demian's Example Code
Slicer Python breakout session in Salt Lake City, Winter Project Week 2009, by Luca Antiga.