Skip to content

Commit

Permalink
ENH: Adding B-spline SyN registration method.
Browse files Browse the repository at this point in the history
Change-Id: Ie9a097c0e52e78dbe0accc3538fc19c2a56b9af1
  • Loading branch information
ntustison committed Mar 15, 2012
1 parent ec741c4 commit 8132425
Show file tree
Hide file tree
Showing 13 changed files with 1,449 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include "itkDisplacementFieldTransform.h"

#include "itkBSplineScatteredDataPointSetToImageFilter.h"
#include "itkDisplacementFieldToBSplineImageFilter.h"
#include "itkPointSet.h"

namespace itk
Expand Down Expand Up @@ -82,14 +82,14 @@ class ITK_EXPORT BSplineSmoothingOnUpdateDisplacementFieldTransform :
* typedefs for projecting the input displacement field onto a
* B-spline field.
*/
typedef typename DisplacementFieldType::PixelType DisplacementVectorType;
typedef PointSet<DisplacementVectorType, Dimension> PointSetType;
typedef unsigned int SplineOrderType;
typedef BSplineScatteredDataPointSetToImageFilter<PointSetType, DisplacementFieldType> BSplineFilterType;
typedef typename BSplineFilterType::WeightsContainerType WeightsContainerType;
typedef typename BSplineFilterType::PointDataImageType DisplacementFieldControlPointLatticeType;
typedef typename BSplineFilterType::ArrayType ArrayType;
typedef typename ArrayType::ValueType ArrayValueType;
typedef typename DisplacementFieldType::PixelType DisplacementVectorType;
typedef PointSet<DisplacementVectorType, Dimension> PointSetType;
typedef unsigned int SplineOrderType;
typedef DisplacementFieldToBSplineImageFilter<DisplacementFieldType, DisplacementFieldType> BSplineFilterType;
typedef typename BSplineFilterType::WeightsContainerType WeightsContainerType;
typedef DisplacementFieldType DisplacementFieldControlPointLatticeType;
typedef typename BSplineFilterType::ArrayType ArrayType;
typedef typename ArrayType::ValueType ArrayValueType;

/**
* Update the transform's parameters by the values in \c update. We
Expand Down Expand Up @@ -165,6 +165,13 @@ class ITK_EXPORT BSplineSmoothingOnUpdateDisplacementFieldTransform :
*/
void SetMeshSizeForTheTotalField( const ArrayType & );

/**
* Enforce stationary boundaries. Important for diffeomorphic transforms.
*/
itkBooleanMacro( EnforceStationaryBoundary );
itkSetMacro( EnforceStationaryBoundary, bool );
itkGetConstMacro( EnforceStationaryBoundary, bool );

protected:
BSplineSmoothingOnUpdateDisplacementFieldTransform();
virtual ~BSplineSmoothingOnUpdateDisplacementFieldTransform();
Expand All @@ -184,6 +191,7 @@ class ITK_EXPORT BSplineSmoothingOnUpdateDisplacementFieldTransform :
void operator=( const Self& ); //purposely not implemented

