MultiLevelFreeFormTransformation.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2008-2015 Imperial College London
5  * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
6  * Copyright 2013-2015 Andreas Schuh
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef MIRTK_MultiLevelFreeFormTransformation_H
22 #define MIRTK_MultiLevelFreeFormTransformation_H
23 
24 #include "mirtk/MultiLevelTransformation.h"
25 
26 
27 namespace mirtk {
28 
29 
30 /**
31  * Class for multi-level FFD where global and local transformations are summed up.
32  *
33  * T_mffd(x) = T_global(x) + sum_i T_local^i(x)
34  */
36 {
37  mirtkTransformationMacro(MultiLevelFreeFormTransformation);
38 
39  // ---------------------------------------------------------------------------
40  // Construction/Destruction
41 
42 public:
43 
44  /// Default constructor
46 
47  /// Construct multi-level transformation given a rigid transformation
49 
50  /// Construct multi-level transformation given an affine transformation
52 
53  /// Copy constructor
55 
56  /// Destructor
58 
59  // ---------------------------------------------------------------------------
60  // Levels
61 
62  /// Combine local transformations on stack
63  virtual void CombineLocalTransformation();
64 
65  /// Convert the global transformation from a matrix representation to a
66  /// FFD and incorporate it with any existing local transformation
67  virtual void MergeGlobalIntoLocalDisplacement();
68 
69  // ---------------------------------------------------------------------------
70  // Bounding box
71 
72  /// Gets the spatial bounding box for a transformation parameter in image coordinates.
73  /// The last parameter specifies what fraction of the bounding box to return.
74  /// The default is 1 which equals 100% of the bounding box.
75  bool DOFBoundingBox(const Image *, int, int &, int &, int &,
76  int &, int &, int &, double = 1) const;
77 
78  // ---------------------------------------------------------------------------
79  // Approximation
80 
81  /// Approximate displacements: This function takes a set of points and a set
82  /// of displacements and finds a transformation which approximates these
83  /// displacements. After approximation, the displacements are replaced by the
84  /// residual displacement errors at the points.
85  ///
86  /// \note This function does not change the global transformation and passive levels.
87  /// Use ApproximateAsNew to also approximate a new global transformation.
88  virtual double Approximate(const ImageAttributes &, double *, double *, double *,
89  int = 1, double = .0);
90 
91  /// Approximate displacements: This function takes a set of points and a set
92  /// of displacements and finds a transformation which approximates these
93  /// displacements. After approximation, the displacements are replaced by the
94  /// residual displacement errors at the points.
95  ///
96  /// \note This function does not change the global transformation and passive levels.
97  /// Use ApproximateAsNew to also approximate a new global transformation.
98  virtual double Approximate(const double *, const double *, const double *,
99  double *, double *, double *, int,
100  int = 1, double = .0);
101 
102  /// Approximate displacements: This function takes a set of points and a set
103  /// of displacements and finds a transformation which approximates these
104  /// displacements. After approximation, the displacements are replaced by the
105  /// residual displacement errors at the points.
106  ///
107  /// \note This function does not change the global transformation and passive levels.
108  /// Use ApproximateAsNew to also approximate a new global transformation.
109  virtual double Approximate(const double *, const double *, const double *, const double *,
110  double *, double *, double *, int,
111  int = 1, double = .0);
112 
113  /// Approximate displacements: This function takes a set of points and a set
114  /// of displacements and finds a !new! transformation which approximates these
115  /// displacements. After approximation, the displacements are replaced by the
116  /// residual displacement errors at the points.
117  ///
118  /// \note This function also modifies the global transformation.
119  /// Use Reset and Approximate instead if this is not desired.
120  virtual double ApproximateAsNew(const ImageAttributes &, double *, double *, double *,
121  int = 1, double = .0);
122 
123  /// Approximate displacements: This function takes a set of points and a set
124  /// of displacements and finds a !new! transformation which approximates these
125  /// displacements. After approximation, the displacements are replaced by the
126  /// residual displacement errors at the points.
127  ///
128  /// \note This function also modifies the global transformation.
129  /// Use Reset and Approximate instead if this is not desired.
130  virtual double ApproximateAsNew(const double *, const double *, const double *,
131  double *, double *, double *, int,
132  int = 1, double = .0);
133 
134  /// Approximate displacements: This function takes a set of points and a set
135  /// of displacements and finds a !new! transformation which approximates these
136  /// displacements. After approximation, the displacements are replaced by the
137  /// residual displacement errors at the points.
138  ///
139  /// \note This function also modifies the global transformation.
140  /// Use Reset and Approximate instead if this is not desired.
141  virtual double ApproximateAsNew(const double *, const double *, const double *, const double *,
142  double *, double *, double *, int,
143  int = 1, double = .0);
144 
145  /// Approximate displacements: This function takes a set of points and a set
146  /// of displacements and finds !new! parameters such that the resulting
147  /// transformation approximates the displacements as good as possible.
148  virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
149  const double *, const double *, const double *, int);
150 
151  /// Finds gradient of approximation error: This function takes a set of points
152  /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
153  /// which minimizes the L2 norm of the approximation error and adds it to the
154  /// input gradient with the given weight.
155  virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
156  const double *, const double *, const double *, int,
157  double *, double = 1.0) const;
158 
159  // ---------------------------------------------------------------------------
160  // Point transformation
161 
162  // Do not hide base class methods
167 
168  /// Transforms a single point using the local transformation component only
169  virtual void LocalTransform(int, int, double &, double &, double &, double = 0, double = NaN) const;
170 
171  /// Transforms a single point
172  virtual void Transform(int, int, double &, double &, double &, double = 0, double = NaN) const;
173 
174  /// Calculates the displacement vectors for a whole image domain
175  ///
176  /// \attention The displacements are computed at the positions after applying the
177  /// current displacements at each voxel. These displacements are then
178  /// added to the current displacements. Therefore, set the input
179  /// displacements to zero if only interested in the displacements of
180  /// this transformation at the voxel positions.
181  virtual void Displacement(int, int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
182 
183  /// Calculates the displacement vectors for a whole image domain
184  ///
185  /// \attention The displacements are computed at the positions after applying the
186  /// current displacements at each voxel. These displacements are then
187  /// added to the current displacements. Therefore, set the input
188  /// displacements to zero if only interested in the displacements of
189  /// this transformation at the voxel positions.
190  virtual void Displacement(int, int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
191 
192  /// Whether this transformation implements a more efficient update of a given
193  /// displacement field given the desired change of a transformation parameter
194  virtual bool CanModifyDisplacement(int = -1) const;
195 
196  /// Updates the displacement vectors for a whole image domain
197  ///
198  /// \param[in] dof Transformation parameter.
199  /// \param[in] dv Change of transformation parameter value.
200  /// \param[in,out] dx Displacement field to be updated.
201  /// \param[in] t Time point of start point.
202  /// \param[in] t0 Time point of end point.
203  /// \param[in] i2w Pre-computed world coordinates.
204  virtual void DisplacementAfterDOFChange(int dof, double dv,
206  double t, double t0 = -1,
207  const WorldCoordsImage *i2w = NULL) const;
208 
209  /// Calculates the inverse displacement vectors for a whole image domain
210  ///
211  /// \attention The displacements are computed at the positions after applying the
212  /// current displacements at each voxel. These displacements are then
213  /// added to the current displacements. Therefore, set the input
214  /// displacements to zero if only interested in the displacements of
215  /// this transformation at the voxel positions.
216  ///
217  /// \returns Number of points for which transformation is non-invertible.
218  virtual int InverseDisplacement(int, int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
219 
220  /// Calculates the inverse displacement vectors for a whole image domain
221  ///
222  /// \attention The displacements are computed at the positions after applying the
223  /// current displacements at each voxel. These displacements are then
224  /// added to the current displacements. Therefore, set the input
225  /// displacements to zero if only interested in the displacements of
226  /// this transformation at the voxel positions.
227  ///
228  /// \returns Number of points for which transformation is non-invertible.
229  virtual int InverseDisplacement(int, int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
230 
231  // ---------------------------------------------------------------------------
232  // Derivatives
233 
234  // Do not hide base class methods
240 
241  /// Calculates the Jacobian of the transformation w.r.t world coordinates
242  virtual void Jacobian(int, int, Matrix &, double, double, double, double = 0, double = NaN) const;
243 
244  /// Calculates the Hessian for each component of the transformation w.r.t world coordinates
245  virtual void Hessian(int, int, Matrix [3], double, double, double, double = 0, double = NaN) const;
246 
247  /// Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w.r.t. a transformation parameter
248  virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double = 0, double = NaN) const;
249 
250  /// Applies the chain rule to convert spatial non-parametric gradient
251  /// to a gradient w.r.t the parameters of this transformation.
252  ///
253  /// If the transformation itself is non-parametric, the gradient will be passed through
254  /// unchanged. The default implementation uses the full Jacobian matrix computed for each
255  /// DoF separately (i.e., calls JacobianDOFs for each DoF).
256  ///
257  /// For 4D transformations, the temporal coordinate t used for the computation of the Jacobian
258  /// of the transformation w.r.t the transformation parameters for all spatial (x, y, z) voxel
259  /// coordinates in world units, is assumed to correspond to the temporal origin of the given
260  /// gradient image. For 4D transformations parameterized by velocities, a second time for the
261  /// upper integration bound can be provided as last argument to this method. This last
262  /// argument is ignored by transformations parameterized by displacements.
263  ///
264  /// \sa ImageSimilarityMetric::EvaluateGradient
265  virtual void ParametricGradient(const GenericImage<double> *, double *,
266  const WorldCoordsImage * = NULL,
267  const WorldCoordsImage * = NULL,
268  double = NaN, double = 1) const;
269 
270  /// Applies the chain rule to convert point-wise non-parametric gradient
271  /// to a gradient w.r.t the parameters of this transformation.
272  virtual void ParametricGradient(const PointSet &, const Vector3D<double> *,
273  double *, double = 0, double = NaN, double = 1) const;
274 
275  // ---------------------------------------------------------------------------
276  // I/O
277 
278  // Do not hide methods of base class
280 
281  /// Prints the parameters of the transformation
282  virtual void Print(ostream &, Indent = 0) const;
283 
284  // ---------------------------------------------------------------------------
285  // Backwards compatibility
286 
287  /// Bending of multi-level free-form deformation
288  double Bending(double, double, double) const;
289 
290 };
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 // Inline definitions
294 ////////////////////////////////////////////////////////////////////////////////
295 
296 // =============================================================================
297 // Bounding box
298 // =============================================================================
299 
300 // -----------------------------------------------------------------------------
302 ::DOFBoundingBox(const Image *image, int dof, int &i1, int &j1, int &k1,
303  int &i2, int &j2, int &k2, double fraction) const
304 {
305  const FreeFormTransformation *ffd;
306  DOFIndexToLocalTransformation(this, dof, ffd, dof);
307  return ffd->DOFBoundingBox(image, dof, i1, j1, k1, i2, j2, k2, fraction);
308 }
309 
310 
311 } // namespace mirtk
312 
313 #endif // MIRTK_MultiLevelFreeFormTransformation_H
virtual void CombineLocalTransformation()
Combine local transformations on stack.
virtual void LocalHessian(int, Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the local transformation w.r.t world coordinates...
virtual void Displacement(int, int, double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point.
bool DOFBoundingBox(const Image *, int, int &, int &, int &, int &, int &, int &, double=1) const
bool DOFBoundingBox(const ImageAttributes &, int, int &, int &, int &, int &, int &, int &, double=1) const
double Bending(double, double, double) const
Bending of multi-level free-form deformation.
virtual int InverseDisplacement(int, int, GenericImage< double > &, double, double=NaN, const WorldCoordsImage *=NULL) const
virtual void LocalJacobian(int, Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
virtual void Hessian(int, int, Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the transformation w.r.t world coordinates.
virtual bool CanModifyDisplacement(int=-1) const
virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int, double *, double=1.0) const
virtual void Hessian(int, int, Matrix [3], double, double, double, double=0, double=NaN) const
Calculates the Hessian for each component of the transformation w.r.t world coordinates.
virtual bool InverseDisplacement(int, int, double &, double &, double &, double=0, double=NaN) const
Calculates the displacement of a single point using the inverse of the transformation.
virtual void DisplacementAfterDOFChange(int dof, double dv, GenericImage< double > &dx, double t, double t0=-1, const WorldCoordsImage *i2w=NULL) const
virtual ~MultiLevelFreeFormTransformation()
Destructor.
virtual void LocalTransform(int, int, double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the local transformation component only.
MultiLevelFreeFormTransformation()
Default constructor.
Definition: IOConfig.h:41
virtual void Displacement(int, int, GenericImage< double > &, double, double=NaN, const WorldCoordsImage *=NULL) const
virtual double Approximate(const ImageAttributes &, double *, double *, double *, int=1, double=.0)
virtual void Transform(int, int, double &, double &, double &, double=0, double=NaN) const
Transforms a single point.
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual void ApproximateDOFs(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int)
virtual void ParametricGradient(const GenericImage< double > *, double *, const WorldCoordsImage *=NULL, const WorldCoordsImage *=NULL, double=NaN, double=1) const
virtual double ApproximateAsNew(const ImageAttributes &, double *, double *, double *, int=1, double=.0)
virtual void Jacobian(int, int, Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the transformation w.r.t world coordinates.
virtual void LocalTransform(int, int, double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the local transformation component only.
virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double=0, double=NaN) const
Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w...
virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double=0, double=NaN) const
Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w...
virtual void Transform(int, int, double &, double &, double &, double=0, double=NaN) const =0
Transforms a single point.
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual void Jacobian(int, int, Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the transformation w.r.t world coordinates.