[ITK] templating typdef question

Dr Bernhard Schaffer bschaffer at superstem.org
Mon Nov 3 12:41:31 EST 2014


Hi Matt,

Sorry for being so persistent, but I really want to understand this, and then do it in the optimum way.

>From your advice, I’ve restructured my code (and it works) as follows:

 

The actual ITK method is templated and does not know anything about “my” image object. 

Instead it just takes the data pointers to source & destination and an array which stores the dimension-sizes. The code now reads:

 

MyIMG MyITKWrapper::CurvatureFlowImageFilter( MyIMG srcImage, long iterations, double timeStep )

{

       // Do stuff to get my pointers and array info

       octet *src = (octet *)  srcImage.GetDataPointer(); 

       octet *dst = (octet *)  dstImage.GetDataPointer(); 

       long srcDataType = srcImage.GetDataType();

 

       ulong dims[5] = { 1, 1, 1, 1, 1 }; 

       for ( long d=0; d<nDims; d++ )

              dims[d] = srcImage.GetSizeAlongDimension(d);

 

       // Switch into templated code to branch depending on type & dimensionality

       switch(nDims)

       {

       case(2):

              switch(srcDataType)

              {

              case(FLOAT4DATA):  { CurvatureFlowImageFilter <2> ( iterations, timeStep, (float *) src ,  (float *) dst,  dims );} break;

              case(FLOAT8DATA):  { CurvatureFlowImageFilter <2> ( iterations, timeStep, (double *) src,  (double *) dst,  dims );} break;

              default: ThrowString("Data type not supported.");

              }

              break;

       case(3):

              switch(srcDataType)

              {

              case(FLOAT4DATA):  { CurvatureFlowImageFilter <3> ( iterations, timeStep, (float *) src ,  (float *) dst,  dims );} break;

              case(FLOAT8DATA):  { CurvatureFlowImageFilter <3> ( iterations, timeStep, (double *) src,  (double *) dst,  dims );} break;

              default: ThrowString("Data type not supported.");

              }

              break; 

default: ThrowString("Dimensionality  not supported.");

       }

 

       return resultImage;

}

 

 

template< unsigned int VDimension, typename tSrc, typename tDest > 

void MyITKWrapper::CurvatureFlowImageFilter( long iterations, double timeStep, typename tSrc *src, typename tDest *dst, ulong *dimSizes )

{

          // Wrap data for ITK

          typedef itk::ImportImageFilter<tSrc,VDimension>  ImportFilterType;

          ImportFilterType::Pointer importFilter = ImportFilterType::New();

 

          ImportFilterType::SizeType  size;

          ImportFilterType::IndexType start;

          itk::SpacePrecisionType origin[VDimension];

          itk::SpacePrecisionType spacing[VDimension];

          long nPixels=1;

          for ( int dim = 0; dim<VDimension; dim++ )

          {

                   size[dim] = dimSizes[dim]; start[dim] = 0; origin[dim] = 0.0;      spacing[dim] = 1.0;

                   nPixels *= size[dim];

          }

          ImportFilterType::RegionType region;

          region.SetIndex( start );

          region.SetSize(  size  );

          importFilter->SetRegion( region );

          importFilter->SetOrigin( origin );

          importFilter->SetSpacing( spacing );

          importFilter->SetImportPointer( src, nPixels, false );

 

          // Perform ITK action

          typedef itk::Image<tSrc,VDimension>  InputImageType;

          typedef itk::Image<tDest,VDimension> OutputImageType;

          typedef itk::CurvatureFlowImageFilter< InputImageType, OutputImageType >  FilterType;

          FilterType::Pointer filter = FilterType::New();

          filter->SetInput( importFilter->GetOutput() );

          filter->SetTimeStep( timeStep );

          filter->SetNumberOfIterations( iterations );

          filter->Update();

 

          //Write back the data

          typedef itk::ImageRegionIterator< OutputImageType >       IteratorType;

          OutputImageType::Pointer filtered = filter->GetOutput();

          IteratorType iterator( filtered, filtered->GetRequestedRegion() );

          for ( iterator.GoToBegin(); !iterator.IsAtEnd(); ++iterator )

          {

                   *dst = (tDest) iterator.Get();

                   dst++;

          }

}

 

Now, as said this works, but if you look into the CurvatureFlowImageFilter method, only the 8 lines in the “Perform ITK action “ section are actually specific to this filter.  As I want to wrap around a lot (ideally all) itk functionality: Is there really no better way to abstract the ‘wrapping’ ? 

 

