LinearFreeFormTransformationTD.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_LinearFreeFormTransformationTD_H
21 #define MIRTK_LinearFreeFormTransformationTD_H
22 
23 #include "mirtk/LinearFreeFormTransformation4D.h"
24 
25 #include <cmath>
26 
27 
28 namespace mirtk {
29 
30 
31 // Forward declaration of other TD FFD
32 class BSplineFreeFormTransformationTD;
33 
34 
35 /**
36  * Temporal diffeomorphic free-form transformation.
37  *
38  * This class implements a free-form transformation which is represented
39  * by a time-varying velocity field (3D+t). The 3D displacement field at a
40  * specific time is obtained by integrating the velocity field starting at the
41  * reference time point. The integration steps are adjusted if necessary in
42  * order to ensure that the resulting spatial transformation is diffeomorphic.
43  *
44  * For more details about the implementation see De Craene et al. (2012).
45  * Temporal diffeomorphic free-form deformation: application to motion and
46  * strain estimation from 3D echocardiography.
47  * Medical image analysis, 16(2), 427, 2012. doi:10.1016/j.media.2011.10.006
48  */
50 {
51  mirtkTransformationMacro(LinearFreeFormTransformationTD);
52 
53  // ---------------------------------------------------------------------------
54  // Attributes
55 
56  /// Minimum length of temporal steps (in ms)
57  mirtkPublicAttributeMacro(double, MinTimeStep);
58 
59  /// Maximum length of temporal steps (in ms)
60  mirtkPublicAttributeMacro(double, MaxTimeStep);
61 
62  // ---------------------------------------------------------------------------
63  // Construction/Destruction
64 
65 public:
66 
67  /// Default constructor
69 
70  /// Construct free-form transformation for given domain and lattice spacing
72  double, double, double, double);
73 
74  /// Construct free-form transformation for given target image and lattice spacing
76  double, double, double, double);
77 
78  /// Constructor
80 
81  /// Copy constructor
83 
84  /// Destructor
86 
87  // ---------------------------------------------------------------------------
88  // Approximation/Interpolation
89 
91 
92  /// Approximate displacements: This function takes a set of 3D displacement fields
93  /// and corresponding time points and temporal intervals. Given these inputs,
94  /// it finds a time-varying velocity field which approximates these displacements.
95  virtual void ApproximateDOFs(const GenericImage<double> * const *,
96  const double *, const double *, int,
97  bool = false, int = 3, int = 8);
98 
99  /// Approximate displacements: This function takes a set of points and a set
100  /// of displacements and finds !new! parameters such that the resulting
101  /// transformation approximates the displacements as good as possible.
102  virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
103  const double *, const double *, const double *, int);
104 
105  /// Finds gradient of approximation error: This function takes a set of points
106  /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
107  /// which minimizes the L2 norm of the approximation error and adds it to the
108  /// input gradient with the given weight.
109  virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
110  const double *, const double *, const double *, int,
111  double *, double = 1.0) const;
112 
113  /// Approximate displacements: This function takes a set of 3D displacement fields
114  /// and corresponding time points and temporal intervals. Given these inputs,
115  /// it finds a time-varying velocity field which approximates these displacements.
116  /// The displacements are replaced by the residual displacements of the newly
117  /// approximated transformation. Returns the approximation error of the resulting FFD.
118  virtual double ApproximateAsNew(GenericImage<double> **,
119  const double *, const double *, int,
120  bool = false, int = 3, int = 8);
121 
122  /// Interpolates displacements: This function takes a set of displacements defined at
123  /// the control points and finds a time-varying velocity field such that the
124  /// resulting transformation interpolates these displacements.
125  virtual void Interpolate(const double *, const double *, const double *);
126 
127  // ---------------------------------------------------------------------------
128  // Point transformation
129 
130  /// Transforms a single point
131  virtual void LocalTransform(double &, double &, double &, double, double) const;
132 
133  /// Transforms a single point using the inverse transformation
134  virtual bool LocalInverse(double &, double &, double &, double, double) const;
135 
136  // ---------------------------------------------------------------------------
137  // I/O
138 
139  // Do not hide methods of base class
141 
142  /// Prints the parameters of the transformation
143  virtual void Print(ostream &, Indent = 0) const;
144 
145  /// Whether this transformation can read a file of specified type (i.e. format)
146  virtual bool CanRead(TransformationType) const;
147 
148 protected:
149 
150  /// Reads transformation parameters from a file stream
152 
153  /// Writes transformation parameters to a file stream
154  virtual Cofstream &WriteDOFs(Cofstream &) const;
155 
156 };
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 // Inline definitions
160 ////////////////////////////////////////////////////////////////////////////////
161 
162 // =============================================================================
163 // Point transformation
164 // =============================================================================
165 
166 // -----------------------------------------------------------------------------
167 inline void LinearFreeFormTransformationTD::LocalTransform(double &x, double &y, double &z, double t1, double t2) const
168 {
169  double u, v, w, s;
170  Matrix sjac(3, 3);
171 
172  // Number of integration steps
173  int minsteps = abs(iround((t2 - t1) / _MaxTimeStep));
174  int maxsteps = abs(iround((t2 - t1) / _MinTimeStep));
175  if (minsteps < 2) minsteps = 2;
176  if (maxsteps < 2) maxsteps = 2;
177 
178  // Initial step size
179  int N = minsteps;
180  double dt = (t2 - t1) / N;
181  // Transform point by integrating the velocity over time
182  double t = t1;
183  for (int n = 0; n < N; n++) {
184  u = x;
185  v = y;
186  w = z;
187  this->WorldToLattice(u, v, w);
188  s = this->TimeToLattice(t);
189  // Check if still inside FFD domain
190  if (-2 <= u && u <= _x + 1 &&
191  -2 <= v && v <= _y + 1 &&
192  -2 <= w && w <= _z + 1 &&
193  -2 <= s && s <= _t + 1) {
194  // Reduce step size if necessary to ensure invertibility
195  while (N < maxsteps) {
196  // Compute current factor of Jacobian of deformation w.r.t the spatial variable.
197  //
198  // See equation (5) of De Craene et al., Medical Image Analysis 16 (2012).
199  // The partial derivatives are calculated w.r.t the spatial variables.
200  // The goal is to avoid foldings and singularities in the spatial domain
201  // while computing the temporal trajectory of a point.
202  EvaluateJacobian(sjac, u, v, w, s);
203  sjac = sjac * _matW2L(0, 0, 3, 3) * dt;
204  sjac(0, 0) += 1;
205  sjac(1, 1) += 1;
206  sjac(2, 2) += 1;
207  // In case of negative Jacobian determinant, reduce step size
208  if (sjac.Det3x3() < 0) {
209  N *= 2;
210  if (N > maxsteps) {
211  N = maxsteps;
212  dt = (t2 - t1) / N;
213  } else {
214  dt /= 2;
215  }
216  continue;
217  }
218  break;
219  }
220  // Integration step
221  EvaluateInside(u, v, w, s); // velocity
222  x += u * dt;
223  y += v * dt;
224  z += w * dt;
225  t += dt;
226  // Outside FFD domain, velocity is zero
227  } else {
228  break;
229  }
230  }
231 }
232 
233 // -----------------------------------------------------------------------------
234 inline bool LinearFreeFormTransformationTD::LocalInverse(double &x, double &y, double &z, double t1, double t2) const
235 {
236  this->LocalTransform(x, y, z, t2, t1);
237  return true;
238 }
239 
240 
241 } // namespace mirtk
242 
243 #endif // MIRTK_LinearFreeFormTransformationTD_H
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual double TimeToLattice(double) const
Transforms time (in ms) to temporal lattice coordinate.
double Det3x3() const
Calculate determinant of a 3x3 matrix.
Definition: Matrix.h:1019
virtual Cifstream & ReadDOFs(Cifstream &, TransformationType)
Reads transformation parameters from a file stream.
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
const Matrix & _matW2L
Read-only reference to _matW2I of _CPImage.
const int & _x
Read-only reference to _x attribute of _CPImage.
virtual Cofstream & WriteDOFs(Cofstream &) const
Writes transformation parameters to a file stream.
virtual void ApproximateDOFs(const GenericImage< double > *const *, const double *, const double *, int, bool=false, int=3, int=8)
void EvaluateJacobian(Matrix &, double, double, double, double) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
void EvaluateInside(double &, double &, double &, double) const
Evaluates the free-form transformation at a point in lattice coordinates.
virtual double ApproximateAsNew(const Transformation *, int=1, double=.0)
Approximate another transformation and return approximation error.
Definition: IOConfig.h:41
LinearFreeFormTransformationTD()
Default constructor.
virtual double ApproximateAsNew(GenericImage< double > **, const double *, const double *, int, bool=false, int=3, int=8)
virtual bool CanRead(TransformationType) const
Whether this transformation can read a file of specified type (i.e. format)
virtual ~LinearFreeFormTransformationTD()
Destructor.
const int & _t
Read-only reference to _t attribute of _CPImage.
virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int, double *, double=1.0) const
const int & _z
Read-only reference to _z attribute of _CPImage.
virtual void Interpolate(const double *, const double *, const double *)
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
Definition: Math.h:170
const int & _y
Read-only reference to _y attribute of _CPImage.
virtual bool LocalInverse(double &, double &, double &, double, double) const
Transforms a single point using the inverse transformation.
virtual void LocalTransform(double &, double &, double &, double, double) const
Transforms a single point.
virtual void WorldToLattice(double &, double &) const
Transforms world coordinates (in mm) to lattice coordinates.