[ITK] templating typdef question
Matt McCormick
matt.mccormick at kitware.com
Wed Oct 29 17:28:19 EDT 2014
Hi Bernhard,
Welcome to ITK!
The basic strategy is to put all the templated code in a template
function or class. This prevents duplicated code (the root of almost
all evil). Then, use a switch statement and call the appropriate
templates. An example is here [1], which is long because it switches
over both a number of pixel types and dimensions, but it demonstrates
the idea.
Inside the templated code, use for loops instead explicit assignment
to set each dimension value. Also, use code like
Image::SpacingType spacing;
spacing.Fill( 1.0 );
instead of
itk::SpacePrecisionType spacing[2];
spacing[0] = 1.0;
spacing[1] = 1.0;
Hope this helps,
Matt
[1] http://itk.org/ITKExamples/src/IO/ImageBase/ReadUnknownImageType/Documentation.html
On Wed, Oct 29, 2014 at 5:03 PM, Dr Bernhard Schaffer
<bschaffer at superstem.org> wrote:
> Hi,
>
> This is my second email to this list. I’m still not so familiar with
> typedefs in coding, and I’ve the current problem:
>
>
>
> I have my own “image” objects which can be 2D or 3D and of different number
> type. If I assume they are only 2D and float I can do something like this:
>
> (The cyan lines show methods of ‘my’ object.)
>
>
>
>
>
> const unsigned int DIMENSION = 2;
>
>
>
> typedef itk::ImportImageFilter<float, DIMENSION >
> ImportFilterType;
>
> ImportFilterType::Pointer importFilter = ImportFilterType::New();
>
>
>
> ImportFilterType::SizeType size;
>
> size[0] = MYIMAGE.GetXSIZE();
>
> size[1] = MYIMAGE.GetYSIZE();
>
>
>
> ImportFilterType::IndexType start;
>
> start.Fill( 0 );
>
>
>
> ImportFilterType::RegionType region;
>
> region.SetIndex( start );
>
> region.SetSize( size );
>
> importFilter->SetRegion( region );
>
>
>
> const itk::SpacePrecisionType origin[ DIMENSION ] = { 0.0, 0.0 };
>
> importFilter->SetOrigin( origin );
>
>
>
> const itk::SpacePrecisionType spacing[ DIMENSION ] = { 1.0, 1.0
> };
>
> importFilter->SetSpacing( spacing );
>
>
>
> const bool importImageFilterWillOwnTheBuffer = false;
>
>
>
> float *localBuffer = MYIMAGE.GETPOINTER();
>
> importFilter->SetImportPointer( localBuffer, size[0]*size[1],
> importImageFilterWillOwnTheBuffer );
>
>
>
> typedef itk::Image< float,DIMENSION > InputImageType;
>
> typedef itk::Image< float,DIMENSION > OutputImageType;
>
>
>
> typedef itk::CurvatureFlowImageFilter< InputImageType,
> OutputImageType > FilterType;
>
> FilterType::Pointer filter = FilterType::New();
>
>
>
> filter->SetInput( importFilter->GetOutput() );
>
> filter->SetTimeStep( timeStep );
>
> filter->SetNumberOfIterations( iterations );
>
> filter->Update();
>
> typedef itk::ImageRegionIterator< OutputImageType >
> IteratorType;
>
> OutputImageType::Pointer filtered = filter->GetOutput();
>
> […]
>
>
>
> If my image is 3D I can do accordingly: (Yellow is the difference to above)
>
>
>
> const unsigned int DIMENSION = 3;
>
>
>
> typedef itk::ImportImageFilter<float, DIMENSION >
> ImportFilterType;
>
> ImportFilterType::Pointer importFilter = ImportFilterType::New();
>
>
>
> ImportFilterType::SizeType size;
>
> size[0] = MYIMAGE.GetXSIZE();
>
> size[1] = MYIMAGE.GetYSIZE();
>
> size[2] = MYIMAGE.GetZSIZE();
>
>
>
>
>
> ImportFilterType::IndexType start;
>
> start.Fill( 0 );
>
>
>
> ImportFilterType::RegionType region;
>
> region.SetIndex( start );
>
> region.SetSize( size );
>
> importFilter->SetRegion( region );
>
>
>
> const itk::SpacePrecisionType origin[ DIMENSION ] = { 0.0, 0.0, 0.0 };
>
> importFilter->SetOrigin( origin );
>
>
>
> const itk::SpacePrecisionType spacing[ DIMENSION ] = { 1.0, 1.0,
> 1.0 };
>
> importFilter->SetSpacing( spacing );
>
>
>
> const bool importImageFilterWillOwnTheBuffer = false;
>
> float *localBuffer = MYIMAGE.GETPOINTER();
>
> importFilter->SetImportPointer( localBuffer,
> size[0]*size[1]*size[2], importImageFilterWillOwnTheBuffer );
>
>
>
> typedef itk::Image< float,DIMENSION > InputImageType;
>
> typedef itk::Image< float,DIMENSION > OutputImageType;
>
>
>
> typedef itk::CurvatureFlowImageFilter< InputImageType,
> OutputImageType > FilterType;
>
> FilterType::Pointer filter = FilterType::New();
>
>
>
> filter->SetInput( importFilter->GetOutput() );
>
> filter->SetTimeStep( timeStep );
>
> filter->SetNumberOfIterations( iterations );
>
> filter->Update();
>
> typedef itk::ImageRegionIterator< OutputImageType >
> IteratorType;
>
> OutputImageType::Pointer filtered = filter->GetOutput();
>
> […]
>
>
>
> The problem I have is the following. I can query my object about its
> dimensionality, but I can’t do the following:
>
>
>
> const unsigned int DIMENSION = MYIMAGE.GETDIMENSIONALITY();
>
>
>
> because the typedefs are evaluated on compilation not on runtime. So my
> way around this is, to actually duplicate all the code and have both my
> examples in a switch-case:
>
>
>
> switch(MYIMAGE.GETDIMENSIONALITY())
>
> {
>
> case(2):
>
> {
>
> … EXAMPLE 2D as above
>
> }
>
> break;
>
> case(3):
>
> {
>
> … EXAMPLE 3D as above
>
> }
>
> break;
>
> }
>
>
>
> Which is rather obvious code duplication. Is there a better way to do this?
> (there has to!) The problem branches out, if I also allow the type float to
> be specified by my object as in
>
> switch(MYIMAGE.GETDATATYPE())
>
> {
>
> case(1):…float…;
>
> case(2):…double…;
>
> case(3):…
>
> …
>
> }
>
>
>
>
>
> I would very much appreciate a few lines of (pseudo-) code showing me how I
> can do this better.
>
>
>
> Thank you very much,
>
> Best regards,
>
> Bernhard
>
>
>
>
> _______________________________________________
> Community mailing list
> Community at itk.org
> http://public.kitware.com/mailman/listinfo/community
>
More information about the Community
mailing list