[Insight-developers] [ITK + Python] Wrapping classes proposal

Miller, James V (Research) millerjv at crd.ge.com
Thu Jun 16 11:48:24 EDT 2005


> and to make construction of the process pipeline easier, if a var is used as 
> parameter in New method, it is used as source of image :
> 
>   reader2 = itk.ImageFileReader[imageType].New(FileName='image2.png')
>   sub = itk.SubtractImageFilter[imageType, imageType, imageType].New(reader, reader2)
>   writer = itk.ImageFileWriter[imageType].New(sub, FileName='out.png')
>   writer.Update()

While it is nice to use python's ability to refer to parameters as name=value pairs, 
I would hesitate to have the python API diverge greatly from the C++ API. In particular, 
when you do 

sub = itk.SubtractImageFilter[imageType, imageType, imageType].New(reader, reader2)

I assume that you have changed New() to run through its parameters list, call and 
set methods based on name-value pairs and then use the remaining parameters to be
the input1 and input2.  Then you make calls in the New() to set the inputs as

	self.SetInput1( reader.GetOutput() )
      self.SetInput2( reader2.GetOutput() )

But what if I wanted to grab the 2nd output of a filter to pass in as the first 
input to the subtract filter?  I guess this is not supported by your New() method
and I would have to fall back to multiline coding. Is this "inconsistency" 
confusing to users?

Jim





-----Original Message-----
From: insight-developers-bounces+millerjv=crd.ge.com at itk.org [mailto:insight-developers-bounces+millerjv=crd.ge.com at itk.org]On Behalf Of Gaetan Lehmann
Sent: Friday, June 10, 2005 1:26 PM
To: insight-developers at itk.org
Subject: Re: [Insight-developers] [ITK + Python] Wrapping classes proposal



Hi Benoit,

I have also written a module some time ago to try to make itk python more 
pleasant to use (see 
http://www.itk.org/Bug/bug.php?op=show&bugid=1766&pos=0), and use some 
similar things.
I'm really happy to see that others than me are interested in this subject. I 
hope we will see nice solutions in future release :-)

I don't take the problem the same way : I was quite frustrated while 
prototyping with itk python. There was so much names in InsightToolkit module 
that it was really difficult to use completion in interperter (ipython). I 
decided to reorganize the module, so now it appear as a tree :
itk
 |-ImageFileReader
 | |-US2
 | | |-New
 | | |-Ptr
 | | +-Pointer
 | |-US3
 | |-F2
 | +-F3
 |-MedianImageFilter
 | |-US2US2
 | |-US3US3
 | +-...
 |-...

It highly decrease number of names in module and highly improve usability in 
ipython interperter :-)
Note that I have also drop the redundant itk prefix, and BTW, decrease line 
length of 3 pixels ;-)

Where my idea is similar to yours, is that I made type accessible at run time.
Instead of writing

  itk.ImageFileReader.US2.New()

we can write
  
  itk.ImageFileReader['US2'].New()

or

  pixelType = 'US'
  dim = 2
  imageType = (pixelType, dim)
  itk.ImageFileReader[imageType].New()

Which is quite similar to c++ coding style :-)

But there is good and less good things in c++ style, and I find quite boring 
to have to set parameters on several lines, or to have to call 
a.SetInput(b.GetOutput()) for each filter, especially in interperter.
So I have given the ability to set attribute value in New method :

  reader = itk.ImageFileReader[imageType].New(FileName='image.png')

and to make construction of the process pipeline easier, if a var is used as 
parameter in New method, it is used as source of image :

  reader2 = itk.ImageFileReader[imageType].New(FileName='image2.png')
  sub = itk.SubtractImageFilter[imageType, imageType, imageType].New(reader, 
reader2)
  writer = itk.ImageFileWriter[imageType].New(sub, FileName='out.png')
  writer.Update()

All of this make code short, readable and flexible.

I agree that type names are not really consistent, but I'm not sure your 
solution is totally doable. How would you call wrapped 
BinaryDilateImageFilter :

    ITK_WRAP_OBJECT3(BinaryDilateImageFilter, image::F2 , image::F2 , 
structuringElement::F2,   itkBinaryDilateImageFilterF2F2  );

for example ?

Gaetan

