[ITK] templating typdef question

Matt McCormick matt.mccormick at kitware.com
Mon Nov 3 13:15:25 EST 2014


Hi Bernhard,

Looks good.

The "// Perform ITK action" section could be another templated
function/class that is templated over InputImageType, OutputImageType,
and FilterType.  Template specialization can be provided for the
different filter types, e.g. CurvatureFlowImageFilter.

HTH,
Matt

On Mon, Nov 3, 2014 at 12:41 PM, Dr Bernhard Schaffer
<bschaffer at superstem.org> wrote:
> 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


More information about the Community mailing list