# B-spline Registration Refactoring

Nick Tustison
2011-07-15
A couple items associated with the B-spline registration refactoring: 1. In the bug report filed by Hans Johnson, http://public.kitware.com/Bug/view.php?id=11512, it was noted that the B-spline grid initialized by the BSplineTransformDomainInitializer lays out the control points according to the image information. Thus, an image and its permuted axis or flip axis analog could end up with different control point grids. Instead, it seems much more intuitive if the control point grid were laid out based on the image location in physical space which is what the new BSplineTransformDomainInitializer does. 2. The API of the B-spline deformable transform has been fixed such that the user does not need to understand the nuances of how the B-spline grid is laid out relative to the transform domain. Instead, it is much more intuitive for the user to simply define the desired transform domain in terms of the domain origin, direction, and physical dimensions. Given this information, as well as the spline order and mesh size, the control point grid is laid out automatically inside the transform class. Note that the mesh size refers to the number of B-spline polynomial patches comprising the transform domain where the degree of polynomial is specified by the order. Since the assumption is that these are uniform B-splines, each mesh element is the same size in terms of physical size. More mesh elements means greater flexibility in the transform. 3. The previous version of the B-spline deformable transform set up the grid such that the mesh elements at the upper index of the transform were not used. So, if you wanted to do a 2-D B-spline registration using a mesh size of 10x10, only 9x9 elements would be used in the transform domain. In my opinion this is a bug which should be fixed. 4. We got rid of the bulk transform in the B-spline transform. We expect to handle global alignment via another mechanism outside a specific transform.

The ITKv3 api is available when ITKv4 configured with ITKV3_COMPATIBILITY:BOOL=ON

// // This is the old api for specifying a B-spline deformable transform // initializer. //

typedef itk::BSplineDeformableTransform< CoordinateRepType, SpaceDimension, SplineOrder > TransformType;

TransformType::Pointer bsplineTransform = TransformType::New();

typedef itk::BSplineDeformableTransformInitializer< TransformType, FixedImageType > InitializerType; InitializerType::Pointer transformInitializer = InitializerType::New();

transformInitializer->SetTransform( bsplineTransform ); transformInitializer->SetImage( fixedImage );

typedef TransformType::RegionType RegionType; RegionType::SizeType size;

const unsigned int numberOfGridNodesInsideTheImageSupport = 5;

size.Fill( numberOfGridNodesInsideTheImageSupport );

transformInitializer->SetGridSizeInsideTheImage( size );

transformInitializer->InitializeTransform();

// // This is the new api for specifying a B-spline deformable transform // initializer. //

typedef itk::BSplineTransform< CoordinateRepType, SpaceDimension, SplineOrder > TransformType;

TransformType::Pointer bsplineTransform = TransformType::New();

typedef itk::BSplineTransformInitializer< TransformType, FixedImageType > InitializerType; InitializerType::Pointer transformInitializer = InitializerType::New();

transformInitializer->SetTransform( bsplineTransform ); transformInitializer->SetImage( fixedImage );

transformInitializer->InitializeTransform();

TransformType::MeshSizeType meshSize; meshSize.Fill( 5 );

bsplineTransform->SetTransformDomainMeshSize( meshSize );

// // This is the old api for specifying a B-spline deformable transform //

typedef TransformType::RegionType RegionType; RegionType bsplineRegion; RegionType::SizeType gridSizeOnImage; RegionType::SizeType gridBorderSize; RegionType::SizeType totalGridSize;

gridSizeOnImage.Fill( numberOfGridNodesInOneDimension ); // Border for spline order = 3 ( 1 lower, 2 upper ) gridBorderSize.Fill( SplineOrder ); totalGridSize = gridSizeOnImage + gridBorderSize;

bsplineRegion.SetSize( totalGridSize );

typedef TransformType::SpacingType SpacingType; SpacingType spacing = fixedImage->GetSpacing();

typedef TransformType::OriginType OriginType; OriginType origin = fixedImage->GetOrigin(); FixedImageType::SizeType fixedImageSize = fixedRegion.GetSize(); for(unsigned int r = 0; r < ImageDimension; r++ ) { spacing[r] *= static_cast<double>(fixedImageSize[r] - 1) / static_cast<double>(gridSizeOnImage[r] - 1); } FixedImageType::DirectionType gridDirection = SpacingType gridOriginOffset = gridDirection * spacing;

OriginType gridOrigin = origin - gridOriginOffset;

transform->SetGridSpacing( spacing ); transform->SetGridOrigin( gridOrigin ); transform->SetGridRegion( bsplineRegion ); transform->SetGridDirection( fixedImage->GetDirection() );

// // This is the new api for specifying a B-spline deformable transform //

TransformType::PhysicalDimensionsType fixedPhysicalDimensions; TransformType::MeshSizeType meshSize; for( unsigned int i=0; i < ImageDimension; i++ ) { fixedPhysicalDimensions[i] = fixedImage->GetSpacing()[i] * static_cast<double>( fixedImage->GetLargestPossibleRegion().GetSize()[i] - 1 ); } meshSize.Fill( numberOfGridNodesInOneDimension - SplineOrder ); transform->SetTransformDomainOrigin( fixedImage->GetOrigin() ); transform->SetTransformDomainPhysicalDimensions( fixedPhysicalDimensions ); transform->SetTransformDomainMeshSize( meshSize ); transform->SetTransformDomainDirection( fixedImage->GetDirection() );
Ic5d7849ea2695dd7e26b8caf547dc1472b2f1265
Examples/Data/BSplineDisplacements1.txt Examples/Data/BSplineDisplacements3.txt Examples/Data/BSplineDisplacements5.txt Examples/IO/TransformReadWrite.cxx Examples/Registration/BSplineWarping1.cxx Examples/Registration/BSplineWarping2.cxx Examples/Registration/DeformableRegistration12.cxx Examples/Registration/DeformableRegistration13.cxx Examples/Registration/DeformableRegistration14.cxx Examples/Registration/DeformableRegistration15.cxx Examples/Registration/DeformableRegistration4.cxx Examples/Registration/DeformableRegistration6.cxx Examples/Registration/DeformableRegistration7.cxx Examples/Registration/DeformableRegistration8.cxx Modules/Core/Transform/include/itkBSplineTransform.h Modules/Core/Transform/include/itkBSplineTransform.txx Modules/Nonunit/Review/test/itkBSplineTransformInitializerTest1.cxx Modules/Nonunit/Review/test/itkBSplineTransformInitializerTest2.cxx Modules/Core/Transform/test/CMakeLists.txt Modules/Core/Transform/test/itkBSplineTransformTest.cxx Modules/Core/Transform/test/itkBSplineTransformTest2.cxx Modules/Core/Transform/test/itkBSplineTransformTest3.cxx Modules/Nonunit/Review/include/itkBSplineTransformInitializer.h Modules/Nonunit/Review/include/itkBSplineTransformInitializer.txx Modules/Nonunit/Review/include/itkOptImageToImageMetricsTest2.h Modules/Nonunit/Review/test/itkTransformToDisplacementFieldSourceTest.cxx Modules/Registration/Common/test/itkMattesMutualInformationImageToImageMetricTest.cxx Modules/Core/Transform/include/itkBSplineDeformableTransform.h Modules/Core/Transform/include/itkBSplineDeformableTransform.txx Modules/Nonunit/Review/test/itkBSplineDeformableTransformInitializerTest1.cxx Modules/Nonunit/Review/test/itkBSplineDeformableTransformInitializerTest2.cxx