bergtholdt / cyitk

A simple ITK-to-Python bridge written in Cython

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

cyitk

A simple ITK-to-Python bridge written in Cython

On of the main bottlenecks in prototyping ITK code (ITK) in C++ is writing very high-level code: once you’ve written you algorithmics by assembling a bunch of ITK classes in C++, say in one or more functions, you have to write a main in which you put them together, expose parameters, parse arguments, do your I/O and go through a complie cycle. To visualize results, you typically write out a file and view it with an external application.

cyitk lets you write your ITK code in C++ and quickly make high-level functions available to Python, where you can do I/O and visualization interactively. No main’s anymore during prototyping. In addition it makes it very easy to switch back and forth between Numpy and ITK in the context of the same script.

cyitk is not intended to be a ITK Pyhton wrapper or a tool to make ITK easier to use. For that, you should look into WrapITK or SimpleITK. cyitk is for those who use ITK in C++ and just want to glue their C++ snippets flexibly with Python, trying out stuff, exploring parameter spaces, looking at intermediate results interactively (a-la Matlab), and in the end want to find themselves with working C++ code with no extra dependencies except ITK.

Note: you don’t have to learn Cython to use cyitk.

Author

  • Luca Antiga, Orobix Srl

Dependencies

Example

Here’s a quick example (taken from cyitk/Testing/cyitkGaussianSmoothingTest and cyitk/Testing/cyitkGaussianSmoothingAutoTest).

Say you have a C++ function GaussianSmoothing that applies an ITK filter to an input image and provides the filtered output image. In addition the function requires to specify the sigma of the Gaussian filter.

GaussianSmoothing.h

#ifndef __GaussianSmoothing_h #define __GaussianSmoothing_h #include “itkImage.h” #include “itkRecursiveGaussianImageFilter.h” namespace itk { typedef Image<float,2> ImageType; void GaussianSmoothing(ImageType* inputImage, ImageType* outputImage, double sigma) { typedef RecursiveGaussianImageFilter RecursiveGaussianFilterType; RecursiveGaussianFilterType::Pointer gaussianFilter = RecursiveGaussianFilterType::New(); gaussianFilter→SetInput(inputImage); gaussianFilter→SetSigma(sigma); gaussianFilter→Update(); outputImage→Graft(gaussianFilter→GetOutput()); } } #endif

Note: the C++ code does not necessarily have to be all in a .h file, and it could also be provided by a static or shared library. In this example it is in a .h file for simplicity.
In order to make it available as a Python module, you can rely on automated generation of the Cython glue code. If you want more control, you can do things manually, just take a look at cyitk/Testing/cyitkGaussianSmoothingTest.

Automated glue code generation

You can generate the Cython glue code automatically (and in fact never deal with Cython directly) by annotating each exported function in the C++ file with a comment starting with //@cyitk and containing the function signature, whereby the ITK image typedefs are replaced by cyitk image types, prepended by a @ character:

//@cyitk void GaussianSmoothingF2(@ImageF2 inputImage, @ImageF2 outputImage, double sigma)

You can place the comment anywhere in the file, I usually place it right above the corresponding function signature.

Write a CMakeLists.txt file:

CMakeLists.txt

cmake_minimum_required(VERSION 2.6) project(CYITK_GAUSSIAN_SMOOTHING) find_path(CYITK_SOURCE_DIR cyitkGenerateImageClass.cmake "") include(${CYITK_SOURCE_DIR}/cyitkGeneratePyx.cmake NO_POLICY_SCOPE) include(${CYITK_SOURCE_DIR}/cyitkGenerateImageClass.cmake NO_POLICY_SCOPE) include(${CYITK_SOURCE_DIR}/cyitkConfigureModule.cmake NO_POLICY_SCOPE) set(CYITK_WRAPPED_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(CYITK_MODULE_NAME cyitkGaussianSmoothing) cyitk_generate_pyx(${CMAKE_CURRENT_SOURCE_DIR}/GaussianSmoothing.h ${CYITK_MODULE_NAME}.pyx) cyitk_generate_image_class(“float” 2 F2) cyitk_configure_module(${CYITK_MODULE_NAME} ${CYITK_MODULE_NAME}.pyx)

The lines you should care about are

set(CYITK_MODULE_NAME cyitkGaussianSmoothing)
give a name to the Python module to be generated

cyitk_generate_pyx(${CMAKE_CURRENT_SOURCE_DIR}/GaussianSmoothing.h ${CYITK_MODULE_NAME}.pyx)
generate the Cython glue code based on the //@cytik comment in the GaussianSmoothing.h file

cyitk_generate_image_class("float" 2 F2)
generate the cyitk glue Image classes. Since the C++ function was operating on itk::Image<float,2>, we generate cyitk.ImageF2, the corresponding glue class. However, we could add a list of several image types here (limited to scalar images for now, but support for vector, tensor and multi-channel images is in the works).
Note that the third argument is the suffix appended to cyitk.Image to generate the class name that will be made available in the Python module (i.e. cyitk.ImageF2, cyitk.ImageD3, etc). The suffix is free-form, just choose a sensible one.
In addition to the cyitk.ImageF2 class, this line will also generate a cyitk.ReadImageF2 function for I/O, which will rely on ITK I/O mechanisms (you get this one for free).

That’s it. With very little effort (one comment and a CMakeLists.txt file – which is basically going to be the same for any project, except for the specification of image types) we have made our code available in a Python module. At this point, just configure the project with CMake and build using make. A cyitkGaussianSmoothing module will be generated in the build directory. Copy the directory at a convenient location (or make PYTHONPATH point to it), fire up Python and just go



  #import the module
  import cyitkGaussianSmoothing as cyitk
  
  #load a float,2 image from file
  a = cyitk.ReadImageF2('input.nrrd')
  
  #instantiate an empty float,2 image
  b = cyitk.ImageF2()
  
  #run the ITK code, by specifying a sigma of 1.0
  cyitk.GaussianSmoothing(a,b,1.0)
  
  #at this point, b contains the smoothed image. Let's write it out
  b.WriteImage('output.mha')
  
  #and now impress your friends with matplotlib
   
  import pylab
  
  fig = pylab.figure(1)
  fig.subplots_adjust(bottom=0.05, left=0.05, top=0.95, right=0.95, wspace=0.1, hspace=0.1)
  
  subplot = pylab.subplot(1,2,1)
  subplot.set_title('input.nrrd')
  pylab.imshow(a.GetArray())
  pylab.gray()
  
  subplot = pylab.subplot(1,2,2)
  subplot.set_title('output.mha')
  pylab.imshow(b.GetArray())
  pylab.gray()
  
  print a.GetArray()
  print b.GetArray()
  
  fig.savefig('figure.png')
  pylab.show()

That’s it for now, enjoy cyitk!

About

A simple ITK-to-Python bridge written in Cython

License:BSD 3-Clause "New" or "Revised" License


Languages

Language:C 59.3%Language:Python 40.7%