NegJacobianConstraint.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2017 Imperial College London
5  * Copyright 2017 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_NegJacobianConstraint_H
21 #define MIRTK_NegJacobianConstraint_H
22 
23 #include "mirtk/JacobianConstraint.h"
24 
25 
26 namespace mirtk {
27 
28 
29 /**
30  * Penalize small and negative Jacobian determinant values of parameterization
31  *
32  * This constraint prevents folding of the transformation parameterization,
33  * i.e., either of the control point displacements or velocities. It preserves
34  * topology in case of a classic FFD model and is in this case identical to
35  * the TopologyPreservationConstraint. For the SVFFD model, it penalizes
36  * small and negative Jacobian determinant values of the velocity field,
37  * not the displacement field generated by this stationary velocity field.
38  *
39  * This Jacobian based transformation constraint is based on the original
40  * IRTK implementation, but not identical. When the Jacobian determinant
41  * value is smaller than a small value, _Epsilon, the penalty function is
42  * a linear function instead, which is a continuation of the penalty function
43  * used for determinant values in the range _Epsilon < det(J) < _Gamma.
44  * The slope of this linear function corresponds to the derivative of the
45  * penalty at _Epsilon. The problem with the IRTK implementation is that the
46  * penalty decreases again for negative values before increasing slowly
47  * quadratically. It is further undefined for zero determinant values.
48  * This is because the penalty function adopted from Edwards et al. (1998)
49  * is only defined for positive values.
50  *
51  * Edwards et al. (1998). A three-component deformation model for image-guided surgery.
52  * Medical Image Analysis, 2(4), 355–367. https://doi.org/10.1016/S1361-8415(98)80016-9
53  *
54  * Rueckert et al. (2006). Diffeomorphic registration using B-splines. MICCAI, 702–709.
55  */
57 {
58  mirtkEnergyTermMacro(LogJacobianConstraint, EM_NegDetJac);
59 
60  /// Small value below which Jacobian determinant is penalised linearly
61  /// with increasing smaller (i.e., negative) value
62  ///
63  /// The penalty implemented in IRTK can be used with _Epsilon set to a very
64  /// negative value, i.e., negative with great magnitude, -inf, or NaN.
65  mirtkPublicAttributeMacro(double, Epsilon);
66 
67  /// Jacobian determinant threshold below which penalty is non-zero
68  ///
69  /// The _Gamma value that was hard coded in IRTK is 0.3. A higher value
70  /// is used by this class, however, because it allows the panlty to earlier
71  /// prevent "shocks" in the deformation before these impose a too strong
72  /// and sudden penalty.
73  mirtkPublicAttributeMacro(double, Gamma);
74 
75  /// Power of Jacobian determinant used for penalty term
76  mirtkPublicAttributeMacro(int, Power);
77 
78 public:
79 
80  /// Constructor
81  NegJacobianConstraint(const char * = "", bool = true);
82 
83  /// Destructor
84  virtual ~NegJacobianConstraint();
85 
86 protected:
87 
88  /// Set parameter value from string
89  virtual bool SetWithPrefix(const char *, const char *);
90 
91  /// Set parameter value from string
92  virtual bool SetWithoutPrefix(const char *, const char *);
93 
94 public:
95 
96  // Import other overloads
98 
99  /// Get parameter key/value as string map
100  virtual ParameterList Parameter() const;
101 
102  // ---------------------------------------------------------------------------
103  // Penalty
104 
105 public:
106 
107  /// Evaluate penalty at control point location given Jacobian determinant value
108  virtual double Penalty(double det) const
109  {
110  if (det >= _Gamma) return 0.;
111  double a = pow(_Gamma, _Power);
112  if (det < _Epsilon) {
113  double b = pow(_Epsilon, _Power);
114  double m = _Power * ((pow(_Epsilon, _Power - 1) / a) - (a / pow(_Epsilon, _Power + 1)));
115  double t = a / b + b / a - 2. - m * _Epsilon;
116  return m * det + t;
117  } else {
118  double b = pow(det, _Power);
119  return a / b + b / a - 2.;
120  }
121  }
122 
123  /// Evaluate derivative of penalty w.r.t. Jacobian determinant value
124  virtual double DerivativeWrtJacobianDet(double det) const
125  {
126  if (det >= _Gamma) return 0.;
127  if (det < _Epsilon) det = _Epsilon;
128  double a = pow(_Gamma, _Power);
129  return _Power * ((pow(det, _Power - 1) / a) - (a / pow(det, _Power + 1)));
130  }
131 
132 };
133 
134 
135 } // namespace mirtk
136 
137 #endif // MIRTK_NegJacobianConstraint_H
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
NegJacobianConstraint(const char *="", bool=true)
Constructor.
Penalise negative Jacobian determinant.
Definition: IOConfig.h:41
virtual ParameterList Parameter() const
Get parameter key/value as string map.
virtual ParameterList Parameter() const
Get parameter key/value as string map.
virtual double Penalty(double det) const
Evaluate penalty at control point location given Jacobian determinant value.
virtual bool SetWithPrefix(const char *, const char *)
Set parameter value from string.
virtual bool SetWithoutPrefix(const char *, const char *)
Set parameter value from string.
virtual double DerivativeWrtJacobianDet(double det) const
Evaluate derivative of penalty w.r.t. Jacobian determinant value.
virtual ~NegJacobianConstraint()
Destructor.