Do I really have to copy&paste the “Wrap data for ITK” and “Write back the data” sections into each and every filter I want to wrap around?

 

Thanks,

  Bernhard

 

 

-----Original Message-----
From: Matt McCormick [mailto:matt.mccormick at kitware.com] 
Sent: 03 November 2014 16:51
To: Dr Bernhard Schaffer
Cc: community at itk.org
Subject: Re: [ITK] templating typdef question

 

Hi Bernhard,

 

> 

> The (dimension) template class wrapping around my own image object 

> MyIMG and one of the functions I want to use the wrapper in:

> 

> ( Methods are static methods of my class. My own stuff is marked in 

> orange below. (Do emails in this list preserve formatting?) )

 

Yes, looks very readable -- thank you.

 

> 

> 

> 

> void MyITKWrapper::SomeCoolITKMethod( MyIMG img )

> 

> {

> 

>        switch ( img.GetDimensionality() )

> 

>        {

> 

>               case( 2 ):    MyITKWrapper::WrapScalarImage < 2 >( img );

> break;

> 

>               case( 3 ):    MyITKWrapper::WrapScalarImage < 3 >( img );

> break;

> 

>        }

> 

> }

> 

> 

> 

> template< unsigned int VDimension >

> 

> void MyITKWrapper::WrapScalarImage( MyIMG img )

> 

> {

> 

>        typedef itk::ImportImageFilter<float,VDimension> 

> ImportFilterType;

> 

>        ImportFilterType::Pointer importFilter = 

> ImportFilterType::New();

> 

> 

> 

>        ImportFilterType::SizeType  size;

> 

>        ImportFilterType::IndexType start;

> 

>        itk::SpacePrecisionType origin[VDimension];

> 

>        itk::SpacePrecisionType spacing[VDimension];

> 

>        long nPixels=1;

> 

>        for ( int dim = 0; dim<VDimension; dim++ )

> 

>        {

> 

>               size[dim] = img.GetSizeAlongDimension(dim);

> 

>               nPixels *= size[dim];

> 

>               start[dim] = 0;

> 

>               origin[dim] = 0.0;

> 

>               spacing[dim] = 1.0;

> 

>        }

> 

> 

> 

>        ImportFilterType::RegionType region;

> 

>        region.SetIndex( start );

> 

>        region.SetSize(  size  );

> 

>        importFilter->SetRegion( region );

> 

>        importFilter->SetOrigin( origin );

> 

>        importFilter->SetSpacing( spacing );

> 

> 

> 

>        float *localBuffer = (float *) img.GetArrayPointer();

> 

>        const bool importImageFilterWillOwnTheBuffer = false;

> 

>        importFilter->SetImportPointer( localBuffer, nPixels, 

> importImageFilterWillOwnTheBuffer );

> 

>        return;

> 

> }

> 

 

Very nice!

 

 

 

> This compiles and is fine. The problem, of course, is, that I now want 

> to use the “importFilter” in my “SomeCoolITKMethod” method, so that I 

> can go on

> like:

> 

> 

> 

> 

> 

> void MyITKWrapper::SomeCoolITKMethod( MyIMG img )

> 

> {

> 

>        switch ( img.GetDimensionality() )

> 

>        {

> 

>               case( 2 ):    importFilter = MyITKWrapper::WrapDMScalarImage <

> 2 >( img );  break;

> 

>               case( 3 ):    importFilter = MyITKWrapper::WrapDMScalarImage <

> 3 >( img );  break;

> 

>        }

> 

> 

> 

>        otherCoolITKFilter->SetInput( importFilter->GetOutput() );

> 

>        […]

> 

> a lot more stuff

> 

> […]

> 

> }

> 

> 

> 

> …but I don’t know how I can “define” importFilter generically in this 

> method, and I also can’t make

> 

> 

> 

> itk::ImportImageFilter<float,VDimension>

> 

> 

> 

> the return-type of my templated wrapper method.

> 

> Do I have to make “SomeCoolITKMethod” a template function itself and 

> have the switch-case in the method calling SomeCoolITKMethod ? Or is 

> there a better way?

> 

 

It generally works best to put all templated code inside the template instead of moving in and out of templates.  However, if this is neally not desired, itk::ImageBase< VImageDimension >::Pointer or itk::DataObject::Pointer can be returned, which are base classes that do not have the template parameters.  They would then have to be downcast when you need to operate on the specific type.

 

HTH,

Matt

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/community/attachments/20141103/cc50834a/attachment-0001.html>


More information about the Community mailing list