ImageGradientFunction.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_ImageGradientFunction_H
21 #define MIRTK_ImageGradientFunction_H
22 
23 #include "mirtk/Object.h"
24 #include "mirtk/Matrix.h"
25 #include "mirtk/Vector3D.h"
26 #include "mirtk/BaseImage.h"
27 #include "mirtk/InterpolationMode.h"
28 #include "mirtk/ExtrapolationMode.h"
29 #include "mirtk/ExtrapolateImageFunction.h"
30 
31 
32 namespace mirtk {
33 
34 
35 /**
36  * Abstract base class of image gradient functions
37  *
38  * An image gradient function applies the derivative of the interpolation
39  * kernel instead of the interpolation kernel itself to evaluate the image
40  * gradient at an arbitrary image location. It interpolates the 1st order
41  * image derivatives instead of the image intensity value. Note that it
42  * cannot be applied to multi-channel or vector-valued images.
43  */
45 {
46  mirtkAbstractMacro(ImageGradientFunction);
47 
48  // ---------------------------------------------------------------------------
49  // Types
50 
51 public:
52 
53  /// Type of interpolated gradient vectors
55 
56 private:
57 
58  // ---------------------------------------------------------------------------
59  // Data members
60 
61  /// Whether to evaluate image gradient w.r.t. world coordinate system
62  mirtkPublicAttributeMacro(bool, WrtWorld);
63 
64  /// Default value to return
65  mirtkPublicAttributeMacro(double, DefaultValue);
66 
67  /// Number of dimensions
68  ///
69  /// Determined either from input dimensions by default or set to a fixed
70  /// number of dimension by specialized subclasses.
71  mirtkPublicAttributeMacro(int, NumberOfDimensions);
72 
73 protected:
74 
75  /// Input image for filter
77 
78  /// Image resolution
79  GradientType _VoxelSize;
80 
81  /// Image orientation matrix
83 
84  /// Infinite discrete image obtained by extrapolation of finite input image.
85  /// Unused by default, i.e., NULL which corresponds to extrapolation mode
86  /// Extrapolation_None. If \c NULL, the interpolator has to deal with
87  /// boundary cases itself either by only partially interpolating the
88  /// available values or returning the _DefaultValue.
90 
91  /// Whether infinite discrete image was instantiated by this image function
93 
94  /// Domain of finite input image for which the image gradient is defined
95  /// without requiring any extrapolation: [x1, x2]x[y1, y2]x[z1, z2]x[t1, t2]
96  double _x1, _y1, _z1, _t1, _x2, _y2, _z2, _t2;
97 
98  // ---------------------------------------------------------------------------
99  // Auxiliary functions
100 
101  /// Orient and scale image gradient by world to image matrix
102  void ImageGradientToWorld(GradientType &) const;
103 
104  // ---------------------------------------------------------------------------
105  // Construction/Destruction
106 
107  /// Default constructor
109 
110 public:
111 
112  /// Destructor
113  virtual ~ImageGradientFunction();
114 
115  /// Construct image gradient function with default infinite extension of input image
116  static ImageGradientFunction *New(enum InterpolationMode, const BaseImage * = NULL);
117 
118  /// Construct extrapolator which is compatible with this image gradient function
119  virtual ExtrapolateImageFunction *New(enum ExtrapolationMode, const BaseImage * = NULL);
120 
121  /// Construct image gradient function with specified infinite extension of input image
122  ///
123  /// The caller is required to set the input, initialize, and destroy the
124  /// image gradient function only, the extrapolator is initialized and destroyed
125  /// by the image function unless the extrapolator has been replaced using the setter.
127  enum ExtrapolationMode,
128  const BaseImage * = NULL);
129 
130  // ---------------------------------------------------------------------------
131  // Initialization
132 
133  /// Set input image
134  virtual void Input(const BaseImage *);
135 
136  /// Get input image
137  const BaseImage *Input() const;
138 
139  /// Get interpolation mode corresponding to this image gradient function
140  virtual enum InterpolationMode InterpolationMode() const = 0;
141 
142  /// Get extrapolation mode used by this interpolator
144 
145  /// Set extrapolate image function for evaluation outside of image domain
146  virtual void Extrapolator(ExtrapolateImageFunction *, bool = false);
147 
148  /// Get extrapolate image function for evaluation outside of image domain
149  /// or \c NULL if extrapolation mode is \c Extrapolation_None
151 
152  /// Get extrapolate image function for evaluation outside of image domain
153  /// or \c NULL if extrapolation mode is \c Extrapolation_None
154  const ExtrapolateImageFunction *Extrapolator() const;
155 
156  /// Initialize image function
157  ///
158  /// \param[in] coeff Whether input image contains interpolation coefficients
159  /// already. Otherwise, the interpolate image function will
160  /// compute these coefficients from the input intensities.
161  virtual void Initialize(bool coeff = false);
162 
163  // ---------------------------------------------------------------------------
164  // Domain checks
165 
166  /// Get temporal origin of input image
167  double GetTOrigin() const;
168 
169  /// Convert world coordinates to image location (in pixels)
170  void WorldToImage(double &, double &) const;
171 
172  /// Convert world coordinates to image location (in pixels)
173  void WorldToImage(double &, double &, double &) const;
174 
175  /// Convert world coordinates to image location (in pixels)
176  void WorldToImage(Point &) const;
177 
178  /// Returns the image domain for which this image interpolation function
179  /// can be used without handling any form of boundary conditions
180  void Inside(double &, double &,
181  double &, double &) const;
182 
183  /// Returns the image domain for which this image interpolation function
184  /// can be used without handling any form of boundary conditions
185  void Inside(double &, double &, double &,
186  double &, double &, double &) const;
187 
188  /// Returns the image domain for which this image interpolation function
189  /// can be used without handling any form of boundary conditions
190  void Inside(double &, double &, double &, double &,
191  double &, double &, double &, double &) const;
192 
193  /// Returns interval of discrete image indices whose values are needed for
194  /// interpolation of the image value at a given continuous coordinate
195  virtual void BoundingInterval(double, int &, int &) const = 0;
196 
197  /// Returns discrete boundaries of local 2D image region needed for interpolation
198  virtual void BoundingBox(double, double, int &, int &,
199  int &, int &) const;
200 
201  /// Returns discrete boundaries of local 3D image region needed for interpolation
202  virtual void BoundingBox(double, double, double, int &, int &, int &,
203  int &, int &, int &) const;
204 
205  /// Returns discrete boundaries of local 4D image region needed for interpolation
206  virtual void BoundingBox(double, double, double, double,
207  int &, int &, int &, int &,
208  int &, int &, int &, int &) const;
209 
210  /// Check if the location (in pixels) is inside the domain for which this image
211  /// interpolation can be used without handling any form of boundary condition
212  bool IsInside(double, double) const;
213 
214  /// Check if the location (in pixels) is inside the domain for which this image
215  /// interpolation can be used without handling any form of boundary condition
216  bool IsInside(double, double, double) const;
217 
218  /// Check if the location (in pixels) is inside the domain for which this image
219  /// interpolation can be used without handling any form of boundary condition
220  bool IsInside(double, double, double, double) const;
221 
222  /// Check if the location (in pixels) is outside the domain for which this image
223  /// interpolation can be used without handling any form of boundary condition
224  bool IsOutside(double, double) const;
225 
226  /// Check if the location (in pixels) is outside the domain for which this image
227  /// interpolation can be used without handling any form of boundary condition
228  bool IsOutside(double, double, double) const;
229 
230  /// Check if the location (in pixels) is outside the domain for which this image
231  /// interpolation can be used without handling any form of boundary condition
232  bool IsOutside(double, double, double, double) const;
233 
234  /// Check if the location is fully inside the foreground of the image, i.e.,
235  /// including all discrete image locations required for interpolation
236  bool IsForeground(double, double) const;
237 
238  /// Check if the location is fully inside the foreground of the image, i.e.,
239  /// including all discrete image locations required for interpolation
240  bool IsForeground(double, double, double) const;
241 
242  /// Check if the location is fully inside the foreground of the image, i.e.,
243  /// including all discrete image locations required for interpolation
244  bool IsForeground(double, double, double, double) const;
245 
246  // ---------------------------------------------------------------------------
247  // Evaluation (C++ style return value, always w.r.t. image coordinates)
248 
249  /// Evaluate image gradient without handling boundary conditions
250  ///
251  /// This version is faster than GetOutside, but is only defined inside
252  /// the domain for which all image values required for interpolation are
253  /// defined and thus require no extrapolation of the finite image.
254  virtual GradientType GetInside(double, double, double = 0, double = 0) const = 0;
255 
256  /// Evaluate generic image gradient at an arbitrary location (in pixels)
257  virtual GradientType GetOutside(double, double, double = 0, double = 0) const = 0;
258 
259  /// Evaluate image gradient at an arbitrary location (in pixels)
260  ///
261  /// If the location is inside the domain for which the filter can perform
262  /// an interpolation without considering a particular boundary condition,
263  /// the faster GetInside method is called. Otherwise, the GetOutside method
264  /// which makes use of the extrapolation of the discrete image domain in
265  /// order to interpolate also at boundary or outside locations is used.
266  GradientType Get(double, double, double = 0, double = 0) const;
267 
268  /// Evaluate image gradient without handling boundary conditions
269  ///
270  /// If the location is partially inside the foreground region of the image,
271  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
272  /// is returned.
273  ///
274  /// This version is faster than GetWithPaddingOutside, but is only defined
275  /// inside the domain for which all image values required for interpolation
276  /// are defined and thus require no extrapolation of the finite image.
277  virtual GradientType GetWithPaddingInside(double, double, double = 0, double = 0) const = 0;
278 
279  /// Evaluate image gradient at an arbitrary location (in pixels)
280  ///
281  /// If the location is partially inside the foreground region of the image,
282  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
283  /// is returned.
284  virtual GradientType GetWithPaddingOutside(double, double, double = 0, double = 0) const = 0;
285 
286  /// Evaluate image gradient at an arbitrary location (in pixels)
287  ///
288  /// If the location is partially inside the foreground region of the image,
289  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
290  /// is returned.
291  GradientType GetWithPadding(double, double, double = 0, double = 0) const;
292 
293  /// Evaluate image gradient at an arbitrary location (in pixels)
294  GradientType operator ()(double, double, double = 0, double = 0) const;
295 
296  // ---------------------------------------------------------------------------
297  // Evaluation (C style return value)
298 
299  // Note: This interface is intentionally identical to the
300  // InterpolateImageFunction Evaluate* functions.
301 
302  /// Evaluate image gradient without handling boundary conditions
303  ///
304  /// This version is faster than EvaluateOutside, but is only defined inside
305  /// the domain for which all image values required for interpolation are
306  /// defined and thus require no extrapolation of the finite image.
307  ///
308  /// If \c _WrtWorld is \c true, the returned gradient vector is in
309  /// world units and oriented according to the image orientation.
310  virtual void EvaluateInside(double *, double, double, double = 0, int = 1) const;
311 
312  /// Evaluate image gradient at an arbitrary location (in pixels)
313  ///
314  /// If \c _WrtWorld is \c true, the returned gradient vector is in
315  /// world units and oriented according to the image orientation.
316  virtual void EvaluateOutside(double *, double, double, double = 0, int = 1) const;
317 
318  /// Evaluate image gradient at an arbitrary location (in pixels)
319  ///
320  /// If the location is inside the domain for which the filter can perform
321  /// an interpolation without considering a particular boundary condition,
322  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
323  /// method which makes use of the extrapolation of the discrete image domain
324  /// in order to interpolate also at boundary or outside locations is used.
325  ///
326  /// If \c _WrtWorld is \c true, the returned gradient vector is in
327  /// world units and oriented according to the image orientation.
328  void Evaluate(double *, double, double, double = 0, int = 1) const;
329 
330  /// Evaluate image gradient at an arbitrary location (in pixels)
331  ///
332  /// If the location is partially inside the foreground region of the image,
333  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
334  /// is returned.
335  ///
336  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
337  /// inside the domain for which all image values required for interpolation are
338  /// defined and thus require no extrapolation of the finite image.
339  ///
340  /// If \c _WrtWorld is \c true, the returned gradient vector is in
341  /// world units and oriented according to the image orientation.
342  virtual void EvaluateWithPaddingInside(double *, double, double, double = 0, int = 1) const;
343 
344  /// Evaluate image gradient at an arbitrary location (in pixels)
345  ///
346  /// If the location is partially inside the foreground region of the image,
347  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
348  /// is returned.
349  ///
350  /// If \c _WrtWorld is \c true, the returned gradient vector is in
351  /// world units and oriented according to the image orientation.
352  virtual void EvaluateWithPaddingOutside(double *, double, double, double = 0, int = 1) const;
353 
354  /// Evaluate image gradient at an arbitrary location (in pixels)
355  ///
356  /// If the location is partially inside the foreground region of the image,
357  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
358  /// is returned.
359  ///
360  /// If the location is inside the domain for which the filter can perform
361  /// an interpolation without considering a particular boundary condition,
362  /// the faster EvaluateWithPaddingInside method is called. Otherwise, the
363  /// EvaluateWithPaddingOutside method which makes use of the extrapolation
364  /// of the discrete image domain in order to interpolate also at boundary or
365  /// outside locations is used.
366  ///
367  /// If \c _WrtWorld is \c true, the returned gradient vector is in
368  /// world units and oriented according to the image orientation.
369  void EvaluateWithPadding(double *, double, double, double = 0, int = 1) const;
370 
371 };
372 
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 // Generic image gradient function interface
376 ////////////////////////////////////////////////////////////////////////////////
377 
378 /**
379  * Abstract base class of generic image gradient functions
380  *
381  * This image function interface is templated over the input image type and
382  * thus can access the image data using non-virtual getters which return
383  * the image values with the appropriate voxel type. Therefore, it is more
384  * efficient and type safe to use this image function interface whenever the
385  * image type is known. Otherwise, use the abstract ImageGradientFunction
386  * interface instead.
387  *
388  * \sa ImageGradientFunction
389  */
390 template <class TImage>
392 {
393  mirtkAbstractMacro(GenericImageGradientFunction);
394 
395 public:
396 
397  // ---------------------------------------------------------------------------
398  // Types
399 
400  typedef TImage ImageType;
401  typedef typename ImageType::VoxelType VoxelType;
402  typedef GradientType::ComponentType Real;
404 
405  // ---------------------------------------------------------------------------
406  // Construction/Destruction
407 
408 protected:
409 
410  /// Default constructor
412 
413 public:
414 
415  /// Destructor
416  virtual ~GenericImageGradientFunction();
417 
418  /// Construct interpolator with default infinite extension of input image
420  const TImage * = NULL);
421 
422  /// Construct extrapolator which is compatible with this interpolator
424  const BaseImage * = NULL);
425 
426  /// Construct interpolator with specified infinite extension of input image
427  ///
428  /// The caller is required to set the input, initialize, and destroy the
429  /// interpolator only, the extrapolator is initialized and destroyed by the
430  /// interpolator unless the extrapolator has been replaced using the setter.
432  enum ExtrapolationMode,
433  const TImage * = NULL);
434 
435  // ---------------------------------------------------------------------------
436  // Initialization
437 
438  /// Set input image
439  virtual void Input(const BaseImage *);
440 
441  /// Get input image
442  const ImageType *Input() const;
443 
444  /// Set extrapolate image function for evaluation outside of image domain
445  virtual void Extrapolator(ExtrapolateImageFunction *, bool = false);
446 
447  /// Get extrapolate image function for evaluation outside of image domain
448  /// or \c NULL if extrapolation mode is \c Extrapolation_None
449  ExtrapolatorType *Extrapolator();
450 
451  /// Get extrapolate image function for evaluation outside of image domain
452  /// or \c NULL if extrapolation mode is \c Extrapolation_None
453  const ExtrapolatorType *Extrapolator() const;
454 
455  /// Initialize image function
456  ///
457  /// \param[in] coeff Whether input image contains interpolation coefficients
458  /// already. Otherwise, the interpolate image function will
459  /// compute these coefficients from the input intensities.
460  virtual void Initialize(bool coeff = false);
461 
462 };
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 // Auxiliary macro for subclass implementation
466 ////////////////////////////////////////////////////////////////////////////////
467 
468 // -----------------------------------------------------------------------------
469 #define mirtkGradientInterpolatorMacro(clsname, mode) \
470  mirtkObjectMacro(clsname); \
471  public: \
472  /** Get interpolation mode implemented by this image gradient function */ \
473  inline virtual enum InterpolationMode InterpolationMode() const \
474  { return mode; } \
475  /** Get interpolation mode implemented by this class */ \
476  inline static enum InterpolationMode InterpolationType() \
477  { return mode; } \
478  private:
479 
480 // -----------------------------------------------------------------------------
481 #define mirtkGenericGradientInterpolatorTypes(superclsname) \
482  public: \
483  typedef superclsname<TImage> Superclass; \
484  typedef typename Superclass::ImageType ImageType; \
485  typedef typename Superclass::VoxelType VoxelType; \
486  typedef typename Superclass::Real Real; \
487  typedef typename Superclass::ExtrapolatorType ExtrapolatorType; \
488  typedef typename Superclass::GradientType GradientType; \
489  private:
490 
491 // -----------------------------------------------------------------------------
492 #define mirtkGenericGradientInterpolatorMacro(clsname, mode) \
493  mirtkGradientInterpolatorMacro(clsname, mode); \
494  mirtkGenericGradientInterpolatorTypes(GenericImageGradientFunction); \
495  private:
496 
497 ////////////////////////////////////////////////////////////////////////////////
498 // Inline definitions -- ImageGradientFunction
499 ////////////////////////////////////////////////////////////////////////////////
500 
501 // =============================================================================
502 // Auxiliary functions
503 // =============================================================================
504 
505 // -----------------------------------------------------------------------------
507 {
508  const GradientType v = g / _VoxelSize;
509  g._x = v._x * _Orientation(0, 0) + v._y * _Orientation(1, 0) + v._z * _Orientation(2, 0);
510  g._y = v._x * _Orientation(0, 1) + v._y * _Orientation(1, 1) + v._z * _Orientation(2, 1);
511  g._z = v._x * _Orientation(0, 2) + v._y * _Orientation(1, 2) + v._z * _Orientation(2, 2);
512 }
513 
514 // =============================================================================
515 // Initialization
516 // =============================================================================
517 
518 // -----------------------------------------------------------------------------
519 inline void ImageGradientFunction::Input(const BaseImage *input)
520 {
521  this->_Input = const_cast<BaseImage *>(input);
522 }
523 
524 // -----------------------------------------------------------------------------
526 {
527  return this->_Input;
528 }
529 
530 // -----------------------------------------------------------------------------
531 inline void ImageGradientFunction
533 {
535  _InfiniteInput = input;
537 }
538 
539 // -----------------------------------------------------------------------------
541 {
542  return _InfiniteInput;
543 }
544 
545 // -----------------------------------------------------------------------------
547 {
548  return _InfiniteInput;
549 }
550 
551 // -----------------------------------------------------------------------------
553 {
554  return (_InfiniteInput ? _InfiniteInput->ExtrapolationMode() : Extrapolation_None);
555 }
556 
557 // =============================================================================
558 // Domain checks
559 // =============================================================================
560 
561 // ----------------------------------------------------------------------------
563 {
564  return this->_Input->GetTOrigin();
565 }
566 
567 // ----------------------------------------------------------------------------
568 inline void ImageGradientFunction::WorldToImage(double &x, double &y) const
569 {
570  this->_Input->WorldToImage(x, y);
571 }
572 
573 // ----------------------------------------------------------------------------
574 inline void ImageGradientFunction::WorldToImage(double &x, double &y, double &z) const
575 {
576  this->_Input->WorldToImage(x, y, z);
577 }
578 
579 // ----------------------------------------------------------------------------
581 {
582  this->_Input->WorldToImage(p);
583 }
584 
585 // -----------------------------------------------------------------------------
586 inline void ImageGradientFunction::Inside(double &x1, double &y1,
587  double &x2, double &y2) const
588 {
589  x1 = _x1, y1 = _y1;
590  x2 = _x2, y2 = _y2;
591 }
592 
593 // -----------------------------------------------------------------------------
594 inline void ImageGradientFunction::Inside(double &x1, double &y1, double &z1,
595  double &x2, double &y2, double &z2) const
596 {
597  x1 = _x1, y1 = _y1, z1 = _z1;
598  x2 = _x2, y2 = _y2, z2 = _z2;
599 }
600 
601 // -----------------------------------------------------------------------------
602 inline void ImageGradientFunction::Inside(double &x1, double &y1, double &z1, double &t1,
603  double &x2, double &y2, double &z2, double &t2) const
604 {
605  x1 = _x1, y1 = _y1, z1 = _z1, t1 = _t1;
606  x2 = _x2, y2 = _y2, z2 = _z2, t2 = _t2;
607 }
608 
609 // -----------------------------------------------------------------------------
610 inline void ImageGradientFunction::BoundingBox(double x, double y,
611  int &i1, int &j1,
612  int &i2, int &j2) const
613 {
614  this->BoundingInterval(x, i1, i2);
615  this->BoundingInterval(y, j1, j2);
616 }
617 
618 // -----------------------------------------------------------------------------
619 inline void ImageGradientFunction::BoundingBox(double x, double y, double z,
620  int &i1, int &j1, int &k1,
621  int &i2, int &j2, int &k2) const
622 {
623  if (this->NumberOfDimensions() >= 3) {
624  this->BoundingInterval(x, i1, i2);
625  this->BoundingInterval(y, j1, j2);
626  this->BoundingInterval(z, k1, k2);
627  } else {
628  this->BoundingInterval(x, i1, i2);
629  this->BoundingInterval(y, j1, j2);
630  k1 = k2 = iround(z);
631  }
632 }
633 
634 // -----------------------------------------------------------------------------
635 inline void ImageGradientFunction::BoundingBox(double x, double y, double z, double t,
636  int &i1, int &j1, int &k1, int &l1,
637  int &i2, int &j2, int &k2, int &l2) const
638 {
639  if (this->NumberOfDimensions() >= 4) {
640  this->BoundingInterval(x, i1, i2);
641  this->BoundingInterval(y, j1, j2);
642  this->BoundingInterval(z, k1, k2);
643  this->BoundingInterval(t, l1, l2);
644  } else if (this->NumberOfDimensions() == 3) {
645  this->BoundingInterval(x, i1, i2);
646  this->BoundingInterval(y, j1, j2);
647  this->BoundingInterval(z, k1, k2);
648  l1 = l2 = iround(t);
649  } else {
650  this->BoundingInterval(x, i1, i2);
651  this->BoundingInterval(y, j1, j2);
652  k1 = k2 = iround(z);
653  l1 = l2 = iround(t);
654  }
655 }
656 
657 // -----------------------------------------------------------------------------
658 inline bool ImageGradientFunction::IsInside(double x, double y) const
659 {
660  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2);
661 }
662 
663 // -----------------------------------------------------------------------------
664 inline bool ImageGradientFunction::IsInside(double x, double y, double z) const
665 {
666  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2) && (_z1 <= z && z <= _z2);
667 }
668 
669 // -----------------------------------------------------------------------------
670 inline bool ImageGradientFunction::IsInside(double x, double y, double z, double t) const
671 {
672  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2) && (_z1 <= z && z <= _z2) && (_t1 <= t && t <= _t2);
673 }
674 
675 // -----------------------------------------------------------------------------
676 inline bool ImageGradientFunction::IsOutside(double x, double y) const
677 {
678  return !IsInside(x, y);
679 }
680 
681 // -----------------------------------------------------------------------------
682 inline bool ImageGradientFunction::IsOutside(double x, double y, double z) const
683 {
684  return !IsInside(x, y, z);
685 }
686 
687 // -----------------------------------------------------------------------------
688 inline bool ImageGradientFunction::IsOutside(double x, double y, double z, double t) const
689 {
690  return !IsInside(x, y, z, t);
691 }
692 
693 // -----------------------------------------------------------------------------
694 inline bool ImageGradientFunction::IsForeground(double x, double y) const
695 {
696  int i1, j1, i2, j2;
697  BoundingBox(x, y, i1, j1, i2, j2);
698  return Input()->IsBoundingBoxInsideForeground(i1, j1, i2, j2);
699 }
700 
701 // -----------------------------------------------------------------------------
702 inline bool ImageGradientFunction::IsForeground(double x, double y, double z) const
703 {
704  int i1, j1, k1, i2, j2, k2;
705  BoundingBox(x, y, z, i1, j1, k1, i2, j2, k2);
706  return Input()->IsBoundingBoxInsideForeground(i1, j1, k1, i2, j2, k2);
707 }
708 
709 // -----------------------------------------------------------------------------
710 inline bool ImageGradientFunction::IsForeground(double x, double y, double z, double t) const
711 {
712  int i1, j1, k1, l1, i2, j2, k2, l2;
713  BoundingBox(x, y, z, t, i1, j1, k1, l1, i2, j2, k2, l2);
714  return Input()->IsBoundingBoxInsideForeground(i1, j1, k1, l1, i2, j2, k2, l2);
715 }
716 
717 // =============================================================================
718 // Evaluation
719 // =============================================================================
720 
721 // -----------------------------------------------------------------------------
723 ImageGradientFunction::Get(double x, double y, double z, double t) const
724 {
725  if (IsInside(x, y, z, t)) return this->GetInside (x, y, z, t);
726  else return this->GetOutside(x, y, z, t);
727 }
728 
729 // -----------------------------------------------------------------------------
731 ImageGradientFunction::GetWithPadding(double x, double y, double z, double t) const
732 {
733  if (IsInside(x, y, z, t)) return this->GetWithPaddingInside (x, y, z, t);
734  else return this->GetWithPaddingOutside(x, y, z, t);
735 }
736 
737 // -----------------------------------------------------------------------------
739 ImageGradientFunction::operator ()(double x, double y, double z, double t) const
740 {
741  return this->Get(x, y, z, t);
742 }
743 
744 // -----------------------------------------------------------------------------
745 inline void
747 ::EvaluateInside(double *v, double x, double y, double z, int vt) const
748 {
749  GradientType g = this->GetInside(x, y, z, .0);
750  if (_WrtWorld) ImageGradientToWorld(g);
751  for (int i = 0; i < GradientType::Rows(); ++i, v += vt) *v = g(i);
752 }
753 
754 // -----------------------------------------------------------------------------
755 inline void
757 ::EvaluateOutside(double *v, double x, double y, double z, int vt) const
758 {
759  GradientType g = this->GetOutside(x, y, z, .0);
760  if (_WrtWorld) ImageGradientToWorld(g);
761  for (int i = 0; i < GradientType::Rows(); ++i, v += vt) *v = g(i);
762 }
763 
764 // -----------------------------------------------------------------------------
765 inline void
767 ::Evaluate(double *v, double x, double y, double z, int vt) const
768 {
769  if (IsInside(x, y, z)) return this->EvaluateInside (v, x, y, z, vt);
770  else return this->EvaluateOutside(v, x, y, z, vt);
771 }
772 
773 // -----------------------------------------------------------------------------
774 inline void
776 ::EvaluateWithPaddingInside(double *v, double x, double y, double z, int vt) const
777 {
778  GradientType g = this->GetWithPaddingInside(x, y, z, .0);
779  if (_WrtWorld) ImageGradientToWorld(g);
780  for (int i = 0; i < GradientType::Rows(); ++i, v += vt) *v = g(i);
781 }
782 
783 // -----------------------------------------------------------------------------
784 inline void
786 ::EvaluateWithPaddingOutside(double *v, double x, double y, double z, int vt) const
787 {
788  GradientType g = this->GetWithPaddingOutside(x, y, z, .0);
789  if (_WrtWorld) ImageGradientToWorld(g);
790  for (int i = 0; i < GradientType::Rows(); ++i, v += vt) *v = g(i);
791 }
792 
793 // -----------------------------------------------------------------------------
794 inline void
796 ::EvaluateWithPadding(double *v, double x, double y, double z, int vt) const
797 {
798  if (IsInside(x, y, z)) return this->EvaluateWithPaddingInside (v, x, y, z, vt);
799  else return this->EvaluateWithPaddingOutside(v, x, y, z, vt);
800 }
801 
802 ////////////////////////////////////////////////////////////////////////////////
803 // Inline definitions -- GenericImageGradientFunction
804 ////////////////////////////////////////////////////////////////////////////////
805 
806 // -----------------------------------------------------------------------------
807 template <class TImage>
809 {
810  return reinterpret_cast<const TImage *>(this->_Input);
811 }
812 
813 // -----------------------------------------------------------------------------
814 template <class TImage>
817 {
818  return reinterpret_cast<ExtrapolatorType *>(_InfiniteInput);
819 }
820 
821 // -----------------------------------------------------------------------------
822 template <class TImage>
825 {
826  return reinterpret_cast<const ExtrapolatorType *>(_InfiniteInput);
827 }
828 
829 
830 } // namespace mirtk
831 
832 #endif // MIRTK_ImageGradientFunction_H
bool IsOutside(double, double) const
virtual void EvaluateOutside(double *, double, double, double=0, int=1) const
bool IsBoundingBoxInsideForeground(int, int, int, int) const
Whether all voxels within a 2D bounding region are inside foreground region.
Definition: BaseImage.h:1563
const ImageType * Input() const
Get input image.
GradientType operator()(double, double, double=0, double=0) const
Evaluate image gradient at an arbitrary location (in pixels)
virtual ~ImageGradientFunction()
Destructor.
GradientType _VoxelSize
Image resolution.
void WorldToImage(double &, double &) const
World to image coordinate conversion with two doubles.
Definition: BaseImage.h:1212
virtual enum InterpolationMode InterpolationMode() const =0
Get interpolation mode corresponding to this image gradient function.
GradientType GetWithPadding(double, double, double=0, double=0) const
virtual void EvaluateWithPaddingOutside(double *, double, double, double=0, int=1) const
bool _InfiniteInputOwner
Whether infinite discrete image was instantiated by this image function.
virtual void BoundingInterval(double, int &, int &) const =0
void EvaluateWithPadding(double *, double, double, double=0, int=1) const
virtual GradientType GetInside(double, double, double=0, double=0) const =0
ExtrapolateImageFunction * Extrapolator()
virtual void BoundingBox(double, double, int &, int &, int &, int &) const
Returns discrete boundaries of local 2D image region needed for interpolation.
InterpolationMode
Image interpolation modes.
virtual enum ExtrapolationMode ExtrapolationMode() const =0
Get extrapolation mode corresponding to this extrapolator.
static ImageGradientFunction * New(enum InterpolationMode, const BaseImage *=NULL)
Construct image gradient function with default infinite extension of input image. ...
Definition: IOConfig.h:41
double GetTOrigin() const
Get temporal origin of input image.
void Evaluate(double *, double, double, double=0, int=1) const
bool IsInside(double, double) const
double GetTOrigin() const
Get temporal origin.
Definition: BaseImage.h:1082
enum ExtrapolationMode ExtrapolationMode() const
Get extrapolation mode used by this interpolator.
virtual GradientType GetWithPaddingInside(double, double, double=0, double=0) const =0
ImageGradientFunction()
Default constructor.
virtual void EvaluateWithPaddingInside(double *, double, double, double=0, int=1) const
void Inside(double &, double &, double &, double &) const
ExtrapolateImageFunction * _InfiniteInput
ExtrapolationMode
Image extrapolation modes.
void ImageGradientToWorld(GradientType &) const
Orient and scale image gradient by world to image matrix.
virtual void Initialize(bool coeff=false)
T _z
The z component.
Definition: Vector3D.h:60
static int Rows()
Number of vector components.
Definition: Vector3D.h:96
const BaseImage * Input() const
Get input image.
T _y
The y component.
Definition: Vector3D.h:59
bool IsForeground(double, double) const
virtual void EvaluateInside(double *, double, double, double=0, int=1) const
virtual GradientType GetOutside(double, double, double=0, double=0) const =0
Evaluate generic image gradient at an arbitrary location (in pixels)
virtual GradientType GetWithPaddingOutside(double, double, double=0, double=0) const =0
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
Definition: Math.h:170
GradientType Get(double, double, double=0, double=0) const
Matrix _Orientation
Image orientation matrix.
T _x
The x component.
Definition: Vector3D.h:58
BaseImage * _Input
Input image for filter.
void WorldToImage(double &, double &) const
Convert world coordinates to image location (in pixels)
Vector3D< double > GradientType
Type of interpolated gradient vectors.