projects links |
Tutorials / PypesAdvanced
Advanced PypeS Tutorialby Carlos Remuzzi BEng, Biomedical Engineering, Freelance Developer, London UK Once you've gained confidence with the execution of vmtk from the command line you might want to push it a little further and start writing your own Python modules based on PypeS. In this tutorial we are going to guide you through the creation of a Python script implemented as a submodule of PypeS. Using PypeS as a parent class for your own scripts offers you the advantage of achieving the same performances of the vmtkscripts that you are already using and makes your own scripts able to easily interact with the rest of the vmtk framework. The module we are about to create has no relevant utility and serves purely as an example. Once completed, the script will display a series of isosurfaces extracted from a same 3D image. Each of the surfaces will represent a value of gray level. The gray levels represented will be limited to a range defined by the user. Creating a new moduleLet's start by opening a text editor and creating a new file. We can name it as #!/usr/bin/env python import sys from vmtk import pypes from vmtk import vmtkscripts The Defining the core structure of our moduleNow we can proceed to the definition of our module
customscript = 'customScript'
class customScript(pypes.pypeScript):
def __init__(self):
pypes.pypeScript.__init__(self)
def Execute(self):
pass
if __name__=='__main__':
main = pypes.pypeMain()
main.Arguments = sys.argv
main.Execute()
Let's go through the code we've just written:
Testing the core structure of our moduleAt this stage we can already appreciate the power of PypeS. Even though we've only defined the empty scaffold of our customScript without assigning any specific task, we can already run the code and notice that our module does more than what we have explicitly defined. Let's save customscript.py. Let's also make sure our file is executable by typing on the command line: $ chmod u+x customscript.py Now, if we run our code from the command line we will get the following output:
$ ./customscript.py
Creating customScript instance.
Automatic piping
Parsing options
Explicit piping
Input members:
Id = 0
Disabled = 0
Executing ...
Done executing .
Output members:
Id = 0
The output shows the typical behavior of a pypeScript. Even more impressively we can already invoke the --help option of our script although we have never cared to define any:
$ ./customscript.py --help
Creating customScript instance.
Automatic piping
Parsing options
Input arguments:
-id Id (str,1); default=0: script id
-handle Self (self,1): handle to self
-disabled Disabled (bool,1); default=0: disable execution and
piping
Output arguments:
-id Id (str,1); default=0: script id
-handle Self (self,1): handle to self
Completing the module instantiationAt this point we can finally start defining the specific properties of our script. In order to do so we want to provide our script with a definition and description of the data that will be exchanged with other pypeScripts. This definitions will be made into the class instantiator
self.Image = None
self.Surface = None
self.Levels=[]
self.SetScriptName('customScript')
self.SetScriptDoc('here goes a description')
self.SetInputMembers([
['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'],
['Levels','levels','float',-1,'','graylevels to generate the isosurface at'],
])
self.SetOutputMembers([
['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter']
])
Let's go through the code:
The SetInputMembers and the SetOutputMembers methodsAn input member is an information that the module expects to be given either as a parameter from the user or as an object from another module. An output member is what a module returns and makes available as reusable data along a pype. In a Pypes logic an output member from a first module becomes an input member for the following one. A pype chain is in fact a series of output members and input members flowing through modules. Now that we know what Input Members and Output members are we can learn how to define them properly for our module. We are going to see how the SetInputMembers method is used but the same rules apply for the SetOutputMembers method as well. self.SetInputMembers() takes a list of lists. Each list represents and describes an Input Member. You can add as many members as you need depending on the complexity of your module.
self.SetInputMembers([
**first input member**,
**second input member**,
...,
** N-th input member**
])
Let's go back to our example:
self.SetInputMembers([
['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'],
['Levels','levels','float',-1,'','graylevels to generate the isosurface at'],
])
For our module we need two Input Members: an image and the levels. So we added a list for Image and a second list for Levels. Now, let's go through the rules to define a single list. Each list will have in general 6 elements with a last 7th optional one. Let's go through the list element by element: [ 'Image' ,'i','vtkImageData',1,'','the input image','vmtkimagereader'] ['Image', 'i','vtkImageData',1,'','the input image','vmtkimagereader'] ['Image','i', 'vtkImageData',1,'','the input image','vmtkimagereader'] ['Image','i','vtkImageData', 1,'','the input image','vmtkimagereader'] ['Image','i','vtkImageData',1, '','the input image','vmtkimagereader'] ['Image','i','vtkImageData',1,'', 'the input image','vmtkimagereader'] Completing the module executionLet's now add the following lines into the
if self.Image == None:
self.PrintError('Error: No Image.')
if self.Levels == []:
self.PrintError('Error: No Levels')
self.marchingCubes = vmtkscripts.vmtkMarchingCubes()
self.marchingCubes.Image = self.Image
self.marchingCubes.Connectivity = 1
self.vmtkRenderer = vmtkscripts.vmtkRenderer()
self.vmtkRenderer.Initialize()
self.SurfaceViewer = vmtkscripts.vmtkSurfaceViewer()
self.SurfaceViewer.vmtkRenderer = self.vmtkRenderer
for level in self.Levels:
self.marchingCubes.Level = level
self.marchingCubes.Execute()
self.Surface = self.marchingCubes.Surface
self.SurfaceViewer.Surface = self.Surface
self.SurfaceViewer.BuildView()
|