LinearFreeFormTransformation3D.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_LinearFreeFormTransformation3D_H
22 #define MIRTK_LinearFreeFormTransformation3D_H
23 
24 #include "mirtk/FreeFormTransformation3D.h"
25 #include "mirtk/LinearInterpolateImageFunction.h"
26 
27 #include <cmath>
28 
29 
30 namespace mirtk {
31 
32 
33 // Forward declaration
34 class BSplineFreeFormTransformation3D;
35 
36 
37 /**
38  * Free-form transformation with linear 3D interpolation kernel
39  */
41 {
42  mirtkTransformationMacro(LinearFreeFormTransformation3D);
43 
44  // ---------------------------------------------------------------------------
45  // Types
46 
48 
49  // ---------------------------------------------------------------------------
50  // Data members
51 
52 protected:
53 
54  /// Interpolates control point values at arbitrary lattice locations
55  Interpolator _FFD;
56 
57 public:
58 
59  // ---------------------------------------------------------------------------
60  // Construction/Destruction
61 
62  /// Default constructor
64 
65  /// Construct free-form transformation for given image domain and lattice spacing
66  LinearFreeFormTransformation3D(double, double, double,
67  double, double, double,
68  double, double, double,
69  double *, double *, double *);
70 
71  /// Construct free-form transformation for given image domain and lattice spacing
73  double = -1, double = -1, double = -1);
74 
75  /// Construct free-form transformation for given target image and lattice spacing
77  double, double, double);
78 
79  /// Construct free-form transformation from existing 3D+t displacement field
80  explicit LinearFreeFormTransformation3D(const GenericImage<double> &, bool = true);
81 
82  /// Construct free-form transformation from B-spline FFD
84 
85  /// Copy Constructor
87 
88  /// Destructor
90 
91  // ---------------------------------------------------------------------------
92  // Approximation/Interpolation
93 
94  /// Approximate displacements: This function takes a set of points and a set
95  /// of displacements and finds !new! parameters such that the resulting
96  /// transformation approximates the displacements as good as possible.
97  virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
98  const double *, const double *, const double *, int);
99 
100  /// Finds gradient of approximation error: This function takes a set of points
101  /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
102  /// which minimizes the L2 norm of the approximation error and adds it to the
103  /// input gradient with the given weight.
104  virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
105  const double *, const double *, const double *, int,
106  double *, double = 1.0) const;
107 
108  /// Interpolates displacements: This function takes a set of displacements defined
109  /// at the control points and finds a FFD which interpolates these displacements.
110  virtual void Interpolate(const double *, const double *, const double *);
111 
112  // ---------------------------------------------------------------------------
113  // Lattice
115 
116  /// Returns the bounding box for a control point (in mm). The last
117  /// parameter specifies what fraction of the bounding box to return.
118  /// The default is 1 which equals 100% of the bounding box.
119  virtual void BoundingBox(int, double &, double &, double &,
120  double &, double &, double &, double = 1) const;
121 
122  // ---------------------------------------------------------------------------
123  // Evaluation
124 
125  /// Evaluates the free-form transformation at a lattice point
126  void Evaluate(double &, double &, double &, int, int, int) const;
127 
128  /// Evaluates the free-form transformation at a point in lattice coordinates
129  void Evaluate(double &, double &, double &) const;
130 
131  /// Calculates the Jacobian of the local transformation w.r.t world coordinates
132  void EvaluateJacobian(Matrix &, double, double, double) const;
133 
134  // ---------------------------------------------------------------------------
135  // Point transformation
136 
137  /// Transforms a single point using the local transformation only
138  virtual void LocalTransform(double &, double &, double &, double = 0, double = NaN) const;
139 
140  /// Transforms a single point using the inverse of the local transformation only
141  virtual bool LocalInverse(double &, double &, double &, double = 0, double = NaN) const;
142 
143  // ---------------------------------------------------------------------------
144  // Derivatives
147 
148  /// Calculates the Jacobian of the local transformation w.r.t world coordinates
149  virtual void LocalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
150 
151  /// Calculates the Jacobian of the transformation w.r.t the transformation parameters
152  virtual void JacobianDOFs(double [3], int, int, int, double, double, double) const;
153 
154  // ---------------------------------------------------------------------------
155  // Properties
157 
158  /// Size of support region of the used kernel
159  virtual int KernelSize() const;
160 
161 protected:
162 
163  /// Calculate the bending energy of the transformation at control points
164  double BendingEnergy(int i, int j, int k) const;
165 
166 public:
167 
168  /// Approximates the bending energy on the control point lattice
169  virtual double BendingEnergy(bool = false, bool = true) const;
170 
171  /// Approximates the gradient of the bending energy on the control point
172  /// lattice w.r.t the transformation parameters and adds it with the given weight
173  virtual void BendingEnergyGradient(double *, double = 1, bool = false, bool = true, bool = true) const;
174 
175  // ---------------------------------------------------------------------------
176  // I/O
177 
178  // Do not hide methods of base class
180 
181  /// Prints the parameters of the transformation
182  virtual void Print(ostream &, Indent = 0) const;
183 
184  /// Whether this transformation can read a file of specified type (i.e. format)
185  virtual bool CanRead(TransformationType) const;
186 
187  // ---------------------------------------------------------------------------
188  // Others
189 
190  /// Compose this transformation (T1) with second transformation (T2).
191  /// The result is defined as T = T1 o T2.
192  virtual void Compose(const Transformation *);
193 
194 };
195 
196 // Backwards compatibility
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 // Inline definitions
201 ////////////////////////////////////////////////////////////////////////////////
202 
203 // =============================================================================
204 // Evaluation
205 // =============================================================================
206 
207 // -----------------------------------------------------------------------------
209 ::Evaluate(double &x, double &y, double &z, int i, int j, int k) const
210 {
211  Vector d = _CPValue->Get(i, j, k);
212  x = d._x, y = d._y, z = d._z;
213 }
214 
215 // -----------------------------------------------------------------------------
217 ::Evaluate(double &x, double &y, double &z) const
218 {
219  Vector d = _FFD(x, y, z);
220  x = d._x, y = d._y, z = d._z;
221 }
222 
223 // =============================================================================
224 // Point transformation
225 // =============================================================================
226 
227 // -----------------------------------------------------------------------------
229 ::LocalTransform(double &x, double &y, double &z, double, double) const
230 {
231  // Convert to lattice coordinates
232  double dx = x, dy = y, dz = z;
233  this->WorldToLattice(dx, dy, dz);
234  // Evaluate displacement
235  this->Evaluate(dx, dy, dz);
236  // Transform point
237  x += dx, y += dy, z += dz;
238 }
239 
240 // -----------------------------------------------------------------------------
242 ::LocalInverse(double &x, double &y, double &z, double, double) const
243 {
244  // Convert to lattice coordinates
245  double dx = x, dy = y, dz = z;
246  this->WorldToLattice(dx, dy, dz);
247  // Evaluate displacement
248  this->Evaluate(dx, dy, dz);
249  // Transform point
250  x -= dx, y -= dy, z -= dz;
251  return true;
252 }
253 
254 // =============================================================================
255 // Derivatives
256 // =============================================================================
257 
258 // -----------------------------------------------------------------------------
260 ::LocalJacobian(Matrix &jac, double x, double y, double z, double, double) const
261 {
262  // Convert to lattice coordinates
263  this->WorldToLattice(x, y, z);
264  // Compute 1st order derivatives
265  this->EvaluateJacobian(jac, x, y, z);
266  // Convert derivatives to world coordinates
267  JacobianToWorld(jac);
268  // Add derivatives of "x" term in T(x) = x + this->Evaluate(x)
269  jac(0, 0) += 1.0;
270  jac(1, 1) += 1.0;
271  jac(2, 2) += 1.0;
272 }
273 
274 // -----------------------------------------------------------------------------
276 ::JacobianDOFs(double jac[3], int ci, int cj, int ck, double x, double y, double z) const
277 {
278  // Convert point to lattice coordinates
279  this->WorldToLattice(x, y, z);
280  // Calculate tensor product of 1D linear interpolation kernels
281  const double dx = abs(ci - x);
282  const double dy = abs(cj - y);
283  const double dz = abs(ck - z);
284  if (dx < 1.0 && dy < 1.0 && dz < 1.0) {
285  jac[0] = jac[1] = jac[2] = (1.0 - dx) * (1.0 - dy) * (1.0 - dz);
286  } else {
287  jac[0] = jac[1] = jac[3] = .0;
288  }
289 }
290 
291 
292 } // namespace mirtk
293 
294 #endif // MIRTK_LinearFreeFormTransformation3D_H
double BendingEnergy(int i, int j, int k) const
Calculate the bending energy of the transformation at control points.
virtual ~LinearFreeFormTransformation3D()
Destructor.
virtual void Compose(const Transformation *)
CPExtrapolator * _CPValue
Infinite discrete representation of free-form transformation coefficients.
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual void JacobianDOFs(Matrix &, int, int, int, double, double, double) const
Calculates the Jacobian of the transformation w.r.t a control point.
void JacobianToWorld(double &, double &) const
virtual void BoundingBox(int, double &, double &, double &, double &, double &, double &, double=1) const
virtual double BendingEnergy(double, double, double, double=0, double=NaN, bool=true) const
Calculates the bending of the transformation.
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
Interpolator _FFD
Interpolates control point values at arbitrary lattice locations.
Definition: IOConfig.h:41
virtual bool CanRead(TransformationType) const
Whether this transformation can read a file of specified type (i.e. format)
void EvaluateJacobian(Matrix &, double, double, double) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
void BoundingBox(double &, double &) const
Gets the temporal bounding box of the free-form deformation (in ms)
virtual void LocalJacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
virtual void Interpolate(const double *, const double *, const double *)
T _z
The z component.
Definition: Vector3D.h:60
T _y
The y component.
Definition: Vector3D.h:59
virtual void LocalTransform(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the local transformation only.
virtual int KernelSize() const
Size of support region of the used kernel.
VoxelType Get(int) const
Get image value at an arbitrary discrete image location.
virtual void JacobianDOFs(double [3], int, int, int, double, double, double) const
Calculates the Jacobian of the transformation w.r.t the transformation parameters.
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 ApproximateDOFs(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int)
T _x
The x component.
Definition: Vector3D.h:58
virtual void LocalJacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
virtual void BendingEnergyGradient(double *, double=1, bool=false, bool=true, bool=true) const
LinearFreeFormTransformation3D()
Default constructor.
void Evaluate(double &, double &, double &, int, int, int) const
Evaluates the free-form transformation at a lattice point.
virtual bool LocalInverse(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the inverse of the local transformation only.
virtual void WorldToLattice(double &, double &) const
Transforms world coordinates (in mm) to lattice coordinates.