InterpolateImageFunction.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_InterpolateImageFunction_H
21 #define MIRTK_InterpolateImageFunction_H
22 
23 #include "mirtk/InterpolationMode.h"
24 #include "mirtk/Point.h"
25 #include "mirtk/Vector.h"
26 #include "mirtk/Voxel.h"
27 #include "mirtk/VoxelCast.h"
28 #include "mirtk/BaseImage.h"
29 #include "mirtk/GenericImage.h"
30 #include "mirtk/ImageFunction.h"
31 #include "mirtk/UnaryVoxelFunction.h"
32 
33 #include "mirtk/ExtrapolateImageFunction.h"
34 
35 
36 namespace mirtk {
37 
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 // Abstract interpolation interface
41 ////////////////////////////////////////////////////////////////////////////////
42 
43 /**
44  * Abstract base class for any general image interpolation function
45  */
47 {
48  mirtkAbstractMacro(InterpolateImageFunction);
49 
50  // ---------------------------------------------------------------------------
51  // Data members
52 
53  /// Number of dimensions to interpolate
54  ///
55  /// Determined either from input dimensions by default or set to a fixed
56  /// number of dimension by specialized subclasses.
57  mirtkPublicAttributeMacro(int, NumberOfDimensions);
58 
59 protected:
60 
61  /// Infinite discrete image obtained by extrapolation of finite input image.
62  /// Unused by default, i.e., NULL which corresponds to extrapolation mode
63  /// Extrapolation_None. If \c NULL, the interpolator has to deal with
64  /// boundary cases itself either by only partially interpolating the
65  /// available values or returning the _DefaultValue.
67 
68  /// Whether infinite discrete image was instantiated by this image function
70 
71  /// Domain of finite input image for which the interpolation is defined
72  /// without requiring any extrapolation: [x1, x2]x[y1, y2]x[z1, z2]x[t1, t2]
73  double _x1, _y1, _z1, _t1, _x2, _y2, _z2, _t2;
74 
75  // ---------------------------------------------------------------------------
76  // Construction/Destruction
77 
78  /// Default constructor
80 
81 public:
82 
83  /// Destructor
84  virtual ~InterpolateImageFunction();
85 
86  /// Construct interpolator with default infinite extension of input image
87  static InterpolateImageFunction *New(enum InterpolationMode = Interpolation_Default,
88  const BaseImage * = NULL);
89 
90  /// Construct extrapolator which is compatible with this interpolator
92  const BaseImage * = NULL);
93 
94  /// Construct interpolator with specified infinite extension of input image
95  ///
96  /// The caller is required to set the input, initialize, and destroy the
97  /// interpolator only, the extrapolator is initialized and destroyed by the
98  /// interpolator unless the extrapolator has been replaced using the setter.
100  enum ExtrapolationMode, const BaseImage * = NULL);
101 
102  // ---------------------------------------------------------------------------
103  // Initialization
104 
105  /// Set input image
106  void Input(const BaseImage *);
107 
108  /// Get input image
109  const BaseImage *Input() const;
110 
111  /// Get interpolation mode corresponding to this interpolator
112  virtual enum InterpolationMode InterpolationMode() const = 0;
113 
114  /// Get extrapolation mode used by this interpolator
116 
117  /// Set extrapolate image function for evaluation outside of image domain
118  virtual void Extrapolator(ExtrapolateImageFunction *, bool = false);
119 
120  /// Get extrapolate image function for evaluation outside of image domain
121  /// or \c NULL if extrapolation mode is \c Extrapolation_None
123 
124  /// Get extrapolate image function for evaluation outside of image domain
125  /// or \c NULL if extrapolation mode is \c Extrapolation_None
126  const ExtrapolateImageFunction *Extrapolator() const;
127 
128  /// Initialize image function
129  ///
130  /// \note Override the virtual Initialize(bool) member function in subclasses,
131  /// but not this member function which is required by the abstract
132  /// image function interface (irtkImageFunction::Initialize).
133  virtual void Initialize();
134 
135  /// Initialize image function
136  ///
137  /// \param[in] coeff Whether input image contains interpolation coefficients
138  /// already. Otherwise, the interpolate image function will
139  /// compute these coefficients from the input intensities.
140  virtual void Initialize(bool coeff);
141 
142  /// Update internal state when input image content has changed
143  ///
144  /// When the attributes of the input have changed, call Initialize instead.
145  /// This function is used for example by B-spline based interpolation functions
146  /// to re-compute the spline coefficients that interpolate the input image.
147  virtual void Update();
148 
149  // ---------------------------------------------------------------------------
150  // Lattice
151 
152  /// Lattice attributes
153  const ImageAttributes &Attributes() const;
154 
155  /// Image size along x axis
156  int X() const;
157 
158  /// Image size along y axis
159  int Y() const;
160 
161  /// Image size along z axis
162  int Z() const;
163 
164  /// Image size along t axis
165  int T() const;
166 
167  /// Image spacing along x axis
168  double XSize() const;
169 
170  /// Image spacing along y axis
171  double YSize() const;
172 
173  /// Image spacing along z axis
174  double ZSize() const;
175 
176  /// Image spacing along t axis
177  double TSize() const;
178 
179  /// Convert world coordinates (in mm) to image location (in pixels)
180  void WorldToImage(double &, double &) const;
181 
182  /// Convert world coordinates (in mm) to image location (in pixels)
183  void WorldToImage(double &, double &, double &) const;
184 
185  /// Convert world coordinates (in mm) to image location (in pixels)
186  void WorldToImage(Point &) const;
187 
188  /// Convert world coordinates vector (in mm) to image vector (in pixels)
189  void WorldToImage(Vector3 &) const;
190 
191  /// Convert image location (in pixels) to world coordinates (in mm)
192  void ImageToWorld(double &, double &) const;
193 
194  /// Convert image location (in pixels) to world coordinates (in mm)
195  void ImageToWorld(double &, double &, double &) const;
196 
197  /// Convert image location (in pixels) to world coordinates (in mm)
198  void ImageToWorld(Point &) const;
199 
200  /// Convert image vector (in pixels) to world coordinates (in mm)
201  void ImageToWorld(Vector3 &) const;
202 
203  // ---------------------------------------------------------------------------
204  // Domain checks
205 
206  /// Returns the image domain for which this image interpolation function
207  /// can be used without handling any form of boundary conditions
208  void Inside(double &, double &,
209  double &, double &) const;
210 
211  /// Returns the image domain for which this image interpolation function
212  /// can be used without handling any form of boundary conditions
213  void Inside(double &, double &, double &,
214  double &, double &, double &) const;
215 
216  /// Returns the image domain for which this image interpolation function
217  /// can be used without handling any form of boundary conditions
218  void Inside(double &, double &, double &, double &,
219  double &, double &, double &, double &) const;
220 
221  /// Returns interval of discrete image indices whose values are needed for
222  /// interpolation of the image value at a given continuous coordinate
223  virtual void BoundingInterval(double, int &, int &) const = 0;
224 
225  /// Returns discrete boundaries of local 2D image region needed for interpolation
226  virtual void BoundingBox(double, double, int &, int &,
227  int &, int &) const;
228 
229  /// Returns discrete boundaries of local 3D image region needed for interpolation
230  virtual void BoundingBox(double, double, double, int &, int &, int &,
231  int &, int &, int &) const;
232 
233  /// Returns discrete boundaries of local 4D image region needed for interpolation
234  virtual void BoundingBox(double, double, double, double,
235  int &, int &, int &, int &,
236  int &, int &, int &, int &) const;
237 
238  /// Check if the location (in pixels) is inside the domain for which this image
239  /// interpolation can be used without handling any form of boundary condition
240  bool IsInside(double, double) const;
241 
242  /// Check if the location (in pixels) is inside the domain for which this image
243  /// interpolation can be used without handling any form of boundary condition
244  bool IsInside(double, double, double) const;
245 
246  /// Check if the location (in pixels) is inside the domain for which this image
247  /// interpolation can be used without handling any form of boundary condition
248  bool IsInside(double, double, double, double) const;
249 
250  /// Check if the location (in pixels) is inside the domain for which this image
251  /// interpolation can be used without handling any form of boundary condition
252  bool IsInside(const Point &) const;
253 
254  /// Check if the location (in pixels) is inside the domain for which this image
255  /// interpolation can be used without handling any form of boundary condition
256  bool IsInside(const Point &, double) const;
257 
258  /// Check if the location (in pixels) is outside the domain for which this image
259  /// interpolation can be used without handling any form of boundary condition
260  bool IsOutside(double, double) const;
261 
262  /// Check if the location (in pixels) is outside the domain for which this image
263  /// interpolation can be used without handling any form of boundary condition
264  bool IsOutside(double, double, double) const;
265 
266  /// Check if the location (in pixels) is outside the domain for which this image
267  /// interpolation can be used without handling any form of boundary condition
268  bool IsOutside(double, double, double, double) const;
269 
270  /// Check if the location (in pixels) is outside the domain for which this image
271  /// interpolation can be used without handling any form of boundary condition
272  bool IsOutside(const Point &) const;
273 
274  /// Check if the location (in pixels) is outside the domain for which this image
275  /// interpolation can be used without handling any form of boundary condition
276  bool IsOutside(const Point &, double) const;
277 
278  /// Check if the location is fully inside the foreground of the image, i.e.,
279  /// including all discrete image locations required for interpolation
280  bool IsForeground(double, double) const;
281 
282  /// Check if the location is fully inside the foreground of the image, i.e.,
283  /// including all discrete image locations required for interpolation
284  bool IsForeground(double, double, double) const;
285 
286  /// Check if the location is fully inside the foreground of the image, i.e.,
287  /// including all discrete image locations required for interpolation
288  bool IsForeground(double, double, double, double) const;
289 
290  /// Check if the location is fully inside the foreground of the image, i.e.,
291  /// including all discrete image locations required for interpolation
292  bool IsForeground(const Point &) const;
293 
294  /// Check if the location is fully inside the foreground of the image, i.e.,
295  /// including all discrete image locations required for interpolation
296  bool IsForeground(const Point &, double) const;
297 
298  // ---------------------------------------------------------------------------
299  // Evaluation
300 
301  /// Evaluate scalar image without handling boundary conditions
302  ///
303  /// This version is faster than EvaluateOutside, but is only defined inside
304  /// the domain for which all image values required for interpolation are
305  /// defined and thus require no extrapolation of the finite image.
306  virtual double EvaluateInside(double, double, double = 0, double = 0) const = 0;
307 
308  /// Evaluate scalar image at an arbitrary location (in pixels)
309  virtual double EvaluateOutside(double, double, double = 0, double = 0) const = 0;
310 
311  /// Evaluate scalar image at an arbitrary location (in pixels)
312  ///
313  /// If the location is inside the domain for which the filter can perform
314  /// an interpolation without considering a particular boundary condition,
315  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
316  /// method which makes use of the extrapolation of the discrete image domain
317  /// in order to interpolate also at boundary or outside locations is used.
318  double Evaluate(double, double, double = 0, double = 0) const;
319 
320  /// Evaluate scalar image at an arbitrary location (in pixels)
321  ///
322  /// If the location is inside the domain for which the filter can perform
323  /// an interpolation without considering a particular boundary condition,
324  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
325  /// method which makes use of the extrapolation of the discrete image domain
326  /// in order to interpolate also at boundary or outside locations is used.
327  double Evaluate(const Point &, double = 0) const;
328 
329  /// Evaluate scalar image at an arbitrary location (in pixels)
330  ///
331  /// If the location is inside the domain for which the filter can perform
332  /// an interpolation without considering a particular boundary condition,
333  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
334  /// method which makes use of the extrapolation of the discrete image domain
335  /// in order to interpolate also at boundary or outside locations is used.
336  ///
337  /// \note This overloaded function corrects for the const-ness of the
338  /// corresponding virtual base class function ImageFunction::Evaluate.
339  double Evaluate(double, double, double = 0, double = 0);
340 
341  /// Evaluate scalar image at an arbitrary location (in pixels)
342  ///
343  /// If the location is partially inside the foreground region of the image,
344  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
345  /// is returned.
346  ///
347  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
348  /// inside the domain for which all image values required for interpolation are
349  /// defined and thus require no extrapolation of the finite image.
350  virtual double EvaluateWithPaddingInside(double, double, double = 0, double = 0) const = 0;
351 
352  /// Evaluate scalar image at an arbitrary location (in pixels)
353  ///
354  /// If the location is partially inside the foreground region of the image,
355  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
356  /// is returned.
357  virtual double EvaluateWithPaddingOutside(double, double, double = 0, double = 0) const = 0;
358 
359  /// Evaluate scalar image at an arbitrary location (in pixels)
360  ///
361  /// If the location is partially inside the foreground region of the image,
362  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
363  /// is returned.
364  ///
365  /// If the location is inside the domain for which the filter can perform
366  /// an interpolation without considering a particular boundary condition,
367  /// the faster EvaluateWithPaddingInside method is called. Otherwise, the
368  /// EvaluateWithPaddingOutside method which makes use of the extrapolation
369  /// of the discrete image domain in order to interpolate also at boundary or
370  /// outside locations is used.
371  double EvaluateWithPadding(double, double, double = 0, double = 0) const;
372 
373  /// Evaluate multi-channel image without handling boundary conditions
374  ///
375  /// This version is faster than EvaluateOutside, but is only defined inside
376  /// the domain for which all image values required for interpolation are
377  /// defined and thus require no extrapolation of the finite image.
378  virtual void EvaluateInside(double *, double, double, double = 0, int = 1) const;
379 
380  /// Evaluate multi-channel image at an arbitrary location (in pixels)
381  virtual void EvaluateOutside(double *, double, double, double = 0, int = 1) const;
382 
383  /// Evaluate multi-channel image at an arbitrary location (in pixels)
384  ///
385  /// If the location is inside the domain for which the filter can perform
386  /// an interpolation without considering a particular boundary condition,
387  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
388  /// method which makes use of the extrapolation of the discrete image domain
389  /// in order to interpolate also at boundary or outside locations is used.
390  void Evaluate(double *, double, double, double = 0, int = 1) const;
391 
392  /// Evaluate multi-channel image at an arbitrary location (in pixels)
393  ///
394  /// If the location is inside the domain for which the filter can perform
395  /// an interpolation without considering a particular boundary condition,
396  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
397  /// method which makes use of the extrapolation of the discrete image domain
398  /// in order to interpolate also at boundary or outside locations is used.
399  void Evaluate(double *, const Point &, int = 1) const;
400 
401  /// Evaluate multi-channel image at an arbitrary location (in pixels)
402  ///
403  /// If the location is partially inside the foreground region of the image,
404  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
405  /// is returned.
406  ///
407  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
408  /// inside the domain for which all image values required for interpolation are
409  /// defined and thus require no extrapolation of the finite image.
410  virtual void EvaluateWithPaddingInside(double *, double, double, double = 0, int = 1) const;
411 
412  /// Evaluate multi-channel image at an arbitrary location (in pixels)
413  ///
414  /// If the location is partially inside the foreground region of the image,
415  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
416  /// is returned.
417  virtual void EvaluateWithPaddingOutside(double *, double, double, double = 0, int = 1) const;
418 
419  /// Evaluate multi-channel image at an arbitrary location (in pixels)
420  ///
421  /// If the location is partially inside the foreground region of the image,
422  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
423  /// is returned.
424  ///
425  /// If the location is inside the domain for which the filter can perform
426  /// an interpolation without considering a particular boundary condition,
427  /// the faster EvaluateWithPaddingInside method is called. Otherwise, the
428  /// EvaluateWithPaddingOutside method which makes use of the extrapolation
429  /// of the discrete image domain in order to interpolate also at boundary or
430  /// outside locations is used.
431  void EvaluateWithPadding(double *, double, double, double = 0, int = 1) const;
432 
433  /// Evaluate vector image without handling boundary conditions
434  ///
435  /// This version is faster than EvaluateOutside, but is only defined inside
436  /// the domain for which all image values required for interpolation are
437  /// defined and thus require no extrapolation of the finite image.
438  virtual void EvaluateInside(Vector &, double, double, double = 0, double = 0) const = 0;
439 
440  /// Evaluate vector image at an arbitrary location (in pixels)
441  virtual void EvaluateOutside(Vector &, double, double, double = 0, double = 0) const = 0;
442 
443  /// Evaluate vector image at an arbitrary location (in pixels)
444  ///
445  /// If the location is inside the domain for which the filter can perform
446  /// an interpolation without considering a particular boundary condition,
447  /// the faster EvaluateInside method is called. Otherwise, the EvaluateOutside
448  /// method which makes use of the extrapolation of the discrete image domain
449  /// in order to interpolate also at boundary or outside locations is used.
450  void Evaluate(Vector &, double, double, double = 0, double = 0) const;
451 
452  /// Evaluate vector image at an arbitrary location (in pixels)
453  ///
454  /// If the location is partially inside the foreground region of the image,
455  /// only the foreground values are interpolated. Otherwise, a vector set to
456  /// the _DefaultValue is returned.
457  ///
458  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
459  /// inside the domain for which all image values required for interpolation are
460  /// defined and thus require no extrapolation of the finite image.
461  virtual void EvaluateWithPaddingInside(Vector &, double, double, double = 0, double = 0) const = 0;
462 
463  /// Evaluate vector image at an arbitrary location (in pixels)
464  ///
465  /// If the location is partially inside the foreground region of the image,
466  /// only the foreground values are interpolated. Otherwise, a vector set to
467  /// the _DefaultValue is returned.
468  virtual void EvaluateWithPaddingOutside(Vector &, double, double, double = 0, double = 0) const = 0;
469 
470  /// Evaluate vector image at an arbitrary location (in pixels)
471  ///
472  /// If the location is partially inside the foreground region of the image,
473  /// only the foreground values are interpolated. Otherwise, a vector set to
474  /// the _DefaultValue is returned.
475  ///
476  /// If the location is inside the domain for which the filter can perform
477  /// an interpolation without considering a particular boundary condition,
478  /// the faster EvaluateWithPaddingInside method is called. Otherwise, the
479  /// EvaluateWithPaddingOutside method which makes use of the extrapolation
480  /// of the discrete image domain in order to interpolate also at boundary or
481  /// outside locations is used.
482  void EvaluateWithPadding(Vector &, double, double, double = 0, double = 0) const;
483 
484  /// Evaluate image function at all locations of the output image
485  template <class TVoxel>
486  void Evaluate(GenericImage<TVoxel> &) const;
487 
488  // ---------------------------------------------------------------------------
489  // Derivatives
490 
491  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
492  ///
493  /// When the image has scalar data type and stores vector components in the
494  /// fourth dimension, the derivatives of all components are evaluated when
495  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
496  /// specified t component are evaluated.
497  virtual void EvaluateJacobianInside(Matrix &, double, double, double = 0, double = NaN) const;
498 
499  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
500  ///
501  /// When the image has scalar data type and stores vector components in the
502  /// fourth dimension, the derivatives of all components are evaluated when
503  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
504  /// specified t component are evaluated.
505  virtual void EvaluateJacobianOutside(Matrix &, double, double, double = 0, double = NaN) const;
506 
507  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
508  ///
509  /// When the image has scalar data type and stores vector components in the
510  /// fourth dimension, the derivatives of all components are evaluated when
511  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
512  /// specified t component are evaluated.
513  void EvaluateJacobian(Matrix &, double, double, double = 0, double = NaN) const;
514 
515 
516  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
517  ///
518  /// When the image has scalar data type and stores vector components in the
519  /// fourth dimension, the derivatives of all components are evaluated when
520  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
521  /// specified t component are evaluated.
522  virtual void EvaluateJacobianWithPaddingInside(Matrix &, double, double, double = 0, double = NaN) const;
523 
524  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
525  ///
526  /// When the image has scalar data type and stores vector components in the
527  /// fourth dimension, the derivatives of all components are evaluated when
528  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
529  /// specified t component are evaluated.
530  virtual void EvaluateJacobianWithPaddingOutside(Matrix &, double, double, double = 0, double = NaN) const;
531 
532  /// Get 1st order derivatives of given image at arbitrary location (in pixels)
533  ///
534  /// When the image has scalar data type and stores vector components in the
535  /// fourth dimension, the derivatives of all components are evaluated when
536  /// the t coordinate is set to NaN. Otherwise, only the derivatives of the
537  /// specified t component are evaluated.
538  void EvaluateJacobianWithPadding(Matrix &, double, double, double = 0, double = NaN) const;
539 
540 };
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 // Generic interpolation interface
544 ////////////////////////////////////////////////////////////////////////////////
545 
546 /**
547  * Abstract base class of generic interpolation functions
548  *
549  * This interpolation interface is templated over the input image type and
550  * thus can access the image data using non-virtual getters which return
551  * the image values with the appropriate voxel type. Therefore, it is more
552  * efficient and type safe to use this interpolation interface whenever the
553  * image type is known. Otherwise, use the abstract InterpolateImageFunction
554  * interface instead.
555  *
556  * \sa InterpolateImageFunction
557  */
558 template <class TImage>
560 {
561  mirtkAbstractMacro(GenericInterpolateImageFunction);
562 
563 public:
564 
565  // ---------------------------------------------------------------------------
566  // Types
567 
568  typedef TImage ImageType;
569  typedef typename ImageType::VoxelType VoxelType;
570  typedef typename ImageType::RealType RealType;
571  typedef typename ImageType::RealScalarType Real;
573 
574  // ---------------------------------------------------------------------------
575  // Construction/Destruction
576 
577 protected:
578 
579  /// Default constructor
581 
582 public:
583 
584  /// Destructor
586 
587  /// Construct interpolator with default infinite extension of input image
588  static GenericInterpolateImageFunction *New(enum InterpolationMode = Interpolation_Default,
589  const TImage * = NULL);
590 
591  /// Construct extrapolator which is compatible with this interpolator
593  const BaseImage * = NULL);
594 
595  /// Construct interpolator with specified infinite extension of input image
596  ///
597  /// The caller is required to set the input, initialize, and destroy the
598  /// interpolator only, the extrapolator is initialized and destroyed by the
599  /// interpolator unless the extrapolator has been replaced using the setter.
601  enum ExtrapolationMode,
602  const TImage * = NULL);
603 
604  // ---------------------------------------------------------------------------
605  // Initialization
606 
607  /// Set input image
608  virtual void Input(const BaseImage *);
609 
610  /// Get input image
611  const ImageType *Input() const;
612 
613  /// Set extrapolate image function for evaluation outside of image domain
614  virtual void Extrapolator(ExtrapolateImageFunction *, bool = false);
615 
616  /// Get extrapolate image function for evaluation outside of image domain
617  /// or \c NULL if extrapolation mode is \c Extrapolation_None
618  ExtrapolatorType *Extrapolator();
619 
620  /// Get extrapolate image function for evaluation outside of image domain
621  /// or \c NULL if extrapolation mode is \c Extrapolation_None
622  const ExtrapolatorType *Extrapolator() const;
623 
624  /// Initialize image function
625  ///
626  /// \param[in] coeff Whether input image contains interpolation coefficients
627  /// already. Otherwise, the interpolate image function will
628  /// compute these coefficients from the input intensities.
629  virtual void Initialize(bool coeff = false);
630 
631  // ---------------------------------------------------------------------------
632  // Evaluation (generic type)
633 
634  /// Evaluate generic image without handling boundary conditions
635  ///
636  /// This version is faster than GetOutside, but is only defined inside
637  /// the domain for which all image values required for interpolation are
638  /// defined and thus require no extrapolation of the finite image.
639  virtual VoxelType GetInside(double, double, double = 0, double = 0) const = 0;
640 
641  /// Evaluate generic image at an arbitrary location (in pixels)
642  virtual VoxelType GetOutside(double, double, double = 0, double = 0) const = 0;
643 
644  /// Evaluate generic image without handling boundary conditions
645  ///
646  /// If the location is partially inside the foreground region of the image,
647  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
648  /// is returned.
649  ///
650  /// This version is faster than GetWithPaddingOutside, but is only defined
651  /// inside the domain for which all image values required for interpolation
652  /// are defined and thus require no extrapolation of the finite image.
653  virtual VoxelType GetWithPaddingInside(double, double, double = 0, double = 0) const = 0;
654 
655  /// Evaluate generic image at an arbitrary location (in pixels)
656  ///
657  /// If the location is partially inside the foreground region of the image,
658  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
659  /// is returned.
660  virtual VoxelType GetWithPaddingOutside(double, double, double = 0, double = 0) const = 0;
661 
662  /// Evaluate generic image at an arbitrary location (in pixels)
663  ///
664  /// If the location is partially inside the foreground region of the image,
665  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
666  /// is returned.
667  VoxelType GetWithPadding(double, double, double = 0, double = 0) const;
668 
669  /// Evaluate generic image at an arbitrary location (in pixels)
670  ///
671  /// If the location is inside the domain for which the filter can perform
672  /// an interpolation without considering a particular boundary condition,
673  /// the faster GetInside method is called. Otherwise, the GetOutside method
674  /// which makes use of the extrapolation of the discrete image domain in
675  /// order to interpolate also at boundary or outside locations is used.
676  VoxelType Get(double, double, double = 0, double = 0) const;
677 
678  /// Evaluate generic image at an arbitrary location (in pixels)
679  VoxelType operator ()(double, double, double = 0, double = 0) const;
680 
681  // ---------------------------------------------------------------------------
682  // Evaluation (general type)
683 
684  /// Evaluate scalar image without handling boundary conditions
685  ///
686  /// This version is faster than EvaluateOutside, but is only defined inside
687  /// the domain for which all image values required for interpolation are
688  /// defined and thus require no extrapolation of the finite image.
689  virtual double EvaluateInside(double, double, double = 0, double = 0) const;
690 
691  /// Evaluate scalar image at an arbitrary location (in pixels)
692  virtual double EvaluateOutside(double, double, double = 0, double = 0) const;
693 
694  /// Evaluate scalar image at an arbitrary location (in pixels)
695  ///
696  /// If the location is partially inside the foreground region of the image,
697  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
698  /// is returned.
699  ///
700  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
701  /// inside the domain for which all image values required for interpolation are
702  /// defined and thus require no extrapolation of the finite image.
703  virtual double EvaluateWithPaddingInside(double, double, double = 0, double = 0) const;
704 
705  /// Evaluate scalar image at an arbitrary location (in pixels)
706  ///
707  /// If the location is partially inside the foreground region of the image,
708  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
709  /// is returned.
710  virtual double EvaluateWithPaddingOutside(double, double, double = 0, double = 0) const;
711 
712  /// Evaluate multi-channel image without handling boundary conditions
713  ///
714  /// This version is faster than EvaluateOutside, but is only defined inside
715  /// the domain for which all image values required for interpolation are
716  /// defined and thus require no extrapolation of the finite image.
717  virtual void EvaluateInside(double *, double, double, double = 0, int = 1) const;
718 
719  /// Evaluate multi-channel image at an arbitrary location (in pixels)
720  virtual void EvaluateOutside(double *, double, double, double = 0, int = 1) const;
721 
722  /// Evaluate multi-channel image at an arbitrary location (in pixels)
723  ///
724  /// If the location is partially inside the foreground region of the image,
725  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
726  /// is returned.
727  ///
728  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
729  /// inside the domain for which all image values required for interpolation are
730  /// defined and thus require no extrapolation of the finite image.
731  virtual void EvaluateWithPaddingInside(double *, double, double, double = 0, int = 1) const;
732 
733  /// Evaluate multi-channel image at an arbitrary location (in pixels)
734  ///
735  /// If the location is partially inside the foreground region of the image,
736  /// only the foreground values are interpolated. Otherwise, the _DefaultValue
737  /// is returned.
738  virtual void EvaluateWithPaddingOutside(double *, double, double, double = 0, int = 1) const;
739 
740  /// Evaluate vector image without handling boundary conditions
741  ///
742  /// This version is faster than EvaluateOutside, but is only defined inside
743  /// the domain for which all image values required for interpolation are
744  /// defined and thus require no extrapolation of the finite image.
745  virtual void EvaluateInside(Vector &, double, double, double = 0, double = 0) const;
746 
747  /// Evaluate vector image at an arbitrary location (in pixels)
748  virtual void EvaluateOutside(Vector &, double, double, double = 0, double = 0) const;
749 
750  /// Evaluate vector image at an arbitrary location (in pixels)
751  ///
752  /// If the location is partially inside the foreground region of the image,
753  /// only the foreground values are interpolated. Otherwise, a vector set to
754  /// the _DefaultValue is returned.
755  ///
756  /// This version is faster than EvaluateWithPaddingOutside, but is only defined
757  /// inside the domain for which all image values required for interpolation are
758  /// defined and thus require no extrapolation of the finite image.
759  virtual void EvaluateWithPaddingInside(Vector &, double, double, double = 0, double = 0) const;
760 
761  /// Evaluate vector image at an arbitrary location (in pixels)
762  ///
763  /// If the location is partially inside the foreground region of the image,
764  /// only the foreground values are interpolated. Otherwise, a vector set to
765  /// the _DefaultValue is returned.
766  virtual void EvaluateWithPaddingOutside(Vector &, double, double, double = 0, double = 0) const;
767 
768 };
769 
770 ////////////////////////////////////////////////////////////////////////////////
771 // Auxiliary macro for subclass implementation
772 ////////////////////////////////////////////////////////////////////////////////
773 
774 // -----------------------------------------------------------------------------
775 #define mirtkInterpolatorMacro(clsname, mode) \
776  mirtkObjectMacro(clsname); \
777  public: \
778  /** Get interpolation mode implemented by this interpolator */ \
779  inline virtual enum InterpolationMode InterpolationMode() const \
780  { return mode; } \
781  /** Get interpolation mode implemented by this class */ \
782  inline static enum InterpolationMode InterpolationType() \
783  { return mode; } \
784  private:
785 
786 // -----------------------------------------------------------------------------
787 #define mirtkGenericInterpolatorTypes(superclsname) \
788  public: \
789  typedef superclsname<TImage> Superclass; \
790  typedef typename Superclass::ImageType ImageType; \
791  typedef typename Superclass::VoxelType VoxelType; \
792  typedef typename Superclass::RealType RealType; \
793  typedef typename Superclass::Real Real; \
794  typedef typename Superclass::ExtrapolatorType ExtrapolatorType; \
795  private:
796 
797 // -----------------------------------------------------------------------------
798 #define mirtkGenericInterpolatorMacro(clsname, mode) \
799  mirtkInterpolatorMacro(clsname, mode); \
800  mirtkGenericInterpolatorTypes(GenericInterpolateImageFunction); \
801  private:
802 
803 ////////////////////////////////////////////////////////////////////////////////
804 // Inline definitions -- InterpolateImageFunction
805 ////////////////////////////////////////////////////////////////////////////////
806 
807 // =============================================================================
808 // Initialization
809 // =============================================================================
810 
811 // -----------------------------------------------------------------------------
813 {
814  this->_Input = const_cast<BaseImage *>(input);
815 }
816 
817 // -----------------------------------------------------------------------------
819 {
820  return this->_Input;
821 }
822 
823 // -----------------------------------------------------------------------------
825 {
826  this->Initialize(false);
827 }
828 
829 // -----------------------------------------------------------------------------
831 {
832 }
833 
834 // -----------------------------------------------------------------------------
835 inline void InterpolateImageFunction
837 {
839  _InfiniteInput = input;
841 }
842 
843 // -----------------------------------------------------------------------------
845 {
846  return _InfiniteInput;
847 }
848 
849 // -----------------------------------------------------------------------------
851 {
852  return _InfiniteInput;
853 }
854 
855 // -----------------------------------------------------------------------------
857 {
858  return (_InfiniteInput ? _InfiniteInput->ExtrapolationMode() : Extrapolation_None);
859 }
860 
861 // =============================================================================
862 // Image attributes
863 // =============================================================================
864 
865 // -----------------------------------------------------------------------------
867 {
868  return this->_Input->Attributes();
869 }
870 
871 // -----------------------------------------------------------------------------
872 inline int InterpolateImageFunction::X() const
873 {
874  return this->_Input->X();
875 }
876 
877 // -----------------------------------------------------------------------------
878 inline int InterpolateImageFunction::Y() const
879 {
880  return this->_Input->Y();
881 }
882 
883 // -----------------------------------------------------------------------------
884 inline int InterpolateImageFunction::Z() const
885 {
886  return this->_Input->Z();
887 }
888 
889 // -----------------------------------------------------------------------------
890 inline int InterpolateImageFunction::T() const
891 {
892  return this->_Input->T();
893 }
894 
895 // -----------------------------------------------------------------------------
896 inline double InterpolateImageFunction::XSize() const
897 {
898  return this->_Input->XSize();
899 }
900 
901 // -----------------------------------------------------------------------------
902 inline double InterpolateImageFunction::YSize() const
903 {
904  return this->_Input->YSize();
905 }
906 
907 // -----------------------------------------------------------------------------
908 inline double InterpolateImageFunction::ZSize() const
909 {
910  return this->_Input->ZSize();
911 }
912 
913 // -----------------------------------------------------------------------------
914 inline double InterpolateImageFunction::TSize() const
915 {
916  return this->_Input->TSize();
917 }
918 
919 // ----------------------------------------------------------------------------
920 inline void InterpolateImageFunction::WorldToImage(double &x, double &y) const
921 {
922  this->_Input->WorldToImage(x, y);
923 }
924 
925 // ----------------------------------------------------------------------------
926 inline void InterpolateImageFunction::WorldToImage(double &x, double &y, double &z) const
927 {
928  this->_Input->WorldToImage(x, y, z);
929 }
930 
931 // ----------------------------------------------------------------------------
933 {
934  this->_Input->WorldToImage(p);
935 }
936 
937 // ----------------------------------------------------------------------------
939 {
940  this->_Input->WorldToImage(v);
941 }
942 
943 // ----------------------------------------------------------------------------
944 inline void InterpolateImageFunction::ImageToWorld(double &x, double &y) const
945 {
946  this->_Input->ImageToWorld(x, y);
947 }
948 
949 // ----------------------------------------------------------------------------
950 inline void InterpolateImageFunction::ImageToWorld(double &x, double &y, double &z) const
951 {
952  this->_Input->ImageToWorld(x, y, z);
953 }
954 
955 // ----------------------------------------------------------------------------
957 {
958  this->_Input->ImageToWorld(p);
959 }
960 
961 // ----------------------------------------------------------------------------
963 {
964  this->_Input->ImageToWorld(v);
965 }
966 
967 // =============================================================================
968 // Domain checks
969 // =============================================================================
970 
971 // -----------------------------------------------------------------------------
972 inline void InterpolateImageFunction::Inside(double &x1, double &y1,
973  double &x2, double &y2) const
974 {
975  x1 = _x1, y1 = _y1;
976  x2 = _x2, y2 = _y2;
977 }
978 
979 // -----------------------------------------------------------------------------
980 inline void InterpolateImageFunction::Inside(double &x1, double &y1, double &z1,
981  double &x2, double &y2, double &z2) const
982 {
983  x1 = _x1, y1 = _y1, z1 = _z1;
984  x2 = _x2, y2 = _y2, z2 = _z2;
985 }
986 
987 // -----------------------------------------------------------------------------
988 inline void InterpolateImageFunction::Inside(double &x1, double &y1, double &z1, double &t1,
989  double &x2, double &y2, double &z2, double &t2) const
990 {
991  x1 = _x1, y1 = _y1, z1 = _z1, t1 = _t1;
992  x2 = _x2, y2 = _y2, z2 = _z2, t2 = _t2;
993 }
994 
995 // -----------------------------------------------------------------------------
996 inline void InterpolateImageFunction::BoundingBox(double x, double y,
997  int &i1, int &j1,
998  int &i2, int &j2) const
999 {
1000  this->BoundingInterval(x, i1, i2);
1001  this->BoundingInterval(y, j1, j2);
1002 }
1003 
1004 // -----------------------------------------------------------------------------
1005 inline void InterpolateImageFunction::BoundingBox(double x, double y, double z,
1006  int &i1, int &j1, int &k1,
1007  int &i2, int &j2, int &k2) const
1008 {
1009  if (this->NumberOfDimensions() >= 3) {
1010  this->BoundingInterval(x, i1, i2);
1011  this->BoundingInterval(y, j1, j2);
1012  this->BoundingInterval(z, k1, k2);
1013  } else {
1014  this->BoundingInterval(x, i1, i2);
1015  this->BoundingInterval(y, j1, j2);
1016  k1 = k2 = iround(z);
1017  }
1018 }
1019 
1020 // -----------------------------------------------------------------------------
1021 inline void InterpolateImageFunction::BoundingBox(double x, double y, double z, double t,
1022  int &i1, int &j1, int &k1, int &l1,
1023  int &i2, int &j2, int &k2, int &l2) const
1024 {
1025  if (this->NumberOfDimensions() >= 4) {
1026  this->BoundingInterval(x, i1, i2);
1027  this->BoundingInterval(y, j1, j2);
1028  this->BoundingInterval(z, k1, k2);
1029  this->BoundingInterval(t, l1, l2);
1030  } else if (this->NumberOfDimensions() == 3) {
1031  this->BoundingInterval(x, i1, i2);
1032  this->BoundingInterval(y, j1, j2);
1033  this->BoundingInterval(z, k1, k2);
1034  l1 = l2 = iround(t);
1035  } else {
1036  this->BoundingInterval(x, i1, i2);
1037  this->BoundingInterval(y, j1, j2);
1038  k1 = k2 = iround(z);
1039  l1 = l2 = iround(t);
1040  }
1041 }
1042 
1043 // -----------------------------------------------------------------------------
1044 inline bool InterpolateImageFunction::IsInside(double x, double y) const
1045 {
1046  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2);
1047 }
1048 
1049 // -----------------------------------------------------------------------------
1050 inline bool InterpolateImageFunction::IsInside(double x, double y, double z) const
1051 {
1052  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2) && (_z1 <= z && z <= _z2);
1053 }
1054 
1055 // -----------------------------------------------------------------------------
1056 inline bool InterpolateImageFunction::IsInside(double x, double y, double z, double t) const
1057 {
1058  return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2) && (_z1 <= z && z <= _z2) && (_t1 <= t && t <= _t2);
1059 }
1060 
1061 // -----------------------------------------------------------------------------
1062 inline bool InterpolateImageFunction::IsInside(const Point &p) const
1063 {
1064  return IsInside(p._x, p._y, p._z);
1065 }
1066 
1067 // -----------------------------------------------------------------------------
1068 inline bool InterpolateImageFunction::IsInside(const Point &p, double t) const
1069 {
1070  return IsInside(p._x, p._y, p._z, t);
1071 }
1072 
1073 // -----------------------------------------------------------------------------
1074 inline bool InterpolateImageFunction::IsOutside(double x, double y) const
1075 {
1076  return !IsInside(x, y);
1077 }
1078 
1079 // -----------------------------------------------------------------------------
1080 inline bool InterpolateImageFunction::IsOutside(double x, double y, double z) const
1081 {
1082  return !IsInside(x, y, z);
1083 }
1084 
1085 // -----------------------------------------------------------------------------
1086 inline bool InterpolateImageFunction::IsOutside(double x, double y, double z, double t) const
1087 {
1088  return !IsInside(x, y, z, t);
1089 }
1090 
1091 // -----------------------------------------------------------------------------
1092 inline bool InterpolateImageFunction::IsOutside(const Point &p) const
1093 {
1094  return IsOutside(p._x, p._y, p._z);
1095 }
1096 
1097 // -----------------------------------------------------------------------------
1098 inline bool InterpolateImageFunction::IsOutside(const Point &p, double t) const
1099 {
1100  return IsOutside(p._x, p._y, p._z, t);
1101 }
1102 
1103 // -----------------------------------------------------------------------------
1104 inline bool InterpolateImageFunction::IsForeground(double x, double y) const
1105 {
1106  int i1, j1, i2, j2;
1107  BoundingBox(x, y, i1, j1, i2, j2);
1108  return Input()->IsBoundingBoxInsideForeground(i1, j1, i2, j2);
1109 }
1110 
1111 // -----------------------------------------------------------------------------
1112 inline bool InterpolateImageFunction::IsForeground(double x, double y, double z) const
1113 {
1114  int i1, j1, k1, i2, j2, k2;
1115  BoundingBox(x, y, z, i1, j1, k1, i2, j2, k2);
1116  return Input()->IsBoundingBoxInsideForeground(i1, j1, k1, i2, j2, k2);
1117 }
1118 
1119 // -----------------------------------------------------------------------------
1120 inline bool InterpolateImageFunction::IsForeground(double x, double y, double z, double t) const
1121 {
1122  int i1, j1, k1, l1, i2, j2, k2, l2;
1123  BoundingBox(x, y, z, t, i1, j1, k1, l1, i2, j2, k2, l2);
1124  return Input()->IsBoundingBoxInsideForeground(i1, j1, k1, l1, i2, j2, k2, l2);
1125 }
1126 
1127 // -----------------------------------------------------------------------------
1129 {
1130  return IsForeground(p._x, p._y, p._z);
1131 }
1132 
1133 // -----------------------------------------------------------------------------
1134 inline bool InterpolateImageFunction::IsForeground(const Point &p, double t) const
1135 {
1136  return IsForeground(p._x, p._y, p._z, t);
1137 }
1138 
1139 // =============================================================================
1140 // Evaluation
1141 // =============================================================================
1142 
1143 // -----------------------------------------------------------------------------
1144 inline double InterpolateImageFunction::Evaluate(double x, double y, double z, double t) const
1145 {
1146  if (IsInside(x, y, z, t)) return this->EvaluateInside (x, y, z, t);
1147  else return this->EvaluateOutside(x, y, z, t);
1148 }
1149 
1150 // -----------------------------------------------------------------------------
1151 inline double InterpolateImageFunction::Evaluate(double x, double y, double z, double t)
1152 {
1153  return const_cast<const InterpolateImageFunction *>(this)->Evaluate(x, y, z, t);
1154 }
1155 
1156 // -----------------------------------------------------------------------------
1157 inline double InterpolateImageFunction::Evaluate(const Point &p, double t) const
1158 {
1159  return Evaluate(p._x, p._y, p._z, t);
1160 }
1161 
1162 // -----------------------------------------------------------------------------
1163 inline double InterpolateImageFunction::EvaluateWithPadding(double x, double y, double z, double t) const
1164 {
1165  if (IsInside(x, y, z, t)) return this->EvaluateWithPaddingInside (x, y, z, t);
1166  else return this->EvaluateWithPaddingOutside(x, y, z, t);
1167 }
1168 
1169 // -----------------------------------------------------------------------------
1170 inline void InterpolateImageFunction::EvaluateInside(double *v, double x, double y, double z, int vt) const
1171 {
1172  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1173  (*v) = this->EvaluateInside(x, y, z, static_cast<double>(t));
1174  }
1175 }
1176 
1177 // -----------------------------------------------------------------------------
1178 inline void InterpolateImageFunction::EvaluateOutside(double *v, double x, double y, double z, int vt) const
1179 {
1180  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1181  (*v) = this->EvaluateOutside(x, y, z, static_cast<double>(t));
1182  }
1183 }
1184 
1185 // -----------------------------------------------------------------------------
1186 inline void InterpolateImageFunction::Evaluate(double *v, double x, double y, double z, int vt) const
1187 {
1188  if (IsInside(x, y, z)) this->EvaluateInside (v, x, y, z, vt);
1189  else this->EvaluateOutside(v, x, y, z, vt);
1190 }
1191 
1192 // -----------------------------------------------------------------------------
1193 inline void InterpolateImageFunction::Evaluate(double *v, const Point &p, int vt) const
1194 {
1195  Evaluate(v, p._x, p._y, p._z, vt);
1196 }
1197 
1198 // -----------------------------------------------------------------------------
1199 inline void InterpolateImageFunction::EvaluateWithPaddingInside(double *v, double x, double y, double z, int vt) const
1200 {
1201  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1202  (*v) = this->EvaluateWithPaddingInside(x, y, z, static_cast<double>(t));
1203  }
1204 }
1205 
1206 // -----------------------------------------------------------------------------
1207 inline void InterpolateImageFunction::EvaluateWithPaddingOutside(double *v, double x, double y, double z, int vt) const
1208 {
1209  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1210  (*v) = this->EvaluateWithPaddingOutside(x, y, z, static_cast<double>(t));
1211  }
1212 }
1213 
1214 // -----------------------------------------------------------------------------
1215 inline void InterpolateImageFunction::EvaluateWithPadding(double *v, double x, double y, double z, int vt) const
1216 {
1217  if (IsInside(x, y, z)) this->EvaluateWithPaddingInside (v, x, y, z, vt);
1218  else this->EvaluateWithPaddingOutside(v, x, y, z, vt);
1219 }
1220 
1221 // -----------------------------------------------------------------------------
1222 inline void InterpolateImageFunction::Evaluate(Vector &v, double x, double y, double z, double t) const
1223 {
1224  if (IsInside(x, y, z, t)) this->EvaluateInside (v, x, y, z, t);
1225  else this->EvaluateOutside(v, x, y, z, t);
1226 }
1227 
1228 // -----------------------------------------------------------------------------
1229 inline void InterpolateImageFunction::EvaluateWithPadding(Vector &v, double x, double y, double z, double t) const
1230 {
1231  if (IsInside(x, y, z, t)) this->EvaluateWithPaddingInside (v, x, y, z, t);
1232  else this->EvaluateWithPaddingOutside(v, x, y, z, t);
1233 }
1234 
1235 // -----------------------------------------------------------------------------
1236 template <class TVoxel>
1238 {
1239  // Interpolate multi-channel image (or 3D+t vector image)
1240  if (output.T() > 1 && IsZero(output.TSize())) {
1242  ParallelForEachVoxel(output.Attributes(), output, eval);
1243  // Interpolate scalar image
1244  } else if (output.N() == 1) {
1246  ParallelForEachVoxel(output.Attributes(), output, eval);
1247  // Interpolate vector image
1248  } else {
1250  ParallelForEachVoxel(output.Attributes(), output, eval);
1251  }
1252 }
1253 
1254 // =============================================================================
1255 // Derivatives
1256 // =============================================================================
1257 
1258 // -----------------------------------------------------------------------------
1259 inline void InterpolateImageFunction
1260 ::EvaluateJacobianInside(Matrix &, double, double, double, double) const
1261 {
1262  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1263 }
1264 
1265 // -----------------------------------------------------------------------------
1266 inline void InterpolateImageFunction
1267 ::EvaluateJacobianOutside(Matrix &, double, double, double, double) const
1268 {
1269  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1270 }
1271 
1272 // -----------------------------------------------------------------------------
1273 inline void InterpolateImageFunction
1274 ::EvaluateJacobian(Matrix &jac, double x, double y, double z, double t) const
1275 {
1276  if (this->IsInside(x, y, z, t)) this->EvaluateJacobianInside (jac, x, y, z, t);
1277  else this->EvaluateJacobianOutside(jac, x, y, z, t);
1278 }
1279 
1280 // -----------------------------------------------------------------------------
1281 inline void InterpolateImageFunction
1282 ::EvaluateJacobianWithPaddingInside(Matrix &, double, double, double, double) const
1283 {
1284  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1285 }
1286 
1287 // -----------------------------------------------------------------------------
1288 inline void InterpolateImageFunction
1289 ::EvaluateJacobianWithPaddingOutside(Matrix &, double, double, double, double) const
1290 {
1291  Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1292 }
1293 
1294 // -----------------------------------------------------------------------------
1295 inline void InterpolateImageFunction
1296 ::EvaluateJacobianWithPadding(Matrix &jac, double x, double y, double z, double t) const
1297 {
1298  if (this->IsInside(x, y, z, t)) this->EvaluateJacobianWithPaddingInside (jac, x, y, z, t);
1299  else this->EvaluateJacobianWithPaddingOutside(jac, x, y, z, t);
1300 }
1301 
1302 ////////////////////////////////////////////////////////////////////////////////
1303 // Inline definitions -- GenericInterpolateImageFunction
1304 ////////////////////////////////////////////////////////////////////////////////
1305 
1306 // =============================================================================
1307 // Getters
1308 // =============================================================================
1309 
1310 // -----------------------------------------------------------------------------
1311 template <class TImage>
1313 {
1314  return reinterpret_cast<const TImage *>(this->_Input);
1315 }
1316 
1317 // -----------------------------------------------------------------------------
1318 template <class TImage>
1321 {
1322  return reinterpret_cast<ExtrapolatorType *>(_InfiniteInput);
1323 }
1324 
1325 // -----------------------------------------------------------------------------
1326 template <class TImage>
1329 {
1330  return reinterpret_cast<const ExtrapolatorType *>(_InfiniteInput);
1331 }
1332 
1333 // =============================================================================
1334 // Evaluation
1335 // =============================================================================
1336 
1337 // -----------------------------------------------------------------------------
1338 template <class TImage>
1339 inline typename TImage::VoxelType
1341 ::Get(double x, double y, double z, double t) const
1342 {
1343  if (IsInside(x, y, z, t)) return this->GetInside (x, y, z, t);
1344  else return this->GetOutside(x, y, z, t);
1345 }
1346 
1347 // -----------------------------------------------------------------------------
1348 template <class TImage>
1349 inline typename TImage::VoxelType
1351 ::GetWithPadding(double x, double y, double z, double t) const
1352 {
1353  if (IsInside(x, y, z, t)) return this->GetWithPaddingInside (x, y, z, t);
1354  else return this->GetWithPaddingOutside(x, y, z, t);
1355 }
1356 
1357 // -----------------------------------------------------------------------------
1358 template <class TImage>
1359 inline typename TImage::VoxelType GenericInterpolateImageFunction<TImage>
1360 ::operator ()(double x, double y, double z, double t) const
1361 {
1362  return this->Get(x, y, z, t);
1363 }
1364 
1365 // -----------------------------------------------------------------------------
1366 template <class TImage>
1368 ::EvaluateInside(double x, double y, double z, double t) const
1369 {
1370  return voxel_cast<double>(this->GetInside(x, y, z, t));
1371 }
1372 
1373 // -----------------------------------------------------------------------------
1374 template <class TImage>
1376 ::EvaluateOutside(double x, double y, double z, double t) const
1377 {
1378  return voxel_cast<double>(this->GetOutside(x, y, z, t));
1379 }
1380 
1381 // -----------------------------------------------------------------------------
1382 template <class TImage>
1384 ::EvaluateWithPaddingInside(double x, double y, double z, double t) const
1385 {
1386  return voxel_cast<double>(this->GetWithPaddingInside(x, y, z, t));
1387 }
1388 
1389 // -----------------------------------------------------------------------------
1390 template <class TImage>
1392 ::EvaluateWithPaddingOutside(double x, double y, double z, double t) const
1393 {
1394  return voxel_cast<double>(this->GetWithPaddingOutside(x, y, z, t));
1395 }
1396 
1397 // -----------------------------------------------------------------------------
1398 template <class TImage>
1400 ::EvaluateInside(double *v, double x, double y, double z, int vt) const
1401 {
1402  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1403  (*v) = voxel_cast<double>(this->GetInside(x, y, z, static_cast<double>(t)));
1404  }
1405 }
1406 
1407 // -----------------------------------------------------------------------------
1408 template <class TImage>
1410 ::EvaluateOutside(double *v, double x, double y, double z, int vt) const
1411 {
1412  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1413  (*v) = voxel_cast<double>(this->GetOutside(x, y, z, static_cast<double>(t)));
1414  }
1415 }
1416 
1417 // -----------------------------------------------------------------------------
1418 template <class TImage>
1420 ::EvaluateWithPaddingInside(double *v, double x, double y, double z, int vt) const
1421 {
1422  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1423  (*v) = voxel_cast<double>(this->GetWithPaddingInside(x, y, z, static_cast<double>(t)));
1424  }
1425 }
1426 
1427 // -----------------------------------------------------------------------------
1428 template <class TImage>
1430 ::EvaluateWithPaddingOutside(double *v, double x, double y, double z, int vt) const
1431 {
1432  for (int t = 0; t < Input()->T(); ++t, v += vt) {
1433  (*v) = voxel_cast<double>(this->GetWithPaddingOutside(x, y, z, static_cast<double>(t)));
1434  }
1435 }
1436 
1437 // -----------------------------------------------------------------------------
1438 template <class TImage>
1440 ::EvaluateInside(Vector &v, double x, double y, double z, double t) const
1441 {
1442  v = voxel_cast<Vector>(this->GetInside(x, y, z, t));
1443 }
1444 
1445 // -----------------------------------------------------------------------------
1446 template <class TImage>
1448 ::EvaluateOutside(Vector &v, double x, double y, double z, double t) const
1449 {
1450  v = voxel_cast<Vector>(this->GetOutside(x, y, z, t));
1451 }
1452 
1453 // -----------------------------------------------------------------------------
1454 template <class TImage>
1456 ::EvaluateWithPaddingInside(Vector &v, double x, double y, double z, double t) const
1457 {
1458  v = voxel_cast<Vector>(this->GetWithPaddingInside(x, y, z, t));
1459 }
1460 
1461 // -----------------------------------------------------------------------------
1462 template <class TImage>
1464 ::EvaluateWithPaddingOutside(Vector &v, double x, double y, double z, double t) const
1465 {
1466  v = voxel_cast<Vector>(this->GetWithPaddingOutside(x, y, z, t));
1467 }
1468 
1469 
1470 } // namespace mirtk
1471 
1472 #endif // MIRTK_InterpolateImageFunction_H
virtual void BoundingInterval(double, int &, int &) const =0
void WorldToImage(double &, double &) const
Convert world coordinates (in mm) to image location (in pixels)
bool IsBoundingBoxInsideForeground(int, int, int, int) const
Whether all voxels within a 2D bounding region are inside foreground region.
Definition: BaseImage.h:1563
void EvaluateJacobian(Matrix &, double, double, double=0, double=NaN) const
virtual ~InterpolateImageFunction()
Destructor.
const ImageAttributes & Attributes() const
Gets the image attributes.
Definition: BaseImage.h:856
MIRTKCU_API bool IsZero(double a, double tol=1e-12)
Determine equality of a floating point number with zero.
Definition: Math.h:131
string Get(const ParameterList &params, string name)
Get parameter value from parameters list.
Definition: Object.h:202
enum ExtrapolationMode ExtrapolationMode() const
Get extrapolation mode used by this interpolator.
const ImageType * Input() const
Get input image.
ExtrapolateImageFunction * _InfiniteInput
bool _InfiniteInputOwner
Whether infinite discrete image was instantiated by this image function.
double _x
x coordinate of Point
Definition: Point.h:46
int X() const
Image size along x axis.
virtual void BoundingBox(double, double, int &, int &, int &, int &) const
Returns discrete boundaries of local 2D image region needed for interpolation.
int Z() const
Image size along z axis.
const ImageAttributes & Attributes() const
Lattice attributes.
double Evaluate(double, double, double=0, double=0) const
VoxelType GetWithPadding(double, double, double=0, double=0) const
int T() const
Image size along t axis.
int Y() const
Image size along y axis.
virtual enum InterpolationMode InterpolationMode() const =0
Get interpolation mode corresponding to this interpolator.
double TSize() const
Image spacing along t axis.
Interpolate scalar or vector image.
virtual double EvaluateInside(double, double, double=0, double=0) const =0
InterpolationMode
Image interpolation modes.
virtual enum ExtrapolationMode ExtrapolationMode() const =0
Get extrapolation mode corresponding to this extrapolator.
int N() const
Number of vector components per voxel.
Definition: GenericImage.h:534
virtual void EvaluateJacobianWithPaddingOutside(Matrix &, double, double, double=0, double=NaN) const
Definition: IOConfig.h:41
VoxelType operator()(double, double, double=0, double=0) const
Evaluate generic image at an arbitrary location (in pixels)
virtual double EvaluateWithPaddingInside(double, double, double=0, double=0) const
void EvaluateJacobianWithPadding(Matrix &, double, double, double=0, double=NaN) const
virtual void EvaluateJacobianWithPaddingInside(Matrix &, double, double, double=0, double=NaN) const
double ZSize() const
Image spacing along z axis.
virtual double EvaluateWithPaddingOutside(double, double, double=0, double=0) const
virtual void EvaluateJacobianInside(Matrix &, double, double, double=0, double=NaN) const
void Inside(double &, double &, double &, double &) const
double YSize() const
Image spacing along y axis.
virtual double EvaluateOutside(double, double, double=0, double=0) const
Evaluate scalar image at an arbitrary location (in pixels)
virtual double EvaluateWithPaddingInside(double, double, double=0, double=0) const =0
InterpolateImageFunction()
Default constructor.
virtual void EvaluateJacobianOutside(Matrix &, double, double, double=0, double=NaN) const
ExtrapolationMode
Image extrapolation modes.
virtual double EvaluateWithPaddingOutside(double, double, double=0, double=0) const =0
void Throw(ErrorType err, const char *func, Args... args) const
Definition: Object.h:166
virtual double EvaluateInside(double, double, double=0, double=0) const
double TSize() const
Returns the size of a voxel in the t-direction.
Definition: BaseImage.h:946
ExtrapolateImageFunction * Extrapolator()
int T() const
Returns the number of voxels in the t-direction.
Definition: BaseImage.h:892
VoxelType Get(double, double, double=0, double=0) const
bool IsForeground(double, double) const
static InterpolateImageFunction * New(enum InterpolationMode=Interpolation_Default, const BaseImage *=NULL)
Construct interpolator with default infinite extension of input image.
double XSize() const
Image spacing along x axis.
double _z
z coordinate of Point
Definition: Point.h:48
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
Definition: Math.h:170
void ImageToWorld(double &, double &) const
Convert image location (in pixels) to world coordinates (in mm)
double _y
y coordinate of Point
Definition: Point.h:47
const BaseImage * Input() const
Get input image.
virtual double EvaluateOutside(double, double, double=0, double=0) const =0
Evaluate scalar image at an arbitrary location (in pixels)
double EvaluateWithPadding(double, double, double=0, double=0) const