SplineOrderType m_SplineOrder;
bool m_EnforceStationaryBoundary;
ArrayType m_NumberOfControlPointsForTheUpdateField;
ArrayType m_NumberOfControlPointsForTheTotalField;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ namespace itk
*/
template<class TScalar, unsigned int NDimensions>
BSplineSmoothingOnUpdateDisplacementFieldTransform<TScalar, NDimensions>
::BSplineSmoothingOnUpdateDisplacementFieldTransform()
::BSplineSmoothingOnUpdateDisplacementFieldTransform() :
m_SplineOrder( 3 ),
m_EnforceStationaryBoundary( true )
{
this->m_SplineOrder = 3;
this->m_NumberOfControlPointsForTheUpdateField.Fill( 4 );
this->m_NumberOfControlPointsForTheTotalField.Fill( 0 );
}
Expand Down Expand Up @@ -184,73 +185,16 @@ typename BSplineSmoothingOnUpdateDisplacementFieldTransform<TScalar, NDimensions
BSplineSmoothingOnUpdateDisplacementFieldTransform<TScalar, NDimensions>
::BSplineSmoothDisplacementField( const DisplacementFieldType * field, const ArrayType &numberOfControlPoints )
{
const typename DisplacementFieldType::RegionType & bufferedRegion = field->GetBufferedRegion();
const typename DisplacementFieldType::IndexType startIndex = bufferedRegion.GetIndex();
const typename DisplacementFieldType::SizeType size = bufferedRegion.GetSize();

typename PointSetType::Pointer fieldPoints = PointSetType::New();
fieldPoints->Initialize();

itkDebugMacro( "Extracting points from field. " )

typename WeightsContainerType::Pointer weights = WeightsContainerType::New();

IdentifierType numberOfPoints = NumericTraits< IdentifierType >::Zero;

const typename WeightsContainerType::Element boundaryWeight = 1.0e10;

ImageRegionConstIteratorWithIndex<DisplacementFieldType> It( field, field->GetBufferedRegion() );
for( It.GoToBegin(); !It.IsAtEnd(); ++It )
{
typename DisplacementFieldType::IndexType index = It.GetIndex();

DisplacementVectorType data = It.Get();
typename WeightsContainerType::Element weight = 1.0;

bool isOnBoundary = false;
for( unsigned int d = 0; d < Dimension; d++ )
{
if( index[d] == startIndex[d] || index[d] == startIndex[d] + static_cast<int>( size[d] ) - 1 )
{
isOnBoundary = true;
break;
}
}
if( isOnBoundary )
{
data.Fill( 0.0 );
weight = boundaryWeight;
}

typename PointSetType::PointType point;
field->TransformIndexToPhysicalPoint( index, point );

fieldPoints->SetPointData( numberOfPoints, data );
fieldPoints->SetPoint( numberOfPoints, point );
weights->InsertElement( numberOfPoints, weight );
numberOfPoints++;
}

itkDebugMacro( "Calculating the B-spline field." );

ArrayType close;
close.Fill( false );
typename BSplineFilterType::Pointer bspliner = BSplineFilterType::New();
bspliner->SetOrigin( field->GetOrigin() );
bspliner->SetSpacing( field->GetSpacing() );
bspliner->SetSize( size );
bspliner->SetDirection( field->GetDirection() );
bspliner->SetNumberOfLevels( 1 );
bspliner->SetSplineOrder( this->m_SplineOrder );
bspliner->SetDisplacementField( field );
bspliner->SetNumberOfControlPoints( numberOfControlPoints );
bspliner->SetCloseDimension( close );
bspliner->SetInput( fieldPoints );
bspliner->SetPointWeights( weights );
bspliner->SetGenerateOutputImage( true );
bspliner->SetSplineOrder( this->m_SplineOrder );
bspliner->SetNumberOfFittingLevels( 1 );
bspliner->SetEnforceStationaryBoundary( this->m_EnforceStationaryBoundary );
bspliner->SetEstimateInverse( false );
bspliner->Update();

DisplacementFieldPointer smoothField = bspliner->GetOutput();
smoothField->Update();
smoothField->DisconnectPipeline();

return smoothField;
}
Expand Down Expand Up @@ -294,6 +238,15 @@ PrintSelf( std::ostream& os, Indent indent ) const
{
Superclass::PrintSelf( os,indent );

os << indent << "Enforce stationary boundary: ";
if( this->m_EnforceStationaryBoundary )
{
os << "true" << std::endl;
}
else
{
os << "false" << std::endl;
}
os << indent << "B-spline parameters: " << std::endl;
os << indent << " spline order = " << this->m_SplineOrder << std::endl;
os << indent << " number of control points for the update field = "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*=========================================================================
*
* Copyright Insight Software Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/
#ifndef __itkDisplacementFieldToBSplineImageFilter_h
#define __itkDisplacementFieldToBSplineImageFilter_h

#include "itkImageToImageFilter.h"

#include "itkBSplineScatteredDataPointSetToImageFilter.h"
#include "itkPointSet.h"
#include "itkVector.h"

namespace itk
{

/**
* \class DisplacementFieldToBSplineImageFilter
* \brief Class which takes a displacement field image and smooths it
* using B-splines. The inverse can also be estimated.
*
* \author Nick Tustison
*
* \ingroup ITKDisplacementField
*/

template <class TInputImage, class TOutputImage = TInputImage>
class DisplacementFieldToBSplineImageFilter
: public ImageToImageFilter<TInputImage, TOutputImage>
{
public:
typedef DisplacementFieldToBSplineImageFilter Self;
typedef ImageToImageFilter<TInputImage, TOutputImage> Superclass;
typedef SmartPointer<Self> Pointer;
typedef SmartPointer<const Self> ConstPointer;

/** Method for creation through the object factory. */
itkNewMacro( Self );

/** Extract dimension from input image. */
itkStaticConstMacro( ImageDimension, unsigned int, TInputImage::ImageDimension );

typedef TInputImage InputFieldType;
typedef TOutputImage OutputFieldType;

typedef InputFieldType DisplacementFieldType;
typedef OutputFieldType InverseDisplacementFieldType;

/** Image typedef support. */
typedef typename OutputFieldType::PixelType PixelType;
typedef typename OutputFieldType::PixelType VectorType;
typedef typename OutputFieldType::RegionType RegionType;
typedef typename OutputFieldType::IndexType IndexType;

typedef typename OutputFieldType::PointType PointType;
typedef typename OutputFieldType::SpacingType SpacingType;
typedef typename OutputFieldType::PointType OriginType;
typedef typename OutputFieldType::SizeType SizeType;
typedef typename OutputFieldType::DirectionType DirectionType;

/** B-spline smoothing filter argument typedefs */
typedef PointSet<VectorType, ImageDimension> PointSetType;

/** B-sline filter typedefs */
typedef BSplineScatteredDataPointSetToImageFilter<
PointSetType, OutputFieldType> BSplineFilterType;
typedef typename BSplineFilterType::WeightsContainerType WeightsContainerType;
typedef typename BSplineFilterType::PointDataImageType DisplacementFieldControlPointLatticeType;
typedef typename BSplineFilterType::ArrayType ArrayType;

/** Set the displacement field */
void SetDisplacementField( const InputFieldType * field )
{
this->SetInput( field );
}

/**
* Get the deformation field.
*/
const InputFieldType* GetDisplacementField() const
{
return this->GetInput( 0 );
}

/**
* Get the displacement field control point lattice.
*/
const DisplacementFieldControlPointLatticeType * GetDisplacementFieldControlPointLattice() const
{
return this->m_DisplacementFieldControlPointLattice;
}

/**
* Set the spline order defining the bias field estimate. Default = 3.
*/
itkSetMacro( SplineOrder, unsigned int );

/**
* Get the spline order defining the bias field estimate. Default = 3.
*/
itkGetConstMacro( SplineOrder, unsigned int );

/**
* Set the control point grid size definining the B-spline estimate of the
* scalar bias field. In each dimension, the B-spline mesh size is equal
* to the number of control points in that dimension minus the spline order.
* Default = 4 control points in each dimension for a mesh size of 1 in each
* dimension.
*/
itkSetMacro( NumberOfControlPoints, ArrayType );

/**
* Get the control point grid size definining the B-spline estimate of the
* scalar bias field. In each dimension, the B-spline mesh size is equal
* to the number of control points in that dimension minus the spline order.
* Default = 4 control points in each dimension for a mesh size of 1 in each
* dimension.
*/
itkGetConstMacro( NumberOfControlPoints, ArrayType );

/**
* Set the number of fitting levels. One of the contributions of N4 is the
* introduction of a multi-scale approach to fitting. This allows one to
* specify a B-spline mesh size for initial fitting followed by a doubling of
* the mesh resolution for each subsequent fitting level. Default = 1 level.
*/
itkSetMacro( NumberOfFittingLevels, ArrayType );

/**
* Set the number of fitting levels. One of the contributions of N4 is the
* introduction of a multi-scale approach to fitting. This allows one to
* specify a B-spline mesh size for initial fitting followed by a doubling of
* the mesh resolution for each subsequent fitting level. Default = 1 level.
*/
void SetNumberOfFittingLevels( unsigned int n )
{
ArrayType nlevels;

nlevels.Fill( n );
this->SetNumberOfFittingLevels( nlevels );
}

/**
* Get the number of fitting levels. One of the contributions of N4 is the
* introduction of a multi-scale approach to fitting. This allows one to
* specify a B-spline mesh size for initial fitting followed by a doubling of
* the mesh resolution for each subsequent fitting level. Default = 1 level.
*/
itkGetConstMacro( NumberOfFittingLevels, ArrayType );

/**
* Estimate the inverse field instead of the forward field. Default = false.
*/
itkBooleanMacro( EstimateInverse );
itkSetMacro( EstimateInverse, bool );
itkGetConstMacro( EstimateInverse, bool );

/**
* Enforce stationary boundary conditions. Default = false.
*/
itkBooleanMacro( EnforceStationaryBoundary );
itkSetMacro( EnforceStationaryBoundary, bool );
itkGetConstMacro( EnforceStationaryBoundary, bool );

protected:

/** Constructor */
DisplacementFieldToBSplineImageFilter();

/** Deconstructor */
virtual ~DisplacementFieldToBSplineImageFilter();

/** Standard print self function **/
void PrintSelf( std::ostream& os, Indent indent ) const;

/** preprocessing function */
void GenerateData();

private:
DisplacementFieldToBSplineImageFilter( const Self& ); //purposely not implemented
void operator=( const Self& ); //purposely not implemented

bool m_EstimateInverse;
bool m_EnforceStationaryBoundary;
unsigned int m_SplineOrder;
ArrayType m_NumberOfControlPoints;
ArrayType m_NumberOfFittingLevels;

typename DisplacementFieldControlPointLatticeType::Pointer m_DisplacementFieldControlPointLattice;


};

} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#include "itkDisplacementFieldToBSplineImageFilter.hxx"
#endif

#endif
Loading

0 comments on commit 8132425

Please sign in to comment.