ImageSimilarity.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2017 Imperial College London
5  * Copyright 2013-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_ImageSimilarity_H
21 #define MIRTK_ImageSimilarity_H
22 
23 #include "mirtk/DataFidelity.h"
24 #include "mirtk/SimilarityMeasure.h"
25 #include "mirtk/Parallel.h"
26 #include "mirtk/FreeFormTransformation.h"
27 #include "mirtk/RegisteredImage.h"
28 
29 
30 namespace mirtk {
31 
32 
33 /**
34  * Base class for image similarity measures
35  *
36  * The lower the value of the similarity measure, the more similar the images are.
37  * It may therefore more precisely be referred to as dissimilarity measure, but
38  * both terms are for historic reasons used interchangeably in this framework.
39  *
40  * If the transformed image has a foreground region defined, we assume that this
41  * corresponds to the region which needs to be matched with the untransformed
42  * image. Therefore we make use of the entire transformed foreground region to
43  * evaluate similarity and in particular the gradient forces defined within
44  * this region. Note that outside this source foreground region, the gradient
45  * is always zero and thus cannot be used to drive the image registration.
46  *
47  * Otherwise, the region of interest is generally defined by the foreground of
48  * the untransformed image. For each such target voxel we want to find a suitable
49  * corresponding voxel in the other image. Therefore, we restrict the similarity
50  * evaluation to this region. In case of a symmetric transformation of both
51  * images, the union of the foreground of both images defines the region for
52  * which similarity is evaluated and forces are computed.
53  *
54  * Subclasses which implement a particular similarity measure should call
55  * the IsForeground member function to decide whether or not to consider
56  * a given voxel of the grid on which the registered images are defined.
57  *
58  * \note The similarity measure owns the registered input images and may thus
59  * modify these to improve the runtime of each Update step.
60  */
62 {
63  mirtkAbstractMacro(ImageSimilarity);
64 
65  // ---------------------------------------------------------------------------
66  // Types
67 public:
68 
69  /// Voxel type of registered images
71 
72  /// Type of similarity gradient components
73  typedef double GradientType;
74 
75  /// Type of similarity gradient image
77 
78  /// Enumeration of available set operations to define region within which
79  /// to evaluate the image similarity given the two foreground regions of
80  /// the two co-registered input images. The resulting foreground region
81  /// is further intersected with the specified binary mask. When no mask
82  /// is given, a mask with constant value 1 is assumed.
84  {
85  FG_Domain, ///< Evaluate similarity for all voxels in image domain, ignore mask
86  FG_Mask, ///< Evaluate similarity for all voxels in domain or with non-zero mask value
87  FG_Target, ///< Evaluate similarity for foreground of untransformed image
88  FG_Overlap, ///< Evaluate similarity for intersection of foreground regions
89  FG_Union ///< Evaluate similarity for union of foreground regions
90  };
91 
92  // ---------------------------------------------------------------------------
93  // Attributes
94 
95  /// (Transformed) Target image
97 
98  /// (Transformed) Source image
100 
101  /// Finite regular domain on which to resample images and evaluate similarity
103 
104  /// Set operation used to define common foreground region of co-registered images
106 
107  /// Mask which defines arbitrary domain on which the similarity is evaluated
108  ///
109  /// Intensities outside the mask (i.e., mask value is zero) are excluded from
110  /// the similarity comparison. The foreground domain of the registered image
111  /// is the intersection of the domain defined by non-zero mask entries with
112  /// the foreground domain used when no mask is set.
114 
115  /// Memory for (non-parametric) similarity gradient w.r.t target transformation
116  mirtkComponentMacro(GradientImageType, GradientWrtTarget);
117 
118  /// Memory for (non-parametric) similarity gradient w.r.t source transformation
119  mirtkComponentMacro(GradientImageType, GradientWrtSource);
120 
121  /// Memory for (parametric) similarity gradient
122  mirtkComponentMacro(double, Gradient);
123 
124  /// Number of voxels per registered image
125  mirtkPublicAttributeMacro(int, NumberOfVoxels);
126 
127  /// Divide transformed image gradient by input intensity range
128  mirtkPublicAttributeMacro(bool, NormalizeImageGradient);
129 
130  /// Approximate gradient using finite differences even if the similarity
131  /// measure implements the NonParametricGradient function
132  mirtkPublicAttributeMacro(bool, UseApproximateGradient);
133 
134  /// Voxel-wise gradient preconditioning sigma used to supress noise.
135  /// A non-positive value disables the voxel-wise preconditioning all together.
136  ///
137  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
138  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
139  mirtkPublicAttributeMacro(double, VoxelWisePreconditioning);
140 
141  /// Node-based (M)FFD control point gradient preconditioning sigma used to
142  /// supress noise. A non-positive value disables the node-based
143  /// preconditioning all together.
144  ///
145  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
146  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
147  mirtkPublicAttributeMacro(double, NodeBasedPreconditioning);
148 
149  /// Skip initialization of target image
150  mirtkPublicAttributeMacro(bool, SkipTargetInitialization);
151 
152  /// Skip initialization of source image
153  mirtkPublicAttributeMacro(bool, SkipSourceInitialization);
154 
155  /// Whether Update has not been called since initialization
156  mirtkAttributeMacro(bool, InitialUpdate);
157 
158  /// Copy attributes of this class from another instance
159  void CopyAttributes(const ImageSimilarity &);
160 
161  // ---------------------------------------------------------------------------
162  // Construction/Destruction
163 protected:
164 
165  /// Constructor
166  ImageSimilarity(const char * = "", double = 1.0);
167 
168  /// Copy constructor
170 
171  /// Assignment operator
173 
174 public:
175 
176  /// Instantiate specified similarity measure
178  const char * = "", double = 1.0);
179 
180  /// Destructor
181  virtual ~ImageSimilarity();
182 
183  // ---------------------------------------------------------------------------
184  // Initialization
185 
186 protected:
187 
188  /// Initialize similarity measure once input and parameters have been set
189  /// \param[in] domain Image domain on which the similarity is evaluated.
190  virtual void InitializeInput(const ImageAttributes &domain);
191 
192 public:
193 
194  /// Initialize similarity measure once input and parameters have been set
195  virtual void Initialize();
196 
197  /// Release input target image
198  void ReleaseTarget();
199 
200  /// Release input source image
201  void ReleaseSource();
202 
203  // ---------------------------------------------------------------------------
204  // Parameters
205 protected:
206 
207  /// Set parameter value from string
208  virtual bool SetWithoutPrefix(const char *, const char *);
209 
210 public:
211 
212  // Import other overloads
214 
215  /// Get parameter key/value as string map
216  virtual ParameterList Parameter() const;
217 
218  // ---------------------------------------------------------------------------
219  // Evaluation
220 
221  /// Update moving input image(s) and internal state of similarity measure
222  virtual void Update(bool = true);
223 
224  /// Whether to evaluate similarity at specified voxel
225  bool IsForeground(int) const;
226 
227  /// Whether to evaluate similarity at specified voxel
228  bool IsForeground(int, int, int) const;
229 
230  /// Exclude region from similarity evaluation
231  ///
232  /// Called by ApproximateGradient \b before the registered image region of
233  /// the transformed image is updated.
234  ///
235  /// Override in subclass for more efficient ApproximateGradient evaluation
236  /// If the analytic derivation is possible and thus the NonParametericGradient
237  /// function is overriden instead, this function is not used. Otherwise,
238  /// if this function is not overriden to update the similarity measure,
239  /// the Evaluate function must re-evaluate the similarity for all voxels.
240  ///
241  /// \sa ApproximateGradient, Include
242  virtual void Exclude(const blocked_range3d<int> &);
243 
244  /// Include region in similarity evaluation
245  ///
246  /// Called by ApproximateGradient \b after the registered image region of
247  /// the transformed image is updated.
248  ///
249  /// Override in subclass for more efficient ApproximateGradient evaluation
250  /// If the analytic derivation is possible and thus the NonParametericGradient
251  /// function is overriden instead, this function is not used. Otherwise,
252  /// if this function is not overriden to update the similarity measure,
253  /// the Evaluate function must re-evaluate the similarity for all voxels.
254  ///
255  /// \sa ApproximateGradient, Exclude
256  virtual void Include(const blocked_range3d<int> &);
257 
258 protected:
259 
260  /// Multiply voxel-wise similarity gradient by transformed image gradient
261  ///
262  /// This function is intended for use by subclass implementations to compute
263  /// the NonParametericGradient. It applies the chain rule to compute
264  /// \f$\frac{dSimilarity}{dy} = \frac{dSimilarity}{dI} * \frac{dI}{dy}\f$, given
265  /// \f$\frac{dSimilarity}{dI}\f$ as input, where \f$y = T(x)\f$.
266  ///
267  /// \param[in] image Transformed image.
268  /// \param[in,out] gradient Input must be the gradient of the image similarity
269  /// w.r.t. the transformed \p image in x. Output is the
270  /// voxel-wise gradient of the similarity w.r.t. T(x).
271  void MultiplyByImageGradient(const RegisteredImage *image,
272  GradientImageType *gradient);
273 
274  /// Compute voxel-wise non-parametric similarity gradient w.r.t the given image
275  ///
276  /// Must be implemented by subclasses to compute the similarity gradient.
277  /// The base class implementation can be used to convert the similarity gradient
278  /// computed w.r.t transformed image (i.e., dSimilarity/dI) to a voxel-wise
279  /// non-parametric gradient (i.e., dSimilarity/dT). Note that the input must
280  /// be a scalar field only. The base class copies the x component of the input
281  /// gradient image to the y and z components before applying the chain rule.
282  ///
283  /// \param[in] image Transformed image
284  /// \param[out] gradient Non-parametric similarity gradient.
285  ///
286  /// \returns Whether voxel-wise similarity gradient has been computed.
287  virtual bool NonParametricGradient(const RegisteredImage *image,
288  GradientImageType *gradient);
289 
290  /// Normalize voxel-wise non-parametric similarity gradient
291  ///
292  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
293  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
294  ///
295  /// \param[inout] gradient Non-parametric similarity gradient.
296  virtual void NormalizeGradient(GradientImageType *gradient);
297 
298  /// Convert non-parametric similarity gradient into gradient
299  /// w.r.t transformation parameters
300  ///
301  /// This function calls Transformation::ParametricGradient of the
302  /// transformation to apply the chain rule in order to obtain the similarity
303  /// gradient w.r.t the transformation parameters. It adds the weighted gradient
304  /// to the final registration energy gradient.
305  ///
306  /// \param[in] image Transformed image.
307  /// \param[in] np_gradient Voxel-wise non-parametric gradient.
308  /// \param[inout] gradient Gradient to which the computed parametric gradient
309  /// is added, after multiplication by the given \p weight.
310  /// \param[in] weight Weight of image similarity.
311  virtual void ParametricGradient(const RegisteredImage *image,
312  GradientImageType *np_gradient,
313  double *gradient,
314  double weight);
315 
316  /// Approximate similarity gradient using finite differences
317  ///
318  /// If the image similarity does not provide an implementation of the
319  /// NonParametricGradient function, the similarity gradient is
320  /// approximated instead using finite differences.
321  ///
322  /// \param[in] image Transformed image.
323  /// \param[in] ffd Free-form deformation.
324  /// \param[in,out] gradient Gradient to which the computed parametric gradient
325  /// is added, after multiplication by the given \p weight.
326  /// \param[in] step Step size to use for finite differences.
327  /// \param[in] weight Weight of image similarity.
330  double *gradient,
331  double step,
332  double weight);
333 
334  /// Approximate similarity gradient using finite differences
335  ///
336  /// If the image similarity does not provide an implementation of the
337  /// NonParametricGradient function, the similarity gradient is
338  /// approximated instead using finite differences.
339  ///
340  /// \param[in] image Transformed image.
341  /// \param[in,out] gradient Gradient to which the computed parametric gradient
342  /// is added, after multiplication by the given \p weight.
343  /// \param[in] step Step size to use for finite differences.
344  /// \param[in] weight Weight of image similarity.
346  double *gradient,
347  double step,
348  double weight);
349 
350  /// Normalize node-based similarity gradient
351  ///
352  /// Zikic, D., Baust, M., Kamen, A., & Navab, N. A General Preconditioning
353  /// Scheme for Difference Measures in Deformable Registration. In ICCV 2011.
354  ///
355  /// This function applies the normalization for FFD transformations to the
356  /// gradient vectors of the control point coefficients. It does nothing for
357  /// non-FFD transformations. In case of a multi-level FFD with more than one
358  /// active level, it furthermore normalizes the gradient vectors across levels.
359  ///
360  /// \param[in] image Transformed image.
361  /// \param[in,out] gradient Parametric similarity gradient.
362  virtual void NormalizeGradient(const RegisteredImage *image, double *gradient);
363 
364  /// Evaluate similarity gradient
365  ///
366  /// This function calls the virtual NonParametricGradient function to be
367  /// implemented by subclasses for each transformed input image to obtain
368  /// the voxel-wise similarity gradient. It then converts this gradient into
369  /// a gradient w.r.t the transformation parameters using the ParametricGradient.
370  ///
371  /// If both target and source are transformed by different transformations,
372  /// the resulting gradient vector contains first the derivative values w.r.t
373  /// the parameters of the target transformation followed by those computed
374  /// w.r.t the parameters of the source transformation. If both images are
375  /// transformed by the same transformation, the sum of the derivative values
376  /// is added to the resulting gradient vector. This is in particular the case
377  /// for a velocity based transformation model which is applied to deform both
378  /// images "mid-way". Otherwise, only one input image is transformed
379  /// (usually the source) and the derivative values of only the respective
380  /// transformation parameters added to the gradient vector.
381  ///
382  /// \sa NonParametricGradient, ParametricGradient
383  ///
384  /// \param[in] image Transformed image.
385  /// \param[in,out] np_gradient Memory for voxel-wise non-parametric gradient.
386  /// \param[in,out] gradient Gradient to which the computed gradient of the
387  /// image similarity is added after multiplying by
388  /// the given similarity \p weight.
389  /// \param[in] step Step size to use for finite differences.
390  /// \param[in] weight Weight of image similarity.
391  virtual void EvaluateGradient(RegisteredImage *image,
392  GradientImageType *&np_gradient,
393  double *gradient,
394  double step, double weight);
395 
396  /// Evaluate similarity gradient
397  ///
398  /// This function calls the virtual NonParametricGradient function to be
399  /// implemented by subclasses for each transformed input image to obtain
400  /// the voxel-wise similarity gradient. It then converts this gradient into
401  /// a gradient w.r.t the transformation parameters using the ParametricGradient.
402  ///
403  /// If both target and source are transformed by different transformations,
404  /// the resulting gradient vector contains first the derivative values w.r.t
405  /// the parameters of the target transformation followed by those computed
406  /// w.r.t the parameters of the source transformation. If both images are
407  /// transformed by the same transformation, the sum of the derivative values
408  /// is added to the resulting gradient vector. This is in particular the case
409  /// for a velocity based transformation model which is applied to deform both
410  /// images "mid-way". Otherwise, only one input image is transformed
411  /// (usually the source) and the derivative values of only the respective
412  /// transformation parameters added to the gradient vector.
413  ///
414  /// \sa NonParametricGradient, ParametricGradient
415  ///
416  /// \param[in,out] gradient Gradient to which the computed gradient of the
417  /// image similarity is added after multiplying by
418  /// the given similarity \p weight.
419  /// \param[in] step Step size to use for finite differences.
420  /// \param[in] weight Weight of image similarity.
421  virtual void EvaluateGradient(double *gradient, double step, double weight);
422 
423  // ---------------------------------------------------------------------------
424  // Debugging
425 
426 public:
427 
428  /// Print debug information
429  virtual void Print(Indent = 0) const;
430 
431  /// Write input of data fidelity term
432  virtual void WriteDataSets(const char *, const char *, bool = true) const;
433 
434  /// Write gradient of data fidelity term w.r.t each transformed input
435  virtual void WriteGradient(const char *, const char *) const;
436 
437 };
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 // Inline definitions
441 ////////////////////////////////////////////////////////////////////////////////
442 
443 // ----------------------------------------------------------------------------
444 template <>
445 inline string ToString(const ImageSimilarity::ForegroundRegion &value, int w, char c, bool left)
446 {
447  const char *str;
448  switch (value) {
449  case ImageSimilarity::FG_Domain: str = "Domain"; break;
450  case ImageSimilarity::FG_Mask: str = "Mask"; break;
451  case ImageSimilarity::FG_Target: str = "Target"; break;
452  case ImageSimilarity::FG_Overlap: str = "Overlap"; break;
453  case ImageSimilarity::FG_Union: str = "Union"; break;
454  default: str = "Unknown"; break;
455  }
456  return ToString(str, w, c, left);
457 }
458 
459 // ----------------------------------------------------------------------------
460 template <>
461 inline bool FromString(const char *str, ImageSimilarity::ForegroundRegion &value)
462 {
463  string lstr = ToLower(str);
464  if (lstr == "domain" || lstr == "including background" || lstr == "incl. background") {
466  } else if (lstr == "mask") {
467  value = ImageSimilarity::FG_Mask;
468  } else if (lstr == "target" || lstr == "target foreground" || lstr == "excluding target background" || lstr == "excl. target background") {
470  } else if (lstr == "overlap" || lstr == "intersection" || lstr == "excluding background" || lstr == "excl. background") {
472  } else if (lstr == "union") {
474  } else {
475  return false;
476  }
477  return true;
478 }
479 
480 // -----------------------------------------------------------------------------
481 inline bool ImageSimilarity::IsForeground(int idx) const
482 {
483  if (_Foreground == FG_Domain || !_Mask || _Mask->Get(idx)) {
484  switch (_Foreground) {
485  case FG_Domain: case FG_Mask:
486  return true;
487  case FG_Target:
488  if ((_Source->Transformation() == nullptr) != (_Target->Transformation() == nullptr)) {
489  // Either both or none of the images is being tranformed
490  return _Source->IsForeground(idx) || _Target->IsForeground(idx);
491  }
492  // Only one of the image is being transformed
493  if (_Target->Transformation()) return _Source->IsForeground(idx);
494  else return _Target->IsForeground(idx);
495  case FG_Overlap:
496  return _Source->IsForeground(idx) && _Target->IsForeground(idx);
497  case FG_Union:
498  return _Source->IsForeground(idx) || _Target->IsForeground(idx);
499  };
500  }
501  // Never evaluate similarity outside explicitly specified domain
502  return false;
503 }
504 
505 // -----------------------------------------------------------------------------
506 inline bool ImageSimilarity::IsForeground(int i, int j, int k) const
507 {
508  return IsForeground(_Domain.LatticeToIndex(i, j, k));
509 }
510 
511 
512 } // namespace mirtk
513 
514 #endif // MIRTK_ImageSimilarity_H
mirtkPublicAttributeMacro(ImageAttributes, Domain)
Finite regular domain on which to resample images and evaluate similarity.
virtual void Update(bool=true)
Update moving input image(s) and internal state of similarity measure.
Evaluate similarity for union of foreground regions.
void MultiplyByImageGradient(const RegisteredImage *image, GradientImageType *gradient)
virtual void EvaluateGradient(RegisteredImage *image, GradientImageType *&np_gradient, double *gradient, double step, double weight)
mirtkAttributeMacro(bool, InitialUpdate)
Whether Update has not been called since initialization.
RegisteredImage::VoxelType VoxelType
Voxel type of registered images.
virtual void Print(Indent=0) const
Print debug information.
virtual void Include(const blocked_range3d< int > &)
void CopyAttributes(const ImageSimilarity &)
Copy attributes of this class from another instance.
mirtkLooseComponentMacro(RegisteredImage, Target)
(Transformed) Target image
double GradientType
Type of similarity gradient components.
ImageSimilarity & operator=(const ImageSimilarity &)
Assignment operator.
void ReleaseSource()
Release input source image.
virtual void InitializeInput(const ImageAttributes &domain)
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
virtual bool NonParametricGradient(const RegisteredImage *image, GradientImageType *gradient)
bool IsForeground(int) const
Whether to evaluate similarity at specified voxel.
void ReleaseTarget()
Release input target image.
virtual ParameterList Parameter() const
Get parameter key/value as string map.
string ToLower(const string &)
Convert string to lowercase letters.
Definition: IOConfig.h:41
Evaluate similarity for all voxels in domain or with non-zero mask value.
virtual void NormalizeGradient(GradientImageType *gradient)
virtual bool SetWithoutPrefix(const char *, const char *)
Set parameter value from string.
mirtkComponentMacro(GradientImageType, GradientWrtTarget)
Memory for (non-parametric) similarity gradient w.r.t target transformation.
virtual ParameterList Parameter() const
Get parameter key/value as string map.
ImageSimilarity(const char *="", double=1.0)
Constructor.
virtual void Initialize()
Initialize similarity measure once input and parameters have been set.
virtual void ParametricGradient(const RegisteredImage *image, GradientImageType *np_gradient, double *gradient, double weight)
Evaluate similarity for foreground of untransformed image.
Three-dimensional range.
Definition: Parallel.h:197
void ApproximateGradient(RegisteredImage *image, FreeFormTransformation *ffd, double *gradient, double step, double weight)
double VoxelType
Definition: BaseImage.h:770
string ToString(const EnergyMeasure &value, int w, char c, bool left)
Convert energy measure enumeration value to string.
Evaluate similarity for intersection of foreground regions.
bool FromString(const char *str, EnergyMeasure &value)
Convert energy measure string to enumeration value.
virtual void WriteDataSets(const char *, const char *, bool=true) const
Write input of data fidelity term.
GenericImage< GradientType > GradientImageType
Type of similarity gradient image.
virtual void Exclude(const blocked_range3d< int > &)
static ImageSimilarity * New(SimilarityMeasure, const char *="", double=1.0)
Instantiate specified similarity measure.
mirtkPublicAggregateMacro(BinaryImage, Mask)
virtual void WriteGradient(const char *, const char *) const
Write gradient of data fidelity term w.r.t each transformed input.
void Gradient(double *gradient, double step)
virtual ~ImageSimilarity()
Destructor.
Evaluate similarity for all voxels in image domain, ignore mask.