This tutorial will get you started with PypeS. This is the first recommended step for using vmtk efficiently.
PypeS is the glue among vmtk scripts. It allows new scripts to be written easily and have a common interface, but, most of all, it allows single vmtk scripts to interact with each other, making vmtk modular and flexible.
For those who know object-oriented programming, PypeS is basically made up of two main classes:
- PypeScript: the base class for every high-level script. It manages parsing, it instantiates proper input/output methods for the script and keeps the script structure consistent
- Pype: the class that orchestrates the interaction among PypeScripts. It enables one to pipe one PypeScript after another, and it takes care of connecting the right arguments from one script to the other. It can be called from the command line by issuing pype pype-arguments or automatically instantiated from a pypescript.
Each PypeScript is at the same time:
- a script which can be called from the command line and piped to other scripts
- a class which can be called from Python code (e.g. inside a tkinter GUI)
Bearing this in mind, we can proceed with something more practical.
vmtkmarchingcubes --help (note for binary package users: you can type the same in PypePad, or you can do it from the command line by prepending the command with vmtk, i.e.).
vmtk vmtkmarchingcubes --help. The following text will be displayed:
vmtkmarchingcubes --help Creating vmtkMarchingCubes instance. Automatic piping vmtkmarchingcubes Parsing options vmtkmarchingcubes vmtkmarchingcubes : generate an isosurface of given level from a 3D image Input arguments: -id Id(int,1); default=0: script id -handle Self (self,1): handle to self -disabled Disabled (bool,1); default=0: disable execution and piping -i Image (vtkImageData,1): the input image -ifile ImageInputFileName(str,1): filename for the default Image Reader -array ArrayName (str,1): name of the array to work with -l Level(float,1); default=0.0: graylevel to generate the isosurface at -connectivity Connectivity (bool,1); default=0: only output the largest connected region of the isosurface -ofile SurfaceOutputFileName (str,1): filename for the default Surface writer Output arguments: -id Id (int,1); default= 0: script id -handle Self (self,1): handle to self -o Surface (vtkPolyData,1): the output surface
The first three lines are a log of what’s happening behind the scenes: a PypeS instance is created, which in turns creates a vmtkMarchingCubes instance and takes care of passing the right arguments to it. Below is the help for vmtkmarchingcubes, starting with the script name, a short description, a list of input arguments and a list of output arguments. These are in turn reported as the command line option, the corresponding instance variable name, its required type, the default value and a description.
As an example on how single scripts can be piped together, let’s now consider the following scripts:
- vmtkimagereader, which reads an image (the format is guessed from the filename extension) and does nothing else (except spitting out a vtkImageData object)
- vmtkmarchingcubes, which takes an image in input (a vtkImageData object) and generates a surface (a vtkPolyData object) using the Marching Cubes algorithm (default isosurface level is 0)
- vmtksurfacesmoothing, which takes a surface in input (a vtkPolyData object) and generates a smoothed version of it (again a vtkPolyData object) using the Taubin algorithm
- vmtksurfaceviewer, which takes in input a surface (a vtkPolyData object) and displays it within a rendering window
- vmtksurfacewriter, which writes a surface to a file (again, the format is guessed from the filename extension)
We can use vmtkmarchingcubes as a stand-alone script by using the built-in I/O functionality
vmtkmarchingcubes -ifile foo.vti -ofile foo.vtp
or we can build a pype that does the same thing
vmtkimagereader -ifile foo.vti --pipe vmtkmarchingcubes --pipe vmtksurfacewriter -ofile foo.vtp
What pype does is piping an argument of every script with the matching argument of the nearest preceding script. Two arguments match when they have the same type and their corresponding instance variables have the same name. Reading the log generated by the above PypeS will help clarifying what happens.
Let’s say we want to display the surface before writing it to disk. Let’s pipe the viewer at the end, then
vmtkimagereader -ifile foo.vti --pipe vmtkmarchingcubes --pipe vmtksurfaceviewer --pipe vmtksurfacewriter -ofile foo.vtp
And what about smoothing the surface before displaying it?
vmtkimagereader -ifile foo.vti --pipe vmtkmarchingcubes --pipe vmtksurfacesmoothing -passband 0.1 -iterations 30 --pipe vmtksurfaceviewer --pipe vmtksurfacewriter -ofile foo.vtp
As a remainder, note that the above could be simplified by using the built-in I/O functionality, this way
vmtkmarchingcubes -ifile foo.vti --pipe vmtksurfacesmoothing -passband 0.1 -iterations 30 -ofile foo.vtp --pipe vmtksurfaceviewer
Besides automatic piping seen here, the connections can be explicitly set by using the @ symbol, followed by the name of the script we want to pipe from, dot the piped option. For example, if we want to display the smoothed surface but write the unsmoothed one without changing the order of the scripts:
vmtkimagereader -ifile foo.vti --pipe vmtkmarchingcubes --pipe vmtksurfacesmoothing -passband 0.1 -iterations 30 --pipe vmtksurfaceviewer --pipe vmtksurfacewriter -i @vmtkmarchingcubes.o -ofile foo.vtp
A short-hand notation to use when one refers to the script immediately preceding the current one, is to omit the scriptname, like
vmtkimagereader -ifile foo.vti --pipe vmtkmarchingcubes --pipe vmtksurfacesmoothing -passband 0.1 -iterations 30 --pipe vmtksurfacewriter -i @.o -ofile foo.vtp
In this case, vmtksurfacewriter has the -ifile argument explicitly piped from the -o argument of vmtksurfacesmoothing. (In this example, the explicit piping has the same output as automatic piping) Use this short-hand notation carefully, since if you decide later on that you want to insert a script between vmtksurfacesmoothing and vmtksurfacewriter, @.o will end up referring to the newly inserted script.
One more feature solves the problem of discerning among scripts having the same name in the same pipe. Say we’ve got two surface readers and a writer
vmtksurfacereader -ifile foo1.vtp --pipe vmtksurfacereader -ifile foo2.vtp --pipe vmtksurfacewriter -ofile foo3.vtp
In this last case, the writer will write the surface coming from the second reader (the automatic piping mechanism looks for the first matching argument going backwards). In order to manually specify that we want to write the surface coming from the first reader, we can assign an id to each of the readers, and then explicitly pipe the surface of the first reader into the writer by using the script’s id
vmtksurfacereader -ifile foo1.vtp -id 1 --pipe vmtksurfacereader -ifile foo2.vtp -id 2 --pipe vmtksurfacewriter -i @vmtksurfacereader-1.o -ofile foo3.vtp
One last feature is the possibility of pushing input arguments along the pype. Say we want to read two images and extract a surface with Marching Cubes with a level of 20 for both. We can either write
vmtkmarchingcubes -ifile foo1.vti -l 20 --pipe vmtkmarchingcubes -ifile foo2.vti -l 20
or push the input argument -l along to the second vmtkmarchingcubes this way
vmtkmarchingcubes -ifile foo1.vti -l@ 20 --pipe vmtkmarchingcubes -ifile foo2.vti
In this example pushing wasn’t actually very convenient, but when things get complicated you’ll be glad pushing is around.
All the scripts in the toolkit can be glued this way (no matter if they belong to vmtk, as long as they are derived from the PypeScript base class). You can even write your own PypeScript derivatives and make them interact with vmtk the same way (this will be subject of a future tutorial).
Although the scripts in the examples pass VTK objects to each other, PypeS has no notion of what VTK is. Types are merely strings specified in the PypeScript derived classes, so if you want to reuse PypeS for different purposes you’re more than welcome to do it. If you want to understand more, just take a look at a script, e.g. vmtk/vmtkScripts/vmtkmarchingcubes.py. It’s a good chance to appreciate the fact that the amount of additional code required in each script to make everything work is minimal. If you consider that I/O, option parsing and usage printing are taken care of automatically, the code required is actually less.
Now you’re ready to explore vmtk scripts.