RegistrationEnergy.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_RegistrationEnergy_H
21 #define MIRTK_RegistrationEnergy_H
22 
23 #include "mirtk/ObjectiveFunction.h"
24 
25 #include "mirtk/Array.h"
26 #include "mirtk/EnergyTerm.h"
27 #include "mirtk/FastDelegate.h"
28 #include "mirtk/EventDelegate.h"
29 #include "mirtk/Transformation.h"
30 
31 
32 namespace mirtk {
33 
34 
35 /**
36  * Registration energy term which sums up the individual composite terms
37  */
39 {
40  mirtkObjectMacro(RegistrationEnergy);
41 
42  // ---------------------------------------------------------------------------
43  // Types
44 public:
45 
46  /// Type of pre-update function delegate
47  typedef FastDelegate1<bool> PreUpdateFunctionType;
48 
49 private:
50 
51  // ---------------------------------------------------------------------------
52  // Attributes
53 
54  /// Transformation with free parameters of energy function
55  mirtkPublicAggregateMacro(class Transformation, Transformation);
56 
57  /// Individual terms of registration energy function
58  Array<EnergyTerm *> _Term;
59 
60  /// Delegate of pre-update function, e.g., to update input to energy terms
61  mirtkPublicAttributeMacro(PreUpdateFunctionType, PreUpdateFunction);
62 
63  /// Whether to normalize each individually energy term gradient
64  ///
65  /// If this option is enabled, also the weights which determine the influence
66  /// of each energy term gradient are normalized by the sum of the weights.
67  /// Note that the weights used to weigh the contribution of the energy term
68  /// values themselves are not normalized, however, to allow more freedom in
69  /// adjusting the relative magnitude of each term.
70  ///
71  /// \attention The use of this option is experimental!
72  mirtkPublicAttributeMacro(bool, NormalizeGradients);
73 
74  /// Exclude values of transformation constraint from total energy value
75  ///
76  /// The gradient of the energy function always includes the gradient
77  /// of the transformation constraint terms which have non-zero weight.
78  /// When this option is enabled, the transformation constraints have
79  /// no direct influence on the stopping criteria.
80  mirtkPublicAttributeMacro(bool, ExcludeConstraints);
81 
82  /// Energy gradient preconditioning sigma used to supress noise.
83  /// A non-positive value disables the preconditioning all together.
84  ///
85  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
86  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
87  mirtkPublicAttributeMacro(double, Preconditioning);
88 
89  /// Forward events of energy terms to observers of the energy function
90  EventDelegate _EventDelegate;
91 
92  // ---------------------------------------------------------------------------
93  // Construction/Destruction
94 private:
95 
96  /// Copy constructor
97  /// \note Intentionally not implemented!
99 
100  /// Assignment operator
101  /// \note Intentionally not implemented!
102  RegistrationEnergy &operator =(const RegistrationEnergy &);
103 
104 public:
105 
106  /// Constructor
108 
109  /// Destructor
110  virtual ~RegistrationEnergy();
111 
112  // ---------------------------------------------------------------------------
113  // Energy terms
114 
115  /// Initialize energy terms once input and parameters have been set
116  virtual void Initialize();
117 
118  /// Delete previously added energy terms
119  void Clear();
120 
121  /// Whether energy function has no terms
122  bool Empty() const;
123 
124  /// Whether the n-th energy term has non-zero weight
125  bool IsActive(int) const;
126 
127  /// Whether the n-th energy term is a data term
128  bool IsDataTerm(int) const;
129 
130  /// Whether the n-th energy term is a penalty term
131  bool IsConstraint(int) const;
132 
133  /// Whether the n-th energy term is a sparsity term
134  bool IsSparsityConstraint(int) const;
135 
136  /// Number of energy terms
137  int NumberOfTerms() const;
138 
139  /// Number of energy terms with non-zero weight
140  int NumberOfActiveTerms() const;
141 
142  /// Number of data terms, i.e., with base type DataFidelity
143  int NumberOfDataTerms() const;
144 
145  /// Number of penalty terms, i.e., with base type TransformationConstraint
146  int NumberOfConstraints() const;
147 
148  /// Add energy term and take over ownership of the object
149  void Add(EnergyTerm *);
150 
151  /// Remove energy term and revoke ownership of the object
152  void Sub(EnergyTerm *);
153 
154  /// Get the n-th energy term
155  EnergyTerm *Term(int);
156 
157  // ---------------------------------------------------------------------------
158  // Settings
159 
160  // Import other overloads
162 
163  /// Set parameter value from string
164  virtual bool Set(const char *, const char *);
165 
166  /// Get parameter as key/value as string map
167  virtual ParameterList Parameter() const;
168 
169  // ---------------------------------------------------------------------------
170  // Function parameters
171 
172  /// Get number of transformation parameters
173  ///
174  /// \returns Number of transformation parameters (DoFs).
175  virtual int NumberOfDOFs() const;
176 
177  /// Set transformation parameters
178  ///
179  /// This function can be used to restore the transformation parameters after
180  /// a failed update which did not result in the desired improvement.
181  ///
182  /// \param[in] x Value of transformation parameters (DoFs).
183  virtual void Put(const double *x);
184 
185  /// Get transformation parameters
186  ///
187  /// This function can be used to store a backup of the current transformation
188  /// parameters before an update such that these can be restored using the Put
189  /// member function if the update did not result in the desired change of the
190  /// overall registration energy.
191  ///
192  /// \param[in] x Current values of transformation parameters (DoFs).
193  virtual void Get(double *x) const;
194 
195  /// Get function parameter value
196  ///
197  /// \returns Value of specified function parameter (DoF).
198  virtual double Get(int) const;
199 
200  /// Add change (i.e., scaled gradient) to each transformation parameter
201  ///
202  /// This function updates each parameter of the registration energy function
203  /// given a vector of desired changes, i.e., the computed gradient of the
204  /// energy function w.r.t. these parameters or a desired change computed
205  /// otherwise such as through matching patches (in a very loose sense an
206  /// approximate "gradient") or a discrete assignment (c.f. MRF registration).
207  /// It moreover triggers an update of the internal state of each energy term
208  /// which depends on the current transformation. A data similarity term,
209  /// for example, will update its moving (transformed) input data.
210  ///
211  /// \note How this change is applied to the transformation parameters depends
212  /// on the particular underlying transformation model. Often \p dx is
213  /// simply added to \c x, the current transformation parameters. Some
214  /// transformations may compute a slightly different update from \p dx,
215  /// however, such as converting displacements into velocities first.
216  ///
217  /// \param[in] dx Change of each function parameter (DoF) as computed by the
218  /// Gradient member function and scaled by a chosen step length.
219  ///
220  /// \returns Maximum change of transformation parameter.
221  virtual double Step(double *dx);
222 
223  /// Update internal state after change of parameters
224  virtual void Update(bool = true);
225 
226  /// Update energy function after convergence
227  ///
228  /// For example, fiducial registration error (FRE) terms may update the
229  /// point correspondences before another gradient-based optimization of
230  /// the new FRE term.
231  ///
232  /// \returns Whether the energy function has changed.
233  virtual bool Upgrade();
234 
235  // ---------------------------------------------------------------------------
236  // Evaluation
237 
238  /// Query/evaluate initial value of registration energy
239  double InitialValue();
240 
241  /// Get initial value of n-th energy term
242  double InitialValue(int);
243 
244  /// Evaluate registration energy
245  double Value();
246 
247  /// Get value of n-th energy term computed upon last evaluation
248  double Value(int);
249 
250  /// Normalize energy gradient
251  ///
252  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
253  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
254  void NormalizeGradient(double *dx);
255 
256  /// Evaluate data fidelity gradient of objective function w.r.t its DoFs
257  ///
258  /// \param[in] step Step length for finite differences.
259  /// \param[out] dx Data fidelity gradient of objective function.
260  /// \param[out] sgn_chg Whether function parameter value is allowed to
261  /// change sign when stepping along the computed gradient.
262  virtual void DataFidelityGradient(double *dx, double step = .0, bool *sgn_chg = nullptr);
263 
264  /// Add model constraint gradient of objective function w.r.t its DoFs
265  ///
266  /// \param[in] step Step length for finite differences.
267  /// \param[out] dx Gradient of objective function, e.g., either initialised to zero or
268  /// the data fidelity gradient computed beforehand using DataFidelityGradient.
269  /// \param[out] sgn_chg Whether function parameter value is allowed to
270  /// change sign when stepping along the computed gradient.
271  virtual void AddConstraintGradient(double *dx, double step = .0, bool *sgn_chg = nullptr);
272 
273  /// Evaluate gradient of registration energy
274  ///
275  /// Note that this gradient need not necessarily correspond to the analytic
276  /// gradient of the energy function. It can also be a desired change of each
277  /// function parameter computed otherwise such as through a local patch
278  /// match. The only requirement is that the change will increase the energy
279  /// function value such that successively walking in the direction of the
280  /// computed "gradient", a (local) maximum of the registration energy will be
281  /// be reached.
282  ///
283  /// \param[in] dx Gradient of registration energy function.
284  /// \param[in] step Step length for finite differences.
285  /// \param[out] sgn_chg Whether function parameter value is allowed to
286  /// change sign when stepping along the computed gradient.
287  void Gradient(double *dx, double step = .0, bool *sgn_chg = nullptr);
288 
289  /// Compute norm of gradient of registration energy
290  ///
291  /// This norm can, for example, be the maximum absolute parameter change or
292  /// the maximum control point displacement in case of a FFD transformation model.
293  double GradientNorm(const double *) const;
294 
295  /// Adjust step length range
296  ///
297  /// \param[in] dx Gradient of objective function.
298  /// \param[inout] min Minimum step length.
299  /// \param[inout] max Maximum step length.
300  void GradientStep(const double *dx, double &min, double &max) const;
301 
302  /// Evaluate registration energy
303  ///
304  /// This function first updates the internal state of the function object
305  /// if required due to a previous change of the function parameters and then
306  /// evaluates the current registration energy.
307  ///
308  /// \param[in] step Step length for finite differences.
309  /// \param[out] dx Gradient of objective function.
310  /// If \c NULL, only the function value is computed.
311  /// \param[out] sgn_chg Whether function parameter value is allowed to
312  /// change sign when stepping along the computed gradient.
313  /// Ignord if \p dx is \c NULL.
314  virtual double Evaluate(double *dx = NULL, double step = .0, bool *sgn_chg = NULL);
315 
316  // ---------------------------------------------------------------------------
317  // Debugging
318 
319  /// Get unweighted and unnormalized value of n-th energy term
320  /// \remarks Use for progress reporting only.
321  double RawValue(int);
322 
323  /// Write input of data fidelity terms
324  virtual void WriteDataSets(const char *, const char *, bool = true) const;
325 
326  /// Write gradient of data fidelity terms w.r.t each transformed input
327  virtual void WriteGradient(const char *, const char *) const;
328 
329 };
330 
331 // =============================================================================
332 // Inline definitions
333 // =============================================================================
334 
335 // -----------------------------------------------------------------------------
337 {
338  return static_cast<int>(_Term.size());
339 }
340 
341 
342 } // namespace mirtk
343 
344 #endif // MIRTK_RegistrationEnergy_H
virtual void WriteGradient(const char *, const char *) const
Write gradient of data fidelity terms w.r.t each transformed input.
bool Empty() const
Whether energy function has no terms.
int NumberOfActiveTerms() const
Number of energy terms with non-zero weight.
EnergyTerm * Term(int)
Get the n-th energy term.
void Add(EnergyTerm *)
Add energy term and take over ownership of the object.
virtual void DataFidelityGradient(double *dx, double step=.0, bool *sgn_chg=nullptr)
RegistrationEnergy()
Constructor.
virtual void Get(double *x) const
int NumberOfDataTerms() const
Number of data terms, i.e., with base type DataFidelity.
void Clear()
Delete previously added energy terms.
bool IsSparsityConstraint(int) const
Whether the n-th energy term is a sparsity term.
double GradientNorm(const double *) const
double InitialValue()
Query/evaluate initial value of registration energy.
virtual double Evaluate(double *dx=NULL, double step=.0, bool *sgn_chg=NULL)
virtual double Step(double *dx)
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
virtual ~RegistrationEnergy()
Destructor.
virtual bool Set(const char *, const char *)
Set parameter value from string.
virtual ParameterList Parameter() const
Get parameter as key/value as string map.
virtual void Update(bool=true)
Update internal state after change of parameters.
Definition: IOConfig.h:41
bool IsConstraint(int) const
Whether the n-th energy term is a penalty term.
virtual void WriteDataSets(const char *, const char *, bool=true) const
Write input of data fidelity terms.
void Gradient(double *dx, double step=.0, bool *sgn_chg=nullptr)
bool IsActive(int) const
Whether the n-th energy term has non-zero weight.
virtual void Initialize()
Initialize energy terms once input and parameters have been set.
double Value()
Evaluate registration energy.
virtual void AddConstraintGradient(double *dx, double step=.0, bool *sgn_chg=nullptr)
virtual int NumberOfDOFs() const
FastDelegate1< bool > PreUpdateFunctionType
Type of pre-update function delegate.
void GradientStep(const double *dx, double &min, double &max) const
int NumberOfTerms() const
Number of energy terms.
virtual ParameterList Parameter() const
Get parameter name/value pairs.
Definition: Object.h:139
void Sub(EnergyTerm *)
Remove energy term and revoke ownership of the object.
virtual void Put(const double *x)
int NumberOfConstraints() const
Number of penalty terms, i.e., with base type TransformationConstraint.
void NormalizeGradient(double *dx)
bool IsDataTerm(int) const
Whether the n-th energy term is a data term.