On Friday 10 June 2005 17:35, Benoit Regrain wrote:
> Motivation:
> -----------
>
> I would like to use ITK from Python (hey, I'm a heavy VTKPython user and
> I would like to have the same pleasure with ITKPyton :).
> Whenever if possible I would like to keep the code written in ITKPython
> as close as possible to the corresponding ITK code written in C++
> (this was the case for VTK/Python versus VTK/C++, and it was really neat).
>
> I understand the wrapping stage requires instantiating the template classes
> and that it is impossible to wrap all possible instantiations of ITK
> templates (for obvious combinatorial explosion reasons and also because
> there can be user-defined template arguments).
>
> Still it would be nice to be able to instantiate an ITK template
> at the Python level (instead of doing the instantiation at the C++ level
> and then wrapping the code). If this feature is not provided, ITKPython
> scripts will not be able to define new types on the fly (think of an
> instantiation produced by user through GUIs or simple prototyping).
>
> Ideally, I would like to be able to write ITKPython code looking like
> the following snippet:
>
>      1 reader=itk.itkImageFileReader_New(ITK_US,2)
>      2 reader.SetFileName("Data/homersbrain.bmp")
>      3 img=reader.GetOutput()
>      4 process=itk.itkThresholdImageFilter_New(img)
>      5 process.SetInput(img)
>      6 process.SetOutsideValue(50)
>      7 process.ThresholdBelow(200)
>      8 cast=itk.itkCastImageFilter_New(img,itk.itkImage(ITK_UC,2))
>      9 cast.SetInput(process.GetOutput())
>     10 img=cast.GetOutput()
>     11 writer=itk.itkImageFileWriter_New(img)
>     12 writer.SetInput(img)
>     13 writer.SetFileName("test2.bmp")
>     14 writer.Write()
>
> In the above snippet, the important lines are line 8, i.e.
>     cast=itk.itkCastImageFilter_New(img,itk.itkImage(ITK_UC,2))
> where we can make reference to an instantiated ITKPython class named
>    itk.itkImage(ITK_UC,2)
> which needs to be implicitely instantiated somewhere !
> But we also need the functionality of line 11 i.e.
>    writer=itk.itkImageFileWriter_New(img)
> where we construct a new ITK object of required type (and the constructor
> should return an exception if the required type isn't wrapped).
>
>
> The specified parameters for the pseudo-template could be one of the 3
> following possibilities :
>  - explicit type like ITK_UC or 2
>       example (line 8) : itk.itkImage_New(ITK_UC,2)
>  - an itk python class like the result of call to itk.itkImage(ITK_UC,2)
>    that returns : itk.itkImageUC2
>       example (line 8) :
> itk.itkCastImageFilter_New(img,itk.itkImage(ITK_UC,2)) - an itk python
> instance like img
>       example (line 11) : itk.itkImageFileWriter_New(img)
>
>
> I was able to realise a small Python module that offers me the possibility
> to instanciate my ITKPython classes on the fly and to get the above snippet
> running.
> The key for this litte module to work in the following:
>    it uses Python internal mechanisms to recover all the required
>    template classes and then creates the required constructor methods.
>
> For example for the above snippet, my python module
>    1/ finds the python classes itkImageUC2, itkImageUS2, etc.
>    2/ searches the common radix class name that is itkImage
>    3/ creates 2 methods :
>       + itkImage(*args) that returns the itkImageUC2, itkImageUS2, etc.
>         class in function of args
>       + itkImage_New(*args) that returns the itkImageUC2, itkImageUS2, etc.
>         class instanciation in function of args
>
> This works fairly well but alas I couldn't get it running for all cases !
>
>
> The snag is that ITK wrapping doesn't seem to be consistent when
> choosing the mangled names for Python of the underlying ITK classes
> (the mangled name is choosed manually).
> Or at least the rules are fairly obscur and don't seem to be systematic.
> For example, in the above snippet the specified template arguments falls
> within one of the following categories :
>  - The itkImage as a PixelType specified as itkVector(type,dim) or
>    itkConvariantVector(type,dim) :
>    example : itkImage_New( itkVector(ITK_F, 2), 2)
>  - For the creation of itkFunctionBase class instance with a class (or
>    instance) in python
>    example : itkFunctionBase_New( itkImage(ITK_F, 2), ITK_D)
>
> But this strategy relies on consistent mangled class names at the Python
> level. More precisely :
>  - if we require a 2D image with vector<float,2> scalar type as template
>    parameter, we would like to write :
>        itk.itkImage( itk.itkVector( ITK_FLOAT, 2), 2)
>    and the method will search the itk.itkImageVF22 class.
>
>    ALAS ITK doesn't produce this mangled name ! Indeed, the valid ITKPython
>    class names are either itk.itkImageV2F2 or itk.itkImageVF2 !
>  - if we require a processing on 2D image with float scalar type as
> template parameter, we would like to write :
>        itk.itkThresholdFilter( itk.itkImage( ITK_FLOAT, 2) )
>    and the method will search the itk.itkThresholdFilterIF2 class.
>
>    ALAS ITK doesn't produce this mangled name ! Indeed, the valid ITKPython
>    class names are either itk.itkThresholdFilterF2 !
>  - if we require a function on 2D image with float scalar type as template
>    parameter, we would like to write :
>        itk.itkFucntionBase( itk.itkImage( ITK_FLOAT, 2), ITK_D )
>    and the method will search the itk.itkFunctionBaseIF2D class.
>
>    ITK produces this mangled name !
>    The ITK wrappers constructs the above mangled named (well actually, they
>    are manually defined in the wrap_Xxx files)! But those mangled names
>    don't seem to be globaly coherent. And we probably rely on the
>    choices of the author of each wrap_Xxx file to attain global
>    coherence (well maybe I am wrong on this one).
>
> This raises the two following questions:
>
>
> First question: why is the ITK name mangling apparently inconsitent ?
> ---------------------------------------------------------------------------
>
> I went looking at the wrapping of ITK classes. I don't fully
> understand the logic used to create the wrapping. The mangled class's
> name doesn't seem to be coherent/consistent for all the wrapped classes.
> In the Wrapping/itkCSwigImages.h file, we can find the following code :
>        1  typedef itk::Image< itkvector::F2, 2 > VF2;
>        2  typedef itk::Image< itkvector::F3, 3 > VF3;
>        3  typedef itk::Image< itkvector::F2, 2 > VD2;
>        4  typedef itk::Image< itkvector::F3, 3 > VD3;
>        5  typedef itk::Image< itkvector::F2, 2 > V2F2;
>        6  typedef itk::Image< itkvector::F2, 3 > V2F3;
>        7  typedef itk::Image< covariantvector::F2, 2 > CVF2;
>        8  typedef itk::Image< covariantvector::F3, 3 > CVF3;
>        9  typedef itk::Image< covariantvector::D2, 2 > CVD2;
>       10  typedef itk::Image< covariantvector::D3, 3 > CVD3;
>
>   + The lines 1, 3 & 5 represent the same type of datas but the typedef
>     names are different !?
>   + The lines 3 & 4 indicate the definition for floating images but the
>     typedef name indicates a double !?
>   + An image having float as scalar type and dimension 2 has the F2
>     mangled type. But, an image having Vector<float,2> as scalar type and
>     dimension 2 has either VF2 or V2F2 as mangled type !?
>     Wouldn't it be better to use VF22 to avoid confusion ? VF22 would
>     more clearly indicate : Image< V< F,2 >, 2>
>   + A process like ImageThresholdFilter that only has one input might be
>     mangled as:
>         ImageThreshold< Image<F,2> >    ==> ImageThresholdIF2
>     The I letter indicates that we have an image (like in few wrapped
> classes or when having ImageVF2... the V letter indicating Vector)
>
> Could any one clarify the ITK mangling strategy for me ?
>
>
> Second question: CableSwig versus Swig ?
> ----------------------------------------
>
> I would like to know what is today the advantage of CableSwig ?
> (as opposed to Swig)
>
> I understand the historic choice, when Swig didn't handle template classes.
> But Swig evolved and is now able to handle template classes (and
> nested classes, though their appear to still be some kind of limitations on
> heavily nester classes, as I understand it).
> What is now the CableSwig additional value compared to Swig ? Does
> CableSwig add any special wrapping features for ITK ? [e.g. by adding or
> removing some specific methods or any other ITK specific reason]  ?
>
>
> Other informations for ITK :
> ----------------------------------------
>
> If the ITK-Kitware folks are interested to work on this subject, I would
> be deligthed to try to provide some help and feedback... since I need
> this feature bad [ I'm a VTKPython drug addict: please help to switch
> ...to ITKPython ;-] .
>
>
>     Yours,
>     Benoit Regrain
_______________________________________________
Insight-developers mailing list
Insight-developers at itk.org
http://www.itk.org/mailman/listinfo/insight-developers


More information about the Insight-developers mailing list