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

Benoit Regrain benoit.regrain at creatis.insa-lyon.fr
Mon Jun 13 08:06:40 EDT 2005


Hi,

----- Original Message ----- 
From: "Gaetan Lehmann" <gaetan.lehmann at jouy.inra.fr>
To: <insight-developers at itk.org>
Sent: Friday, June 10, 2005 7:26 PM
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 :-)
It's an interessant concept. With that, we have the list of all possible
wrapped types for one ITK process. But in python, the 2 values 'US2'
or ('US',2) or img.GetTemplateType() are different but specifie the same
resulting class.
When the call of a function (in your case, the __getitem__ function),
we can mask this problem and make internal solutions like I do in
my 'itkImage' or 'itkImage_New' function.


This proposal have a second problem :
The user must know the instanciation type.
Consider the following example :

1 def Write( img, name):
X     imgType = ???

2     writer = itk.ImageFileWriter[imgType].New()
2b   writer = itk.ImageFileWriter_New( img )

3     writer.SetInput( img )
4     writer.SetFileName( name )
5     writer.Update()

To create the writer, we must know the image type. But the image don't have
its type (with the actual wrapping). At line X, the use must be able to get
the image type from the image (line 2).
With my solution (line 2b), the image type is directly found from the img
instance (actually with an heuristic :-( )


In third remark, I will consider the itk.FucntionBase class.
ITK_WRAP_OBJECT2( FunctionBase, image::F2, double, itkFunctionBaseIF2D )
ITK_WRAP_OBJECT2( FunctionBase, point::F2, double, itkFunctionBasePF2D )

Will you have :
   FunctionBase[ (IF2,D) ].New()    => to create itkFunctionBaseIF2D
   FunctionBase[ (PF2,D) ].New()  => to create itkFunctionBasePF2D
or
   FunctionBase[ (F2,D) ].New()    => to create itkFunctionBaseIF2D
   FunctionBase[ (F2,D) ].New()    => to create itkFunctionBasePF2D
      With a problem to do the difference between the 2 types F2,D

And in the example, we do the difference between image and point by the I or
P prefix. So, why this prefer is not used to present all image or point type
in other processes (problem of consistence in the mangled names) ?


Last, your parsing have some problems with classes ending by IO.
But I don't think have a more robust parsing of the all classes.
I think that a post-importation parsing to find classes isn't a good 
solution.
It will be better to add class's methods when generating wrapping by 
CableSwig
(it's possible with swig). With these methods we will get the class name,
the added mangle suffix (in a string or a list of components).



> 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.
This can be a good addict. But some processes in ITK don't have the SetInput
method (reader processes for example). How does the function
react in this case ? Does your solution work in all cases ?



> 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  );

The images are : IF2
For the structure element, we can prefix by SE, so we have the result : SEF2
Finally, we obtain : BinaryDilateUmageFilterIF2IF2SEF2

But we may consider that the structure element can be different that
structuringElement::F2
for each 2D images process, so the resulting mangled name will be :
BinaryDilateUmageFilterIF2IF2



I will see to have a mix between our solutions. But I think the first point
to solve is to have a coherence between all mangled names.


Cheers
Benoit Regrain



More information about the Insight-developers mailing list