/usr/src/WrapITK/Documentation/Guide.txt is in libinsighttoolkit3-dev 3.20.1+git20120521-6build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | WrapITK README
--------------
WrapITK is a project designed to allow classes from ITK (and custom, classes that interact with ITK) to be "wrapped" for use with scripting languages like Python, Tcl, and Java.
Note that ITK already has a wrapping infrastructure. This project aims to be address the following deficits of the existing wrappers (and others):
- The ITK wrapping system is difficult to understand and maintain. WrapITK was written -- and thoroughly documented -- to be as easy as possible to understand, maintain, and extend.
- It is non-trivial to add wrappers for different ITK classes to the system. In WrapITK, adding a wrapper can be as simple as adding a single file containing a few well-documented cmake macros.
- It is difficult if not impossible to add original-style ITK wrappers for external C++ classes that interact with ITK. WrapITK provides explicit hooks for external C++ classes to be wrapped and even installed in the WrapITK tree so that they interact seamlessly with the other wrapped classes.
- Once the ITK wrappers are built, using them from within the target languages is in many cases painful, forcing Python code (for example) to look a lot like C++ code, but nastier. In particular, template types must be hard-coded into every function name. WrapITK attempts to address this in Python by providing run-time lookup of templated types. Additionally, WrapITK ensures that SmartPointers are always returned and acceptable as input, so no bare pointers are ever exposed to Python. This is not the case in the standard ITK wrappers.
An example:
C++:
typedef itk::Image<unsigned short, 2> ImageI2;
ImageI2::Pointer image = ImageUS2::New();
typedef itk::ImageFileWriter<ImageUS2> Writer;
Writer::Pointer writer = Writer::New();
writer->SetInput(image);
writer->SetFileName("foo.tif");
Python with current ITK wrappers:
image = itk.ImageUS2_Pointer(itk.ImageUS2_New())
witer = itk.ImageFileWriterIUS2_Pointer(itk.ImageFileWriterIUS2_New())
writer.SetInput(image);
writer.SetFileName("foo.tif");
Python with WrapITK:
image = itk.Image[itk.US, 2].New()
writer = itk.ImageFileWriter[image].New(Input=image, FileName="foo.tif")
BUILDING
--------
WrapITK requires ITK and CableSwig to have been previously downloaded and built. To get CableSwig, simply run:
cvs -d:pserver:anonymous@public.kitware.com:/cvsroot/CableSwig co CableSwig
(Note that no cvs login is needed here.)
If you check out CableSwig into the Insight/Utilities directory, then it will be built as a part of ITK, and will be automatically detected by WrapITK when ITK is found.
WrapITK will work properly with a CVS checkout of ITK from 2006-1-31 or later, or with the ITK 2.4.1 release. If you are using 2.4.1, there are several required patches to correct bugs in ITK that must be applied. Follow the directions in WrapITK/patches to do so. Additionally, there are some optional patches to the ITK source in WrapITK/patches/optional which can be applied to either a CVS checkout of ITK or to version 2.4.1. These optional patches provide better support for python by providing __str__ methods and the like.
After CableSwig and ITK have been (possibly patched) and built, building WrapITK with cmake is simple. Run ccmake in a new directory with the path to the WrapITK source tree as the first argument, and provide the locations of the ITK and CableSwig build trees if ccmake so requests. Build options are relatively self-explanatory.
Note that each individual filter that is wrapped can declare which dimensions it should be wrapped for, and what image types it can accept. For example, a filter could declare that it should only be wrapped for 3D images with floating-point typed pixels. In this case, then wrappers will only be created if the user has selected to build 3-dimensional image wrappers and has selected one or more floating point types (e.g. double or float) in ccmake. Thus, the ccmake configuration specifies the maximum possible range of image and filter types to be created, and each filter is wrapped for some subset of that range.
INSTALLING
----------
(0) Philosophy
WrapITK is both a tool for users and for developers who wish to create wrappers for additional classes from ITK or classes that interact with ITK. The best way to both use WrapITK and extend it is by installing it into a known location. Once installed, using WrapITK is easy because the installation process informs Python where to look for the itk libraries. Installation makes extending WrapITK easy as well because extensions can be subsequently installed to the same place and used seamlessly.
The install location is specified in ccmake with the CMAKE_INSTALL_PREFIX variable. Simply run 'make install' (if you are using make as the build tool) to install the package.
(1) FindWrapITK.cmake and WrapITK.pth
In addition to the libraries and script files installed into CMAKE_INSTALL_PREFIX/WRAP_ITK_INSTALL_LOCATION, a cmake script will be placed in the proper directory in the CMake tree so that the command FIND_PACKAGE(WrapITK) will work with no additional configuration, making developing external projects (see below) very easy.
Moreover (as described above), a file called 'WrapITK.pth' will be installed in the python site-packages directory which points python at the WrapITK scripts, so that they can be imported from within python with no additional configuration.
In some cases, it is not desirable to install these files (which require superuser/administrator privileges to install). If so, turn off the INSTALL_WRAP_ITK_COMPATIBILITY option in ccmake. If this option is off, these files can be manually installed by building the 'install_wrapitk_compatibility' target. (E.g. 'make install_wrapitk_compatibility' if using makefiles.) If INSTALL_WRAP_ITK_COMPATIBILITY is on, manually building the install_wrapitk_compatibility target does nothing.
PYTHON USAGE
------------
(0) Configuring Python and Importing the Libraries
If WrapITK has been installed, then using it from within python is trivial: simply issue the command "import itk", and you are ready to go. This is because WrapITK installs a pth file in the python site-packages directory so that python knows where to find the itk scripts.
If WrapITK has not been installed, then you will either need to set the PYTHONPATH environment variable to contain the directory /path-to-WrapITK-build/Python, add this path to sys.paths within python, or start python from that directory. After this, "import itk" will work properly.
(1) Basic Usage
Most class in the itk python module are "template proxy classes" that encapsulate all of the template instantiations that were created at build time. If three-dimensional unsigned char and unsigned short image types were created, they can be accessed as follows:
itk.Image[itk.UC, 3] -or- itk.Image.UC3
itk.Image[itk.US, 3] -or- itk.Image.US3
Filters templated on images can be similarly accessed:
itk.ImageFileReader[itk.Image[itk.UC,3]]
or
itk.ImageFileReader[itk.Image.UC3]
or even
itk.ImageFileReader[image]
if 'image' is of type UC3. This makes it easy to write generic routines which can deal with any input image type.
Each class has a New() method which returns a smart pointer to that class. The New() method in python has some additional features:
- Arguments to the new method are assumed to be filter inputs. So you could write:
adder = itk.AddImageFilter[...].New()
adder.SetInput1(inputA)
adder.SetInput2(inputB)
or you could write
adder = itk.AddImageFilter[...].New(inputA, inputB)
- Additionally, keyword arguments are allowed as well. Keyword arguments cause the corresponding "Set..." method to be called, so you could write the following:
itk.ImageFileWriter[image].New(image, FileName="foo.tif")
or
itk.ImageFileWriter[image].New(Input=image, FileName="foo.tif")
(2) Advanced Features
As an extra bonus, it is possible to view the doxygen documentation for each class as the python docstring. This string is available as:
print itk.Image.__doc__
or even better (if you use iPython)
itk.Image?
Several steps are necessary to obtain this nirvana, however. First, when configuring the build in ccmake, you must set DOXYGEN_MAN_PATH to some directory where man pages for the ITK classes will be created. Then, after the build, you must run 'make_doxygen_config.py' from within the Python directory in the build directory, to collect information about the wrapped classes and create a doxygen configuration file to make these man pages. Finally, run doxygen with that configuration file. After these three simple steps, class docstrings will contain the man page information. Note that this is limited to systems which support the python "commands" module, and which have "groff" in the path. This basically means anything but windows will work. (Cygwin should work too.)
In addition (as mentioned above), WrapITK by default ensures that no bare pointers are ever returned to python: instead reference-counting SmartPointers are used. However, there may be times when extracting a bare pointer or creating a new SmartPointer is necessary. To get a bare pointer from a smart pointer, use the GetPointer() method, as in ITK proper. To create a new smart pointer, the SmartPointer template proxy class can be used just as above:
smartPtr = itk.SmartPointer[itk.Image[itk.US, 2]](image.GetPointer())
or just
smartPtr = itk.SmartPointer[image](image.GetPointer())
ADDING OR REMOVING WRAPPED ITK CLASSES
--------------------------------------
To minimize build times and library size, it is possible to manually prevent various classes from being wrapped. WrapITK is divided into several sub-libraries, each with a sub-directory: Algorithms, BasicFilters[ABC], Common[AB], IO, Numerics, SpatialObject, and VXLNumerics. Within these directories are sets or wrap_XXX.cmake files, where XXX is the name of the class (or set of classes) to be wrapped. To prevent one of these classes from being wrapped, simply rename the file to anything that does *not* start with wrap_ and end with cmake. (E.g. append ".notwrapped" to the name.) (This is probably unsafe to do in the Common, Numerics, or IO directories.)
To add classes to be wrapped, it is recommended that you create a simple "External Project" described below. If this is out of the question, you could create additional wrap_XXX.cmake files in the appropriate directory. (Read on for instructions as to what to put in these files.)
EXTERNAL PROJECTS
-----------------
In WrapITK/ExternalProjects there are several sample "External Projects" that can be built to provide additional functionality to WrapITK and to serve as a demonstration for how to create your own such projects. One project is an ITK-VTK bridge, and the other is a Python class to allow conversion from Numeric/Numarray/numpy matrices to ITK images (and vice-versa).
(0) Building
To build an external project, first ensure that WrapITK has been properly built. Then use ccmake to configure a build directory for the external project. If WrapITK has not been installed, you will have to manually enter the path to the WrapITK build directory.
(1) Usage
Once an external project has been built, it can be tested directly from the build tree. Start python in the external project build directory's Python subdirectory, and run the command 'import ProjectConfig' (or 'import ProjectConfig-[Debug|Release|...]' if you were using an IDE, depending on which build configuration was set from the IDE). This command sets up the search paths properly so that WrapITK and the newly-created library files can be found. Then type 'import ...' (where '...' is replaced with the name of the external project; e.g. 'import BufferConversion'), and use the project.
(2) Installation
Simply type 'make install' (or run your IDE's install step) to install the external project into the WrapITK tree (provided WrapITK has already been installed). Now the external project can be used just like any of the other WrapITK libraries, and it will be imported into the 'itk' namespace when the 'import itk' command is issued from Python.
DEVELOPER GUIDE
---------------
What follows is a brief description of how the WrapITK build system works, haw it can be extended, and how to write external projects.
(1) Creating a CMakeLists.txt file for a wrapper library
Each WrapITK sub-library (e.g. 'Base', or 'SpatialObject') lives in a sub-directory of the WrapITK project (within the 'Modules' directory) with a CMakeLists.txt file that describes how that library and language support files (e.g. python template definitions) is to be created. Moreover, any external project will need a similar file to describe how to create that library.
See "SampleCMakeLists.txt" in this directory for a description of each macro and option that can appear in such a file. What follows is the usual set of commands that will appear:
BEGIN_WRAPPER_LIBRARY("MySpatialObjectExtensions")
SET(WRAPPER_LIBRARY_DEPENDS SpatialObject Base)
SET(WRAPPER_LIBRARY_LINK_LIBRARIES ITKCommon)
WRAPPER_LIBRARY_CREATE_WRAP_FILES()
WRAPPER_LIBRARY_CREATE_LIBRARY()
BEGIN_WRAPPER_LIBRARY() sets up the environment to wrap a set of classes into a library with a given name. This macro is defined in ConfigureWrapping.cmake.
WRAPPER_LIBRARY_DEPENDS stores the list of WrapITK libraries on which the current library depends (e.g. which libraries wrap classes like Image or SpatialObject, that are going to be used in the current library). Every project should at least depend on Base.
WRAPPER_LIBRARY_LINK_LIBRARIES stores a set of other libraries to add at link time. This can be 3rd party libraries that you will use (be sure to properly set LINK_DIRECTORIES in this case), or more commonly, the ITK libraries that need to be linked in, like ITKCommon, ITKIO, or other.
WRAPPER_LIBRARY_CREATE_WRAP_FILES() scans all of the wrap_XXX.cmake files in the current directory and uses the directives within to create CableSwig input files for these classes. Information about template instantiations is also recorded for the language support files that are created next. This macro is defined in CreateCableSwigInputs.cmake, and calls language support macros from CreateLanguageSupport.cmake.
Finally, WRAPPER_LIBRARY_CREATE_LIBRARY() creates rules to parse the CalbeSwig inputs and compile a wrapper library. This macro also causes various language support files to be created (python only currently) which make it easy to load that library in python, and which know about the template instances defined. This macro is defined in CreateWrapperLibrary.cmake, and calls language support macros from CreateLanguageSupport.cmake.
(2) Creating wrap_XXX.cmake files to wrap classes
A wrap_XXX.cmake file defines a group of classes and/or template instantiations to be wrapped. Often one such file is defined for each class wrapped, but this is not strictly necessary.
Within such a file, directives are issued to wrap classes and particular template instances. All of the available directives are defined and documented in CreateCableSwigInputs.cmake. The basics are presented here:
- WRAP_INCLUDE("header.h") -- causes the named header to be #included in the generated files.
- WRAP_CLASS("fully_qualified::ClassName" [POINTER|POINTER_WITH_SUPERCLASS]) -- causes a templated class to be wrapped. All namespaces must be included in the class name, and note that no template instantiation is given. Template instantiations are created with various WRAP directives, described below, between invocations of WRAP_CLASS() and END_WRAP_CLASS().
WRAP_CLASS issues an implicit call to WRAP_INCLUDE("ClassName.h"), so the header for the wrapped class itself does not need to be manually included. To disable this behavior, set WRAPPER_AUTO_INCLUDE_HEADERS to OFF.
The final optional parameter to WRAP_CLASS is POINTER or POINTER_WITH_SUPERCLASS. If no options are passed, then the class is wrapped as-is. If POINTER is passed, then the class and the typedef'd class::Pointer type is wrapped. (Class::Pointer had better be a SmartPointer instantiation, or things won't work. This is always the case for ITK-style code.) If POINTER_WITH_SUPERCLASS is provided, then class::Pointer, class::Superclass and class::Superclass::Pointer are all wrapped. (Again, this only works for ITK-style code where the class has a typedef'd Superclass, and the superclass has Self and Pointer typedefs.)
- WRAP_TEMPLATE("mangled_suffix" "template parameters") -- When issued between WRAP_CLASS and END_WRAP_CLASS, this command causes a particular template instantiation of the current class to be wrapped. The parameter "mangled_suffix" is a suffix to append to the class's name that uniquely identifies this particular template instantiation, and "template parameters" are whatever should go between the < > template instantiation brackets. (Do not include the brackets.) If you are wrapping a filter, there are simpler macros to use, which are defined at the bottom of CreateCableSwigInputs and described below.
- WRAP_type(size) (where 'type' is INT, SIGN_INT, REAL, VECTOR_REAL, COV_VECTOR_REAL or RGB) -- create a template instantiation with 'size' itk::Image parameters of the given pixel type. So if you are wrapping a filter which should take two images with integral pixel types, write WRAP_IMAGE_FILTER_USIGN_INT(2). The specific integral data type(s) (char, long, or short in the WRAP_IMAGE_FILTER_USIGN_INT case) will be determined by the user-selected build parameters (e.g. WRAP_long, and WRAP_short).
- WRAP_type_DIMS(size dims) (with 'type' as above) -- Wrap a filter for certain dimensions only. Dims should be either a semicolon-separated list of valid dimensions, or something of the form '3+' to specify that the filter can be instantiated only for three- and higher-dimensional images. Note that if the user has not selected to wrap a given dimension at build time, a filter wrapped with WRAP_type_DIMS will not be instantiated: the final dimensions wrapped are the *intersection* of the user-selected dimensions and the valid dimensions declared with WRAP_type_DIMS.
- END_WRAP_CLASS() -- end a block of template instantiations for a particular class.
- WRAP_NON_TEMPLATE_CLASS("fully_qualified::ClassName" [POINTER|POINTER_WITH_SUPERCLASS]) -- Same as WRAP_CLASS, but creates a wrapper for a non-templated class. No END_WRAP_CLASS() is necessary after this macro because there is no block of template instantiating commands to close.
(3) Top-level CMakeLists for external projects
In addition to having a set of wrap_XXX.cmake files and the proper commands to read in these files and create a library (all described above), an external project's CMakeLists file needs at least one additional command to start it out:
FIND_PACKAGE(WrapITK REQUIRED)
This command will cause cmake to try to find the WrapITK build/install directory. If WrapITK has been installed, this will work on the first try. Otherwise, you will have to set (within ccmake, or in the CMakeLists if you prefer) the variable WrapITK_DIR to contain the path to the WrapITK build directory.
|