1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkBSplineDeformableTransform_h
19 #define itkBSplineDeformableTransform_h
20 
21 #include "itkBSplineBaseTransform.h"
22 
23 namespace itk
24 {
25 /** \class BSplineDeformableTransform
26  *
27  * \brief Deformable transform using a BSpline representation
28  *
29  * \note BSplineTransform is a newer version of this class, and it is
30  * preferred.
31  *
32  * This class encapsulates a deformable transform of points from one
33  * N-dimensional space to another N-dimensional space.
34  * The deformation field is modelled using B-splines.
35  * A deformation is defined on a sparse regular grid of control points
36  * \f$ \vec{\lambda}_j \f$ and is varied by defining a deformation
37  * \f$ \vec{g}(\vec{\lambda}_j) \f$ of each control point.
38  * The deformation \f$ D(\vec{x}) \f$ at any point \f$ \vec{x} \f$
39  * is obtained by using a B-spline interpolation kernel.
40  *
41  * The deformation field grid is defined by a user specified GridRegion,
42  * GridSpacing and GridOrigin. Each grid/control point has associated with it
43  * N deformation coefficients \f$ \vec{\delta}_j \f$, representing the N
44  * directional components of the deformation. Deformation outside the grid
45  * plus support region for the BSpline interpolation is assumed to be zero.
46  *
47  * Additionally, the user can specified an addition bulk transform \f$ B \f$
48  * such that the transformed point is given by:
49  * \f[ \vec{y} = B(\vec{x}) + D(\vec{x}) \f]
50  *
51  * The parameters for this transform is an N x N-D grid of spline coefficients.
52  * The user specifies the parameters as one flat array: each N-D grid
53  * is represented by an array in the same way an N-D image is represented
54  * in the buffer; the N arrays are then concatentated together on form
55  * a single array.
56  *
57  * For efficiency, this transform does not make a copy of the parameters.
58  * It only keeps a pointer to the input parameters and assumes that the memory
59  * is managed by the caller.
60  *
61  * The following illustrates the typical usage of this class:
62  * \verbatim
63  * using TransformType = BSplineDeformableTransform<double,2,3>;
64  * TransformType::Pointer transform = TransformType::New();
65  *
66  * transform->SetGridRegion( region );
67  * transform->SetGridSpacing( spacing );
68  * transform->SetGridOrigin( origin );
69  *
70  * // NB: the region must be set first before setting the parameters
71  *
72  * TransformType::ParametersType parameters(
73  *                                       transform->GetNumberOfParameters() );
74  *
75  * // Fill the parameters with values
76  *
77  * transform->SetParameters( parameters )
78  *
79  * outputPoint = transform->TransformPoint( inputPoint );
80  *
81  * \endverbatim
82  *
83  * An alternative way to set the B-spline coefficients is via array of
84  * images. The grid region, spacing and origin information is taken
85  * directly from the first image. It is assumed that the subsequent images
86  * are the same buffered region. The following illustrates the API:
87  * \verbatim
88  *
89  * TransformType::ImageConstPointer images[2];
90  *
91  * // Fill the images up with values
92  *
93  * transform->SetCoefficientImages( images );
94  * outputPoint = transform->TransformPoint( inputPoint );
95  *
96  * \endverbatim
97  *
98  * Warning: use either the SetParameters() or SetCoefficientImages()
99  * API. Mixing the two modes may results in unexpected results.
100  *
101  * The class is templated coordinate representation type (float or double),
102  * the space dimension and the spline order.
103  *
104  * \ingroup ITKTransform
105  *
106  * \sa BSplineTransform
107  *
108  * \wiki
109  * \wikiexample{Registration/ImageRegistrationMethodBSpline,A global registration of two images}
110  * \endwiki
111  */
112 template<typename TParametersValueType=double,
113           unsigned int NDimensions = 3,
114           unsigned int VSplineOrder = 3>
115 class ITK_TEMPLATE_EXPORT BSplineDeformableTransform :
116   public BSplineBaseTransform<TParametersValueType,NDimensions,VSplineOrder>
117 {
118 public:
119   ITK_DISALLOW_COPY_AND_ASSIGN(BSplineDeformableTransform);
120 
121   /** Standard class type aliases. */
122   using Self = BSplineDeformableTransform;
123   using Superclass = BSplineBaseTransform<TParametersValueType,NDimensions,VSplineOrder>;
124   using Pointer = SmartPointer<Self>;
125   using ConstPointer = SmartPointer<const Self>;
126 
127   /** New macro for creation of through the object factory. */
128   // Explicit New() method, used here because we need to split the itkNewMacro()
129   // in order to overload the CreateAnother() method so that we can copy the m_BulkTransform
130   // explicitly.
131   // TODO: shouldn't it be done with the Clone() method?
132   itkSimpleNewMacro(Self);
CreateAnother()133   ::itk::LightObject::Pointer CreateAnother() const override
134     {
135     ::itk::LightObject::Pointer smartPtr;
136     Pointer copyPtr = Self::New().GetPointer();
137     //THE FOLLOWING LINE IS DIFFERENT FROM THE DEFAULT MACRO!
138     copyPtr->m_BulkTransform =  this->GetBulkTransform();
139     smartPtr = static_cast<Pointer>( copyPtr );
140     return smartPtr;
141     }
142 
143   /** implement type-specific clone method*/
144   itkCloneMacro(Self);
145 
146   /** Run-time type information (and related methods). */
147   itkTypeMacro( BSplineDeformableTransform, BSplineBaseTransform );
148 
149   /** Dimension of the domain space. */
150   static constexpr unsigned int SpaceDimension = NDimensions;
151 
152   /** The BSpline order. */
153   static constexpr unsigned int SplineOrder = VSplineOrder;
154 
155   /** Standard scalar type for this class. */
156   using ScalarType = TParametersValueType;
157 
158   /** Standard parameters container. */
159   using ParametersType = typename Superclass::ParametersType;
160   using ParametersValueType = typename Superclass::ParametersValueType;
161   using FixedParametersType = typename Superclass::FixedParametersType;
162   using FixedParametersValueType = typename Superclass::FixedParametersValueType;
163 
164   /** Standard Jacobian container. */
165   using JacobianType = typename Superclass::JacobianType;
166   using JacobianPositionType = typename Superclass::JacobianPositionType;
167   using InverseJacobianPositionType = typename Superclass::InverseJacobianPositionType;
168 
169   /** The number of parameters defininig this transform. */
170   using NumberOfParametersType = typename Superclass::NumberOfParametersType;
171 
172   /** Standard vector type for this class. */
173   using InputVectorType = typename Superclass::InputVectorType;
174   using OutputVectorType = typename Superclass::OutputVectorType;
175 
176   /** Standard covariant vector type for this class. */
177   using InputCovariantVectorType = typename Superclass::InputCovariantVectorType;
178   using OutputCovariantVectorType = typename Superclass::OutputCovariantVectorType;
179 
180   /** Standard vnl_vector type for this class. */
181   using InputVnlVectorType = typename Superclass::InputVnlVectorType;
182   using OutputVnlVectorType = typename Superclass::OutputVnlVectorType;
183 
184   /** Standard coordinate point type for this class. */
185   using InputPointType = Point <TParametersValueType, Self::SpaceDimension >;
186   using OutputPointType = Point <TParametersValueType, Self::SpaceDimension >;
187 
188 
189   /** This method sets the fixed parameters of the transform.
190    * For a BSpline deformation transform, the parameters are the following:
191    *    Grid Size, Grid Origin, and Grid Spacing
192    *
193    * The fixed parameters are the three times the size of the templated
194    * dimensions.
195    * This function has the effect of make the following calls:
196    *       transform->SetGridSpacing( spacing );
197    *       transform->SetGridOrigin( origin );
198    *       transform->SetGridDirection( direction );
199    *       transform->SetGridRegion( bsplineRegion );
200    *
201    * This function was added to allow the transform to work with the
202    * itkTransformReader/Writer I/O filters.
203    *
204    */
205   void SetFixedParameters( const FixedParametersType & parameters ) override;
206 
207   /** Parameters as SpaceDimension number of images. */
208   using ImageType = typename Superclass::ImageType;
209   using ImagePointer = typename Superclass::ImagePointer;
210   using CoefficientImageArray = typename Superclass::CoefficientImageArray;
211 
212   /** Set the array of coefficient images.
213    *
214    * This is an alternative API for setting the BSpline coefficients
215    * as an array of SpaceDimension images. The fixed parameters are
216    * taken from the first image. It is assumed that
217    * the buffered region of all the subsequent images are the same
218    * as the first image. Note that no error checking is done.
219    *
220    * Warning: use either the SetParameters() or SetCoefficientImages()
221    * API. Mixing the two modes may results in unexpected results.
222    */
223   void SetCoefficientImages( const CoefficientImageArray & images ) override;
224 
225   /** Typedefs for specifying the extent of the grid. */
226   using RegionType = typename Superclass::RegionType;
227 
228   using IndexType = typename Superclass::IndexType;
229   using SizeType = typename Superclass::SizeType;
230   using SpacingType = typename Superclass::SpacingType;
231   using DirectionType = typename Superclass::DirectionType;
232   using OriginType = typename Superclass::OriginType;
233 
234   /** Interpolation weights function type. */
235   using WeightsFunctionType = typename Superclass::WeightsFunctionType;
236 
237   using WeightsType = typename Superclass::WeightsType;
238   using ContinuousIndexType = typename Superclass::ContinuousIndexType;
239 
240   /** Parameter index array type. */
241   using ParameterIndexArrayType = typename Superclass::ParameterIndexArrayType;
242 
243   /**
244    * Transform points by a BSpline deformable transformation.
245    * On return, weights contains the interpolation weights used to compute the
246    * deformation and indices of the x (zeroth) dimension coefficient parameters
247    * in the support region used to compute the deformation.
248    * Parameter indices for the i-th dimension can be obtained by adding
249    * ( i * this->GetNumberOfParametersPerDimension() ) to the indices array.
250    */
251   using Superclass::TransformPoint;
252   void TransformPoint( const InputPointType & inputPoint, OutputPointType & outputPoint,
253     WeightsType & weights, ParameterIndexArrayType & indices, bool & inside ) const override;
254 
255   void ComputeJacobianWithRespectToParameters( const InputPointType &, JacobianType & ) const override;
256 
257   /** Return the number of parameters that completely define the Transfom */
258   NumberOfParametersType GetNumberOfParameters() const override;
259 
260   /** Return the number of parameters per dimension */
261   NumberOfParametersType GetNumberOfParametersPerDimension() const override;
262 
263   using PhysicalDimensionsType = typename Superclass::SpacingType;
264   using PixelType = typename Superclass::PixelType;
265 
266   using MeshSizeType = typename Superclass::MeshSizeType;
267 
268   /** Function to specify the transform domain origin. */
269   virtual void SetGridOrigin( const OriginType & );
270 
271   /** Function to retrieve the transform domain origin. */
272   itkGetConstMacro( GridOrigin, OriginType );
273 
274   /** This method specifies the grid spacing or resolution. */
275   virtual void SetGridSpacing( const SpacingType & );
276 
277   /** This method retrieve the grid spacing or resolution. */
278   itkGetConstMacro( GridSpacing, SpacingType );
279 
280   /** Function to specify the transform domain direction. */
281   virtual void SetGridDirection( const DirectionType & );
282 
283   /** Function to retrieve the transform domain direction. */
284   itkGetConstMacro( GridDirection, DirectionType );
285 
286   /** Function to specify the transform domain mesh size. */
287   virtual void SetGridRegion( const RegionType & );
288 
289   /** Function to retrieve the transform domain mesh size. */
290   itkGetConstMacro( GridRegion, RegionType );
291 
292   using BulkTransformType = Transform<TParametersValueType,
293                     Self::SpaceDimension,
294                     Self::SpaceDimension>;
295   using BulkTransformPointer = typename BulkTransformType::ConstPointer;
296   /** This method specifies the bulk transform to be applied.
297    * The default is the identity transform.
298    */
299   itkSetConstObjectMacro(BulkTransform, BulkTransformType);
300   itkGetConstObjectMacro(BulkTransform, BulkTransformType);
301 
302   /** Return the region of the grid wholly within the support region */
303   itkGetConstReferenceMacro(ValidRegion, RegionType);
304 
305 protected:
306   /** Print contents of an BSplineDeformableTransform. */
307   void PrintSelf( std::ostream & os, Indent indent ) const override;
308 
309   BSplineDeformableTransform();
310   ~BSplineDeformableTransform() override = default;
311 
312 private:
313 
314   /** Construct control point grid size from transform domain information */
315   void SetFixedParametersGridSizeFromTransformDomainInformation() const override;
316 
317   /** Construct control point grid origin from transform domain information */
318   void SetFixedParametersGridOriginFromTransformDomainInformation() const override;
319 
320   /** Construct control point grid spacing from transform domain information */
321   void SetFixedParametersGridSpacingFromTransformDomainInformation() const override;
322 
323   /** Construct control point grid direction from transform domain information */
324   void SetFixedParametersGridDirectionFromTransformDomainInformation() const override;
325 
326   /** Construct control point grid size from transform domain information */
327   void SetCoefficientImageInformationFromFixedParameters() override;
328 
329   /** Check if a continuous index is inside the valid region. */
330   bool InsideValidRegion( ContinuousIndexType & ) const override;
331 
332   /** The variables defining the coefficient grid domain for the
333    * InternalParametersBuffer are taken from the m_CoefficientImages[0]
334    * image, and must be kept in sync with them. by using
335    * references to that instance, this is more naturally enforced
336    * and does not introduce a speed penalty of dereferencing
337    * through the pointers (although it does enforce some
338    * internal class synchronization).
339    */
340   const RegionType &    m_GridRegion;
341   const OriginType &    m_GridOrigin;
342   const SpacingType &   m_GridSpacing;
343   const DirectionType & m_GridDirection;
344 
345   /** The bulk transform. */
346   BulkTransformPointer m_BulkTransform;
347 
348   RegionType m_ValidRegion;
349 
350   /** Variables defining the interpolation support region. */
351   unsigned long m_Offset;
352   bool          m_SplineOrderOdd;
353   IndexType     m_ValidRegionLast;
354   IndexType     m_ValidRegionFirst;
355 
356   void UpdateValidGridRegion();
357 
358 }; // class BSplineDeformableTransform
359 }  // namespace itk
360 
361 #ifndef ITK_MANUAL_INSTANTIATION
362 #include "itkBSplineDeformableTransform.hxx"
363 #endif
364 
365 #endif /* itkBSplineDeformableTransform_h */
366