BSplineFreeFormTransformation3D.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_BSplineFreeFormTransformation3D_H
22 #define MIRTK_BSplineFreeFormTransformation3D_H
23 
24 #include "mirtk/FreeFormTransformation3D.h"
25 
26 #include "mirtk/FastCubicBSplineInterpolateImageFunction2D.h"
27 #include "mirtk/FastCubicBSplineInterpolateImageFunction3D.h"
28 
29 
30 namespace mirtk {
31 
32 
33 /**
34  * Class for free-form transformations based on tensor product B-splines.
35  *
36  * This class implements 3D free-form transformation using B-splines.
37  *
38  * For more details about the implementation see Lee, Wolberg and Shin, IEEE
39  * Transactions on Visualization and Computer Graphics, Vol. 3, No. 3, 1997.
40  */
42 {
43  mirtkTransformationMacro(BSplineFreeFormTransformation3D);
44 
45  // ---------------------------------------------------------------------------
46  // Types
47 
48  /// \todo Remove once BSplineFreeFormTransformation2D is implemented.
50 
51 public:
52 
55 
56  /// Options for parametric gradient calculation
58  {
59  PG_Default, ///< Default gradient computation.
60  PG_Analytic, ///< Analytic derivation w.r.t. DoFs.
61  PG_Convolution, ///< Convolution with cubic B-spline filter.
62  PG_Approximation ///< Approximate voxel-wise non-parametric gradient
63  ///< field with cubic B-spline function, also known
64  ///< as "directly manipulated FFD (DMFFD)".
65  };
66 
67  // ---------------------------------------------------------------------------
68  // Attributes
69 
70 protected:
71 
72  /// Whether to compute parametric gradient using cubic B-spline convolution
73  mirtkPublicAttributeMacro(ParametricGradientType, ParametricGradientCalculation);
74 
75  /// Interpolates control point values at arbitrary lattice locations
76  Interpolator _FFD;
77 
78  /// Interpolates control point values at arbitrary 2D lattice locations
79  /// \todo Remove once BSplineFreeFormTransformation2D is implemented.
80  Interpolator2D _FFD2D;
81 
82  // ---------------------------------------------------------------------------
83  // Construction/Destruction
84 
85 public:
86 
87  /// Default constructor
89 
90  /// Construct free-form transformation for given image domain and lattice spacing
91  BSplineFreeFormTransformation3D(double, double, double,
92  double, double, double,
93  double, double, double,
94  double *, double *, double *);
95 
96  /// Construct free-form transformation for given image domain and lattice spacing
98  double = -1, double = -1, double = -1);
99 
100  /// Construct free-form transformation for given target image and lattice spacing
102  double, double, double);
103 
104  /// Construct free-form transformation from existing 3D+t deformation field
105  explicit BSplineFreeFormTransformation3D(const GenericImage<double> &, bool = false);
106 
107  /// Copy Constructor
109 
110  /// Destructor
112 
113  // ---------------------------------------------------------------------------
114  // Parameters (non-DoFs)
115 
116  // Import other Parameter overloads
118 
119  /// Set named (non-DoF) parameter from value as string
120  virtual bool Set(const char *, const char *);
121 
122  /// Get (non-DoF) parameters as key/value as string map
123  virtual ParameterList Parameter() const;
124 
125  // ---------------------------------------------------------------------------
126  // Approximation/Interpolation
127 
128  /// Approximate displacements: This function takes a set of points and a set
129  /// of displacements and finds !new! parameters such that the resulting
130  /// transformation approximates the displacements as good as possible.
131  /// These parameters are added to the given coefficients using specified weight.
132  void AddApproximateSplineCoefficients(const double *, const double *, const double *,
133  const double *, const double *, const double *,
134  int, double *, double = 1., bool = false) const;
135 
136  /// Approximate displacements: This function takes a set of points and a set
137  /// of displacements and finds !new! parameters such that the resulting
138  /// transformation approximates the displacements as good as possible.
139  virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
140  const double *, const double *, const double *, int);
141 
142  /// Finds gradient of approximation error: This function takes a set of points
143  /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
144  /// which minimizes the L2 norm of the approximation error and adds it to the
145  /// input gradient with the given weight.
146  virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
147  const double *, const double *, const double *, int,
148  double *, double = 1.0) const;
149 
150  /// Interpolates displacements: This function takes a set of displacements defined
151  /// at the control points and finds a FFD which interpolates these displacements.
152  virtual void Interpolate(const double *, const double *, const double * = NULL);
153 
154  // ---------------------------------------------------------------------------
155  // Lattice
156 
158 
159  /// Number of control points in x after subdivision
160  virtual int GetXAfterSubdivision() const;
161 
162  /// Number of control points in y after subdivision
163  virtual int GetYAfterSubdivision() const;
164 
165  /// Number of control points in z after subdivision
166  virtual int GetZAfterSubdivision() const;
167 
168  /// Number of control points in t after subdivision
169  virtual int GetTAfterSubdivision() const;
170 
171  /// Control point spacing in x after subdivision
172  virtual double GetXSpacingAfterSubdivision() const;
173 
174  /// Control point spacing in y after subdivision
175  virtual double GetYSpacingAfterSubdivision() const;
176 
177  /// Control point spacing in z after subdivision
178  virtual double GetZSpacingAfterSubdivision() const;
179 
180  /// Control point spacing in t after subdivision
181  virtual double GetTSpacingAfterSubdivision() const;
182 
183  /// Subdivide FFD lattice
184  virtual void Subdivide(bool = true, bool = true, bool = true, bool = true);
185 
186  /// Returns the bounding box for a control point (in mm). The last
187  /// parameter specifies what fraction of the bounding box to return.
188  /// The default is 1 which equals 100% of the bounding box.
189  virtual void BoundingBox(int, double &, double &, double &,
190  double &, double &, double &, double = 1) const;
191 
192  // ---------------------------------------------------------------------------
193  // Evaluation
194 
195  /// Evaluates the FFD at a lattice point
196  void Evaluate(double &, double &, double &, int, int) const;
197 
198  /// Evaluates the FFD at a lattice point
199  void Evaluate(double &, double &, double &, int, int, int) const;
200 
201  /// Evaluates the FFD at a point in lattice coordinates
202  void Evaluate(double &, double &, double &) const;
203 
204  /// Evaluates the FFD at a point in lattice coordinates inside the FFD domain
205  void EvaluateInside(double &, double &, double &) const;
206 
207  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
208  void EvaluateJacobian(Matrix &, int, int) const;
209 
210  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
211  void EvaluateJacobian(Matrix &, int, int, int) const;
212 
213  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
214  void EvaluateJacobian(Matrix &, double, double) const;
215 
216  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
217  void EvaluateJacobian(Matrix &, double, double, double) const;
218 
219  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
220  /// and converts the resulting Jacobian to derivatives w.r.t world coordinates
221  void EvaluateJacobianWorld(Matrix &, double, double) const;
222 
223  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
224  /// and converts the resulting Jacobian to derivatives w.r.t world coordinates
225  void EvaluateJacobianWorld(Matrix &, double, double, double) const;
226 
227  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
228  /// w.r.t the control point with lattice coordinates (i, j)
229  void EvaluateJacobianDOFs(double [3], int, int, double, double) const;
230 
231  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
232  /// w.r.t the control point with lattice coordinates (i, j, k)
233  void EvaluateJacobianDOFs(double [3], int, int, int,
234  double, double, double) const;
235 
236  /// Calculates the Jacobian of the FFD at a point in lattice coordinates
237  /// w.r.t the control point with lattice coordinates (i, j, k)
238  ///
239  /// \note The temporal coordinates are required by the templated integration
240  /// methods. These arguments are ignored by this function.
241  void EvaluateJacobianDOFs(double [3], int, int, int, int,
242  double, double, double, double) const;
243 
244  /// Calculates the derivative of the Jacobian of the FFD at a point in lattice coordinates
245  /// w.r.t a transformation parameter
246  void EvaluateDerivativeOfJacobianWrtDOF(Matrix &, int, double, double) const;
247 
248  /// Calculates the derivative of the Jacobian of the FFD at a point in lattice coordinates
249  /// w.r.t a transformation parameter
250  void EvaluateDerivativeOfJacobianWrtDOF(Matrix &, int, double, double, double) const;
251 
252  /// Calculates the Hessian of the 2D FFD at a point in lattice coordinates
253  void EvaluateHessian(Matrix [3], int, int) const;
254 
255  /// Calculates the Hessian of the 2D FFD at a point in lattice coordinates
256  void EvaluateHessian(Matrix [3], double, double) const;
257 
258  /// Calculates the Hessian of the FFD at a point in lattice coordinates
259  void EvaluateHessian(Matrix [3], int, int, int) const;
260 
261  /// Calculates the Hessian of the FFD at a point in lattice coordinates
262  void EvaluateHessian(Matrix [3], double, double, double) const;
263 
264  /// Calculates the Laplacian of the FFD at a point in lattice coordinates
265  void EvaluateLaplacian(double [3], int, int, int) const;
266 
267  /// Calculates the Laplacian of the FFD at a point in lattice coordinates
268  void EvaluateLaplacian(double [3], double, double, double) const;
269 
270  /// Calculates the Laplacian of the FFD at a point in lattice coordinates
271  void EvaluateLaplacian(double &, double &, double &) const;
272 
273  /// Calculate derivatives of Jacobian determinant w.r.t. DoFs of control point
274  ///
275  /// \param[out] dJ Partial derivatives of Jacobian determinant w.r.t. DoFs of control point.
276  /// \param[in] adj Adjugate of Jacobian matrix evaluated at (x, y, z).
277  /// \param[in] a Distance from control point along x axis of lattice in lattice units.
278  /// \param[in] b Distance from control point along y axis of lattice in lattice units.
279  /// \param[in] c Distance from control point along z axis of lattice in lattice units.
280  /// \param[in] wrt_world Whether derivatives are computed w.r.t. world coordinate system.
281  /// \param[in] use_spacing Whether to use grid spacing when \p wrt_world is \c true.
282  void EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj, double a, double b, double c,
283  bool wrt_world = true, bool use_spacing = true) const;
284 
285  /// Calculate derivatives of Jacobian determinant w.r.t. DoFs of control point
286  ///
287  /// \param[out] dJ Partial derivatives of Jacobian determinant w.r.t. DoFs of control point.
288  /// \param[in] adj Adjugate of Jacobian matrix evaluated at (x, y, z).
289  /// \param[in] a Distance from control point along x axis of lattice in lattice units.
290  /// \param[in] b Distance from control point along y axis of lattice in lattice units.
291  /// \param[in] c Distance from control point along z axis of lattice in lattice units.
292  /// \param[in] wrt_world Whether derivatives are computed w.r.t. world coordinate system.
293  /// \param[in] use_spacing Whether to use grid spacing when \p wrt_world is \c true.
294  void EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj, int a, int b, int c,
295  bool wrt_world = true, bool use_spacing = true) const;
296 
297  /// Calculate derivatives of Jacobian determinant w.r.t. DoFs of control point
298  ///
299  /// \param[out] dJ Partial derivatives of Jacobian determinant w.r.t. DoFs of control point.
300  /// \param[in] adj Adjugate of Jacobian matrix evaluated at (x, y, z).
301  /// \param[in] i Index of control point along x axis of lattice.
302  /// \param[in] j Index of control point along y axis of lattice.
303  /// \param[in] k Index of control point along z axis of lattice.
304  /// \param[in] x Point coordinate along x axis of lattice in lattice units.
305  /// \param[in] y Point coordinate along y axis of lattice in lattice units.
306  /// \param[in] z Point coordinate along z axis of lattice in lattice units.
307  /// \param[in] wrt_world Whether derivatives are computed w.r.t. world coordinate system.
308  /// \param[in] use_spacing Whether to use grid spacing when \p wrt_world is \c true.
309  void EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj,
310  int i, int j, int k,
311  double x, double y, double z,
312  bool wrt_world = true, bool use_spacing = true) const;
313 
314  /// Calculate derivatives of Jacobian determinant w.r.t. DoFs of control point
315  ///
316  /// \param[out] dJ Partial derivatives of Jacobian determinant w.r.t. DoFs of control point.
317  /// \param[in] adj Adjugate of Jacobian matrix evaluated at (x, y, z).
318  /// \param[in] cp Linear index of control point.
319  /// \param[in] x Point coordinate along x axis of lattice in lattice units.
320  /// \param[in] y Point coordinate along y axis of lattice in lattice units.
321  /// \param[in] z Point coordinate along z axis of lattice in lattice units.
322  /// \param[in] wrt_world Whether derivatives are computed w.r.t. world coordinate system.
323  /// \param[in] use_spacing Whether to use grid spacing when \p wrt_world is \c true.
324  void EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj, int cp,
325  double x, double y, double z,
326  bool wrt_world = true, bool use_spacing = true) const;
327 
328  // ---------------------------------------------------------------------------
329  // Point transformation
330 
331  /// Transforms a single point using the local transformation component only
332  virtual void LocalTransform(double &, double &, double &, double = 0, double = NaN) const;
333 
334  /// Whether this transformation implements a more efficient update of a given
335  /// displacement field given the desired change of a transformation parameter
336  virtual bool CanModifyDisplacement(int = -1) const;
337 
338  /// Updates the displacement vectors for a whole image domain
339  ///
340  /// \param[in] dof Transformation parameter.
341  /// \param[in] dv Change of transformation parameter value.
342  /// \param[in,out] dx Displacement field to be updated.
343  /// \param[in] t Time point of start point.
344  /// \param[in] t0 Time point of end point.
345  /// \param[in] i2w Pre-computed world coordinates.
346  virtual void DisplacementAfterDOFChange(int dof, double dv,
348  double t, double t0 = -1,
349  const WorldCoordsImage *i2w = NULL) const;
350 
351  // ---------------------------------------------------------------------------
352  // Derivatives
353 
358 
359  /// Calculates the Jacobian of the transformation w.r.t either control point displacements or velocities
360  virtual void FFDJacobianWorld(Matrix &, double, double, double, double = 0, double = NaN) const;
361 
362  /// Calculates the Jacobian of the local transformation w.r.t world coordinates
363  virtual void LocalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
364 
365  /// Calculates the Hessian for each component of the local transformation w.r.t world coordinates
366  virtual void LocalHessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
367 
368  /// Calculates the Jacobian of the transformation w.r.t. the parameters of a control point
369  virtual void JacobianDOFs(double [3], int, int, int, double, double, double) const;
370 
371  /// Calculates derivatives of the Jacobian determinant of spline function w.r.t. DoFs of a control point
372  ///
373  /// This function is identical to JacobianDetDerivative when the DoFs of the control points are displacements.
374  /// When the DoFs are velocities, however, this function computes the derivatives of the Jacobian determinant
375  /// of the velocity field instead.
376  ///
377  /// \param[out] dJ Partial derivatives of Jacobian determinant at (x, y, z) w.r.t. DoFs of control point.
378  /// \param[in] cp Index of control point w.r.t. whose DoFs the derivatives are computed.
379  /// \param[in] x World coordinate along x axis at which to evaluate derivatives.
380  /// \param[in] y World coordinate along y axis at which to evaluate derivatives.
381  /// \param[in] z World coordinate along z axis at which to evaluate derivatives.
382  /// \param[in] adj Adjugate of Jacobian matrix evaluated at (x, y, z).
383  /// \param[in] wrt_world Whether derivatives are computed w.r.t. world coordinate system.
384  /// \param[in] use_spacing Whether to use grid spacing when \p wrt_world is \c true.
385  virtual void FFDJacobianDetDerivative(double dJ[3], const Matrix &adj,
386  int cp, double x, double y, double z, double = 0, double = NaN,
387  bool wrt_world = true, bool use_spacing = true) const;
388 
389  /// Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w.r.t. a transformation parameter
390  virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double = 0, double = NaN) const;
391 
392  /// Applies the chain rule to convert spatial non-parametric gradient
393  /// to a gradient w.r.t the parameters of this transformation
394  virtual void ParametricGradient(const GenericImage<double> *, double *,
395  const WorldCoordsImage *,
396  const WorldCoordsImage *,
397  double = NaN, double = 1) const;
398 
399  // ---------------------------------------------------------------------------
400  // Properties
401 
402  /// Size of support region of the used kernel
403  virtual int KernelSize() const;
404 
405  /// Calculates the bending energy of the transformation
406  virtual double BendingEnergy(double, double, double, double = 0, double = NaN, bool = true) const;
407 
408  /// Approximates the bending energy on the control point lattice
409  virtual double BendingEnergy(bool = false, bool = true) const;
410 
411  /// Approximates the bending energy on the specified discrete domain
412  virtual double BendingEnergy(const ImageAttributes &, double = NaN, bool = true) const;
413 
414  /// Approximates and adds the gradient of the bending energy on the control point
415  /// lattice w.r.t the transformation parameters using the given weight
416  virtual void BendingEnergyGradient(double *, double = 1, bool = false, bool = true, bool = true) const;
417 
418  // ---------------------------------------------------------------------------
419  // I/O
420 
421  // Do not hide methods of base class
423 
424  /// Prints the parameters of the transformation
425  virtual void Print(ostream &, Indent = 0) const;
426 
427  /// Whether this transformation can read a file of specified type (i.e. format)
428  virtual bool CanRead(TransformationType) const;
429 
430 };
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 // Inline definitions
434 ////////////////////////////////////////////////////////////////////////////////
435 
436 // =============================================================================
437 // String conversion of enum values
438 // =============================================================================
439 
440 // ----------------------------------------------------------------------------
441 template <>
442 inline string ToString(const BSplineFreeFormTransformation3D::ParametricGradientType &value, int w, char c, bool left)
443 {
444  const char *str;
445  switch (value) {
446  case BSplineFreeFormTransformation3D::PG_Default: str = "Default"; break;
447  case BSplineFreeFormTransformation3D::PG_Analytic: str = "Analytic"; break;
448  case BSplineFreeFormTransformation3D::PG_Convolution: str = "Convolution"; break;
449  case BSplineFreeFormTransformation3D::PG_Approximation: str = "Approximation"; break;
450  default: str = "Unknown"; break;
451  }
452  return ToString(str, w, c, left);
453 }
454 
455 // ----------------------------------------------------------------------------
456 template <>
457 inline bool FromString(const char *str, BSplineFreeFormTransformation3D::ParametricGradientType &value)
458 {
459  string lstr = ToLower(str);
460  if (lstr == "default") {
462  } else if (lstr == "analytic" || lstr == "exact") {
464  } else if (lstr == "convolution") {
466  } else if (lstr == "dmffd" || lstr == "directlymanipulated" || lstr == "directly manipulated" || lstr == "approximation") {
468  } else {
469  return false;
470  }
471  return true;
472 }
473 
474 // =============================================================================
475 // Evaluation
476 // =============================================================================
477 
478 // -----------------------------------------------------------------------------
480 ::Evaluate(double &x, double &y, double &z) const
481 {
482  Vector d = ((_z == 1) ? _FFD2D(x, y) : _FFD(x, y, z));
483  x = d._x, y = d._y, z = d._z;
484 }
485 
486 // -----------------------------------------------------------------------------
488 ::EvaluateInside(double &x, double &y, double &z) const
489 {
490  Vector d = ((_z == 1) ? _FFD2D.GetInside(x, y) : _FFD.GetInside(x, y, z));
491  x = d._x, y = d._y, z = d._z;
492 }
493 
494 // -----------------------------------------------------------------------------
496 ::EvaluateJacobianWorld(Matrix &jac, double x, double y) const
497 {
498  // Compute 1st order derivatives
499  EvaluateJacobian(jac, x, y);
500  // Convert derivatives to world coordinates
501  JacobianToWorld(jac);
502 }
503 
504 // -----------------------------------------------------------------------------
506 ::EvaluateJacobianWorld(Matrix &jac, double x, double y, double z) const
507 {
508  // Compute 1st order derivatives
509  EvaluateJacobian(jac, x, y, z);
510  // Convert derivatives to world coordinates
511  JacobianToWorld(jac);
512 }
513 
514 // -----------------------------------------------------------------------------
516 ::EvaluateJacobianDOFs(double jac[3], int i, int j, double x, double y) const
517 {
518  jac[0] = jac[1] = jac[2] = Kernel::Weight(x - i) * Kernel::Weight(y - j);
519 }
520 
521 // -----------------------------------------------------------------------------
523 ::EvaluateJacobianDOFs(double jac[3], int i, int j, int k,
524  double x, double y, double z) const
525 {
526  jac[0] = jac[1] = jac[2] = Kernel::Weight(x - i) *
527  Kernel::Weight(y - j) *
528  Kernel::Weight(z - k);
529 }
530 
531 // -----------------------------------------------------------------------------
533 ::EvaluateJacobianDOFs(double jac[3], int i, int j, int k, int,
534  double x, double y, double z, double) const
535 {
536  EvaluateJacobianDOFs(jac, i, j, k, x, y, z);
537 }
538 
539 // -----------------------------------------------------------------------------
541 ::EvaluateDerivativeOfJacobianWrtDOF(Matrix &dJdp, int dof, double x, double y) const
542 {
543  const int dim = this->DOFToDimension(dof);
544 
545  int i, j;
546  this->IndexToLattice(this->DOFToIndex(dof), i, j);
547 
548  double val;
549  if (dim == 0) val = Kernel::B_I(x - i) * Kernel::B (y - j);
550  else val = Kernel::B (x - i) * Kernel::B_I(y - j);
551 
552  dJdp.Initialize(3, 3);
553  dJdp(0, dim) = dJdp(1, dim) = dJdp(2, dim) = val;
554 }
555 
556 // -----------------------------------------------------------------------------
558 ::EvaluateDerivativeOfJacobianWrtDOF(Matrix &dJdp, int dof, double x, double y, double z) const
559 {
560  const int dim = this->DOFToDimension(dof);
561 
562  int i, j, k;
563  this->IndexToLattice(this->DOFToIndex(dof), i, j, k);
564 
565  double val;
566  if (dim == 0) val = Kernel::B_I(x - i) * Kernel::B (y - j) * Kernel::B (z - k);
567  else if (dim == 1) val = Kernel::B (x - i) * Kernel::B_I(y - j) * Kernel::B (z - k);
568  else val = Kernel::B (x - i) * Kernel::B (y - j) * Kernel::B_I(z - k);
569 
570  dJdp.Initialize(3, 3);
571  dJdp(0, dim) = dJdp(1, dim) = dJdp(2, dim) = val;
572 }
573 
574 // =============================================================================
575 // Point transformation
576 // =============================================================================
577 
578 // -----------------------------------------------------------------------------
580 ::LocalTransform(double &x, double &y, double &z, double, double) const
581 {
582  // Convert to lattice coordinates
583  double dx = x, dy = y, dz = z;
584  this->WorldToLattice(dx, dy, dz);
585  // Evaluate displacement
586  Evaluate(dx, dy, dz);
587  // Transform point
588  x += dx, y += dy, z += dz;
589 }
590 
591 // =============================================================================
592 // Derivatives
593 // =============================================================================
594 
595 // -----------------------------------------------------------------------------
596 inline void BSplineFreeFormTransformation3D::FFDJacobianWorld(Matrix &jac, double x, double y, double z, double, double) const
597 {
598  // Convert to lattice coordinates
599  this->WorldToLattice(x, y, z);
600  // Compute 1st order derivatives
601  if (_z == 1) EvaluateJacobianWorld(jac, x, y);
602  else EvaluateJacobianWorld(jac, x, y, z);
603  // Add derivatives of "x" term in T(x) = x + FFD(x)
604  jac(0, 0) += 1.0;
605  jac(1, 1) += 1.0;
606  jac(2, 2) += 1.0;
607 }
608 
609 // -----------------------------------------------------------------------------
610 inline void BSplineFreeFormTransformation3D::LocalJacobian(Matrix &jac, double x, double y, double z, double t, double t0) const
611 {
613 }
614 
615 // -----------------------------------------------------------------------------
616 inline void BSplineFreeFormTransformation3D::LocalHessian(Matrix hessian[3], double x, double y, double z, double, double) const
617 {
618  // Convert to lattice coordinates
619  this->WorldToLattice(x, y, z);
620  // Compute 2nd order derivatives
621  if (_z == 1) EvaluateHessian(hessian, x, y);
622  else EvaluateHessian(hessian, x, y, z);
623  // Convert derivatives to world coordinates
624  HessianToWorld(hessian);
625 }
626 
627 // -----------------------------------------------------------------------------
629 ::JacobianDOFs(double jac[3], int ci, int cj, int ck, double x, double y, double z) const
630 {
631  // Convert point to lattice coordinates
632  this->WorldToLattice(x, y, z);
633  // Evaluate derivatives w.r.t. transformation parameters
634  if (_z == 1) EvaluateJacobianDOFs(jac, ci, cj, x, y);
635  else EvaluateJacobianDOFs(jac, ci, cj, ck, x, y, z);
636 }
637 
638 // -----------------------------------------------------------------------------
640 ::DeriveJacobianWrtDOF(Matrix &dJdp, int dof, double x, double y, double z, double, double) const
641 {
642  // Convert point to lattice coordinates
643  this->WorldToLattice(x, y, z);
644  // Evaluate derivatives w.r.t. transformation parameters
645  if (_z == 1) EvaluateDerivativeOfJacobianWrtDOF(dJdp, dof, x, y);
646  else EvaluateDerivativeOfJacobianWrtDOF(dJdp, dof, x, y, z);
647  // Convert derivatives to world coordinates
648  JacobianToWorld(dJdp);
649 }
650 
651 // -----------------------------------------------------------------------------
653 ::EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj,
654  int i, int j, int k, double x, double y, double z,
655  bool wrt_world, bool use_spacing) const
656 {
657  EvaluateJacobianDetDerivative(dJ, adj, x - i, y - j, z - k, wrt_world, use_spacing);
658 }
659 
660 // -----------------------------------------------------------------------------
662 ::EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj,
663  int cp, double x, double y, double z,
664  bool wrt_world, bool use_spacing) const
665 {
666  int i, j, k;
667  this->IndexToLattice(cp, i, j, k);
668  EvaluateJacobianDetDerivative(dJ, adj, x - i, y - j, z - k, wrt_world, use_spacing);
669 }
670 
671 // -----------------------------------------------------------------------------
673 ::FFDJacobianDetDerivative(double dJ[3], const Matrix &adj,
674  int cp, double x, double y, double z, double, double,
675  bool wrt_world, bool use_spacing) const
676 {
677  int i, j, k;
678  this->IndexToLattice(cp, i, j, k);
679  this->WorldToLattice(x, y, z);
680  EvaluateJacobianDetDerivative(dJ, adj, x - i, y - j, z - k, wrt_world, use_spacing);
681 }
682 
683 
684 } // namespace mirtk
685 
686 #endif // MIRTK_BSplineFreeFormTransformation3D_H
void EvaluateInside(double &, double &, double &) const
Evaluates the FFD at a point in lattice coordinates inside the FFD domain.
void EvaluateJacobian(Matrix &, int, int) const
Calculates the Jacobian of the FFD at a point in lattice coordinates.
static MIRTKCU_API TReal Weight(TReal)
Returns the value of the B-spline function.
Definition: BSpline.h:291
static MIRTKCU_API TReal B_I(TReal)
Returns the 1st derivative value of the B-spline function.
Definition: BSpline.h:356
virtual void ApproximateDOFs(const double *, const double *, const double *, const double *, const double *, const double *, const double *, int)
void EvaluateJacobianDetDerivative(double dJ[3], const Matrix &adj, double a, double b, double c, bool wrt_world=true, bool use_spacing=true) const
virtual void ParametricGradient(const GenericImage< double > *, double *, const WorldCoordsImage *, const WorldCoordsImage *, double=NaN, double=1) const
to a gradient w.r.t the parameters of this transformation
static MIRTKCU_API TReal B(TReal)
Returns the value of the B-spline function.
Definition: BSpline.h:308
virtual void FFDJacobianDetDerivative(double dJ[3], const Matrix &adj, int cp, double x, double y, double z, double=0, double=NaN, bool wrt_world=true, bool use_spacing=true) const
void EvaluateJacobianWorld(Matrix &, double, double) const
virtual void JacobianDOFs(Matrix &, int, int, int, double, double, double) const
Calculates the Jacobian of the transformation w.r.t a control point.
virtual void LocalJacobian(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the local transformation w.r.t world coordinates.
Interpolator _FFD
Interpolates control point values at arbitrary lattice locations.
void JacobianToWorld(double &, double &) const
virtual bool Set(const char *, const char *)
Set named (non-DoF) parameter from value as string.
virtual void DisplacementAfterDOFChange(int dof, double dv, GenericImage< double > &dx, double t, double t0=-1, const WorldCoordsImage *i2w=NULL) const
virtual ~BSplineFreeFormTransformation3D()
Destructor.
virtual VoxelType GetInside(double, double, double=0, double=0) const
int DOFToDimension(int) const
Get index of dimension corresponding to transformation parameter (DoFs)
virtual void Interpolate(const double *, const double *, const double *=NULL)
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual void LocalHessian(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 ParametricGradient(const GenericImage< double > *, double *, const WorldCoordsImage *, const WorldCoordsImage *, double=NaN, double=1) const
virtual void LocalTransform(double &, double &, double &, double=0, double=NaN) const
Transforms a single point using the local transformation component only.
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
virtual ParameterList Parameter() const
Get (non-DoF) parameters as key/value as string map.
virtual bool CanRead(TransformationType) const
Whether this transformation can read a file of specified type (i.e. format)
virtual double GetYSpacingAfterSubdivision() const
Control point spacing in y after subdivision.
virtual double GetTSpacingAfterSubdivision() const
Control point spacing in t after subdivision.
void EvaluateLaplacian(double [3], int, int, int) const
Calculates the Laplacian of the FFD at a point in lattice coordinates.
void Initialize(int, int=-1, double *=NULL)
Initialize matrix with number of rows and columns.
string ToLower(const string &)
Convert string to lowercase letters.
virtual int GetYAfterSubdivision() const
Number of control points in y after subdivision.
virtual void BendingEnergyGradient(double *, double=1, bool=false, bool=true, bool=true) const
Definition: IOConfig.h:41
virtual void BoundingBox(int, double &, double &, double &, double &, double &, double &, double=1) const
virtual int GetZAfterSubdivision() const
Number of control points in z after subdivision.
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...
void AddApproximateSplineCoefficients(const double *, const double *, const double *, const double *, const double *, const double *, int, double *, double=1., bool=false) const
ParametricGradientType
Options for parametric gradient calculation.
virtual VoxelType GetInside(double, double, double, double=0) const
void BoundingBox(double &, double &) const
Gets the temporal bounding box of the free-form deformation (in ms)
mirtkPublicAttributeMacro(ParametricGradientType, ParametricGradientCalculation)
Whether to compute parametric gradient using cubic B-spline convolution.
void EvaluateHessian(Matrix [3], int, int) const
Calculates the Hessian of the 2D FFD at a point in lattice coordinates.
virtual void FFDJacobianWorld(Matrix &, double, double, double, double=0, double=NaN) const
Calculates the Jacobian of the transformation w.r.t either control point displacements or velocities...
string ToString(const EnergyMeasure &value, int w, char c, bool left)
Convert energy measure enumeration value to string.
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.
bool FromString(const char *str, EnergyMeasure &value)
Convert energy measure string to enumeration value.
virtual double GetZSpacingAfterSubdivision() const
Control point spacing in z after subdivision.
BSplineFreeFormTransformation3D()
Default constructor.
void Evaluate(double &, double &, double &, int, int) const
Evaluates the FFD at a lattice point.
void IndexToLattice(int, int &, int &) const
Get control point lattice coordinates from index.
T _z
The z component.
Definition: Vector3D.h:60
T _y
The y component.
Definition: Vector3D.h:59
virtual void Print(ostream &, Indent=0) const
Prints the parameters of the transformation.
virtual ParameterList Parameter() const
Get (non-DoF) parameters as key/value as string map.
virtual int GetXAfterSubdivision() const
Number of control points in x after subdivision.
virtual void Subdivide(bool=true, bool=true, bool=true, bool=true)
Subdivide FFD lattice.
virtual void LocalHessian(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 int GetTAfterSubdivision() const
Number of control points in t after subdivision.
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 double GetXSpacingAfterSubdivision() const
Control point spacing in x after subdivision.
virtual bool CanModifyDisplacement(int=-1) const
virtual int KernelSize() const
Size of support region of the used kernel.
virtual double BendingEnergy(double, double, double, double=0, double=NaN, bool=true) const
Calculates the bending energy of the transformation.
void EvaluateJacobianDOFs(double [3], int, int, double, double) const
void HessianToWorld(double &, double &, double &) const
int DOFToIndex(int) const
Get index of control point corresponding to transformation parameter (DoFs)
void EvaluateDerivativeOfJacobianWrtDOF(Matrix &, int, double, double) const
virtual void JacobianDOFs(double [3], int, int, int, double, double, double) const
Calculates the Jacobian of the transformation w.r.t. the parameters of a control point.
virtual void WorldToLattice(double &, double &) const
Transforms world coordinates (in mm) to lattice coordinates.