[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