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  */
46 class InterpolateImageFunction : public ImageFunction
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.
66   ExtrapolateImageFunction *_InfiniteInput;
67 
68   /// Whether infinite discrete image was instantiated by this image function
69   bool _InfiniteInputOwner;
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
79   InterpolateImageFunction();
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
91   virtual ExtrapolateImageFunction *New(enum ExtrapolationMode,
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.
99   static InterpolateImageFunction *New(enum InterpolationMode,
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
115   enum ExtrapolationMode ExtrapolationMode() const;
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
122   ExtrapolateImageFunction *Extrapolator();
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>
559 class GenericInterpolateImageFunction : public InterpolateImageFunction
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;
572   typedef GenericExtrapolateImageFunction<ImageType> ExtrapolatorType;
573 
574   // ---------------------------------------------------------------------------
575   // Construction/Destruction
576 
577 protected:
578 
579   /// Default constructor
580   GenericInterpolateImageFunction();
581 
582 public:
583 
584   /// Destructor
585   virtual ~GenericInterpolateImageFunction();
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
592   virtual ExtrapolateImageFunction *New(enum ExtrapolationMode,
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.
600   static GenericInterpolateImageFunction *New(enum InterpolationMode,
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 // -----------------------------------------------------------------------------
Input(const BaseImage * input)812 inline void InterpolateImageFunction::Input(const BaseImage *input)
813 {
814   this->_Input = const_cast<BaseImage *>(input);
815 }
816 
817 // -----------------------------------------------------------------------------
Input()818 inline const BaseImage *InterpolateImageFunction::Input() const
819 {
820   return this->_Input;
821 }
822 
823 // -----------------------------------------------------------------------------
Initialize()824 inline void InterpolateImageFunction::Initialize()
825 {
826   this->Initialize(false);
827 }
828 
829 // -----------------------------------------------------------------------------
Update()830 inline void InterpolateImageFunction::Update()
831 {
832 }
833 
834 // -----------------------------------------------------------------------------
835 inline void InterpolateImageFunction
Extrapolator(ExtrapolateImageFunction * input,bool owner)836 ::Extrapolator(ExtrapolateImageFunction *input, bool owner)
837 {
838   if (_InfiniteInputOwner) delete _InfiniteInput;
839   _InfiniteInput      = input;
840   _InfiniteInputOwner = _InfiniteInput && owner;
841 }
842 
843 // -----------------------------------------------------------------------------
Extrapolator()844 inline ExtrapolateImageFunction *InterpolateImageFunction::Extrapolator()
845 {
846   return _InfiniteInput;
847 }
848 
849 // -----------------------------------------------------------------------------
Extrapolator()850 inline const ExtrapolateImageFunction *InterpolateImageFunction::Extrapolator() const
851 {
852   return _InfiniteInput;
853 }
854 
855 // -----------------------------------------------------------------------------
ExtrapolationMode()856 inline enum ExtrapolationMode InterpolateImageFunction::ExtrapolationMode() const
857 {
858   return (_InfiniteInput ? _InfiniteInput->ExtrapolationMode() : Extrapolation_None);
859 }
860 
861 // =============================================================================
862 // Image attributes
863 // =============================================================================
864 
865 // -----------------------------------------------------------------------------
Attributes()866 inline const ImageAttributes &InterpolateImageFunction::Attributes() const
867 {
868   return this->_Input->Attributes();
869 }
870 
871 // -----------------------------------------------------------------------------
X()872 inline int InterpolateImageFunction::X() const
873 {
874   return this->_Input->X();
875 }
876 
877 // -----------------------------------------------------------------------------
Y()878 inline int InterpolateImageFunction::Y() const
879 {
880   return this->_Input->Y();
881 }
882 
883 // -----------------------------------------------------------------------------
Z()884 inline int InterpolateImageFunction::Z() const
885 {
886   return this->_Input->Z();
887 }
888 
889 // -----------------------------------------------------------------------------
T()890 inline int InterpolateImageFunction::T() const
891 {
892   return this->_Input->T();
893 }
894 
895 // -----------------------------------------------------------------------------
XSize()896 inline double InterpolateImageFunction::XSize() const
897 {
898   return this->_Input->XSize();
899 }
900 
901 // -----------------------------------------------------------------------------
YSize()902 inline double InterpolateImageFunction::YSize() const
903 {
904   return this->_Input->YSize();
905 }
906 
907 // -----------------------------------------------------------------------------
ZSize()908 inline double InterpolateImageFunction::ZSize() const
909 {
910   return this->_Input->ZSize();
911 }
912 
913 // -----------------------------------------------------------------------------
TSize()914 inline double InterpolateImageFunction::TSize() const
915 {
916   return this->_Input->TSize();
917 }
918 
919 // ----------------------------------------------------------------------------
WorldToImage(double & x,double & y)920 inline void InterpolateImageFunction::WorldToImage(double &x, double &y) const
921 {
922   this->_Input->WorldToImage(x, y);
923 }
924 
925 // ----------------------------------------------------------------------------
WorldToImage(double & x,double & y,double & z)926 inline void InterpolateImageFunction::WorldToImage(double &x, double &y, double &z) const
927 {
928   this->_Input->WorldToImage(x, y, z);
929 }
930 
931 // ----------------------------------------------------------------------------
WorldToImage(Point & p)932 inline void InterpolateImageFunction::WorldToImage(Point &p) const
933 {
934   this->_Input->WorldToImage(p);
935 }
936 
937 // ----------------------------------------------------------------------------
WorldToImage(Vector3 & v)938 inline void InterpolateImageFunction::WorldToImage(Vector3 &v) const
939 {
940   this->_Input->WorldToImage(v);
941 }
942 
943 // ----------------------------------------------------------------------------
ImageToWorld(double & x,double & y)944 inline void InterpolateImageFunction::ImageToWorld(double &x, double &y) const
945 {
946   this->_Input->ImageToWorld(x, y);
947 }
948 
949 // ----------------------------------------------------------------------------
ImageToWorld(double & x,double & y,double & z)950 inline void InterpolateImageFunction::ImageToWorld(double &x, double &y, double &z) const
951 {
952   this->_Input->ImageToWorld(x, y, z);
953 }
954 
955 // ----------------------------------------------------------------------------
ImageToWorld(Point & p)956 inline void InterpolateImageFunction::ImageToWorld(Point &p) const
957 {
958   this->_Input->ImageToWorld(p);
959 }
960 
961 // ----------------------------------------------------------------------------
ImageToWorld(Vector3 & v)962 inline void InterpolateImageFunction::ImageToWorld(Vector3 &v) const
963 {
964   this->_Input->ImageToWorld(v);
965 }
966 
967 // =============================================================================
968 // Domain checks
969 // =============================================================================
970 
971 // -----------------------------------------------------------------------------
Inside(double & x1,double & y1,double & x2,double & y2)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 // -----------------------------------------------------------------------------
Inside(double & x1,double & y1,double & z1,double & x2,double & y2,double & z2)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 // -----------------------------------------------------------------------------
Inside(double & x1,double & y1,double & z1,double & t1,double & x2,double & y2,double & z2,double & t2)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 // -----------------------------------------------------------------------------
BoundingBox(double x,double y,int & i1,int & j1,int & i2,int & j2)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 // -----------------------------------------------------------------------------
BoundingBox(double x,double y,double z,int & i1,int & j1,int & k1,int & i2,int & j2,int & k2)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 // -----------------------------------------------------------------------------
BoundingBox(double x,double y,double z,double t,int & i1,int & j1,int & k1,int & l1,int & i2,int & j2,int & k2,int & l2)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 // -----------------------------------------------------------------------------
IsInside(double x,double y)1044 inline bool InterpolateImageFunction::IsInside(double x, double y) const
1045 {
1046   return (_x1 <= x && x <= _x2) && (_y1 <= y && y <= _y2);
1047 }
1048 
1049 // -----------------------------------------------------------------------------
IsInside(double x,double y,double z)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 // -----------------------------------------------------------------------------
IsInside(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
IsInside(const Point & p)1062 inline bool InterpolateImageFunction::IsInside(const Point &p) const
1063 {
1064   return IsInside(p._x, p._y, p._z);
1065 }
1066 
1067 // -----------------------------------------------------------------------------
IsInside(const Point & p,double t)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 // -----------------------------------------------------------------------------
IsOutside(double x,double y)1074 inline bool InterpolateImageFunction::IsOutside(double x, double y) const
1075 {
1076   return !IsInside(x, y);
1077 }
1078 
1079 // -----------------------------------------------------------------------------
IsOutside(double x,double y,double z)1080 inline bool InterpolateImageFunction::IsOutside(double x, double y, double z) const
1081 {
1082   return !IsInside(x, y, z);
1083 }
1084 
1085 // -----------------------------------------------------------------------------
IsOutside(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
IsOutside(const Point & p)1092 inline bool InterpolateImageFunction::IsOutside(const Point &p) const
1093 {
1094   return IsOutside(p._x, p._y, p._z);
1095 }
1096 
1097 // -----------------------------------------------------------------------------
IsOutside(const Point & p,double t)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 // -----------------------------------------------------------------------------
IsForeground(double x,double y)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 // -----------------------------------------------------------------------------
IsForeground(double x,double y,double z)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 // -----------------------------------------------------------------------------
IsForeground(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
IsForeground(const Point & p)1128 inline bool InterpolateImageFunction::IsForeground(const Point &p) const
1129 {
1130   return IsForeground(p._x, p._y, p._z);
1131 }
1132 
1133 // -----------------------------------------------------------------------------
IsForeground(const Point & p,double t)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 // -----------------------------------------------------------------------------
Evaluate(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
Evaluate(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
Evaluate(const Point & p,double t)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 // -----------------------------------------------------------------------------
EvaluateWithPadding(double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
EvaluateInside(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
EvaluateOutside(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
Evaluate(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
Evaluate(double * v,const Point & p,int vt)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 // -----------------------------------------------------------------------------
EvaluateWithPaddingInside(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
EvaluateWithPaddingOutside(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
EvaluateWithPadding(double * v,double x,double y,double z,int vt)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 // -----------------------------------------------------------------------------
Evaluate(Vector & v,double x,double y,double z,double t)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 // -----------------------------------------------------------------------------
EvaluateWithPadding(Vector & v,double x,double y,double z,double t)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>
Evaluate(GenericImage<TVoxel> & output)1237 inline void InterpolateImageFunction::Evaluate(GenericImage<TVoxel> &output) const
1238 {
1239   // Interpolate multi-channel image (or 3D+t vector image)
1240   if (output.T() > 1 && IsZero(output.TSize())) {
1241     UnaryVoxelFunction::InterpolateMultiChannelImage<InterpolateImageFunction> eval(this, &output);
1242     ParallelForEachVoxel(output.Attributes(), output, eval);
1243   // Interpolate scalar image
1244   } else if (output.N() == 1) {
1245     UnaryVoxelFunction::InterpolateScalarImage<InterpolateImageFunction> eval(this, &output);
1246     ParallelForEachVoxel(output.Attributes(), output, eval);
1247   // Interpolate vector image
1248   } else {
1249     UnaryVoxelFunction::InterpolateImage<InterpolateImageFunction> eval(this, &output);
1250     ParallelForEachVoxel(output.Attributes(), output, eval);
1251   }
1252 }
1253 
1254 // =============================================================================
1255 // Derivatives
1256 // =============================================================================
1257 
1258 // -----------------------------------------------------------------------------
1259 inline void InterpolateImageFunction
EvaluateJacobianInside(Matrix &,double,double,double,double)1260 ::EvaluateJacobianInside(Matrix &, double, double, double, double) const
1261 {
1262   Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1263 }
1264 
1265 // -----------------------------------------------------------------------------
1266 inline void InterpolateImageFunction
EvaluateJacobianOutside(Matrix &,double,double,double,double)1267 ::EvaluateJacobianOutside(Matrix &, double, double, double, double) const
1268 {
1269   Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1270 }
1271 
1272 // -----------------------------------------------------------------------------
1273 inline void InterpolateImageFunction
EvaluateJacobian(Matrix & jac,double x,double y,double z,double t)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
EvaluateJacobianWithPaddingInside(Matrix &,double,double,double,double)1282 ::EvaluateJacobianWithPaddingInside(Matrix &, double, double, double, double) const
1283 {
1284   Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1285 }
1286 
1287 // -----------------------------------------------------------------------------
1288 inline void InterpolateImageFunction
EvaluateJacobianWithPaddingOutside(Matrix &,double,double,double,double)1289 ::EvaluateJacobianWithPaddingOutside(Matrix &, double, double, double, double) const
1290 {
1291   Throw(ERR_NotImplemented, __FUNCTION__, "Not implemented");
1292 }
1293 
1294 // -----------------------------------------------------------------------------
1295 inline void InterpolateImageFunction
EvaluateJacobianWithPadding(Matrix & jac,double x,double y,double z,double t)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>
Input()1312 inline const TImage *GenericInterpolateImageFunction<TImage>::Input() const
1313 {
1314   return reinterpret_cast<const TImage *>(this->_Input);
1315 }
1316 
1317 // -----------------------------------------------------------------------------
1318 template <class TImage>
1319 inline typename GenericInterpolateImageFunction<TImage>::ExtrapolatorType *
Extrapolator()1320 GenericInterpolateImageFunction<TImage>::Extrapolator()
1321 {
1322   return reinterpret_cast<ExtrapolatorType *>(_InfiniteInput);
1323 }
1324 
1325 // -----------------------------------------------------------------------------
1326 template <class TImage>
1327 inline const typename GenericInterpolateImageFunction<TImage>::ExtrapolatorType *
Extrapolator()1328 GenericInterpolateImageFunction<TImage>::Extrapolator() const
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
1340 GenericInterpolateImageFunction<TImage>
Get(double x,double y,double z,double t)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
1350 GenericInterpolateImageFunction<TImage>
GetWithPadding(double x,double y,double z,double t)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>
operator()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>
1367 inline double GenericInterpolateImageFunction<TImage>
EvaluateInside(double x,double y,double z,double t)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>
1375 inline double GenericInterpolateImageFunction<TImage>
EvaluateOutside(double x,double y,double z,double t)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>
1383 inline double GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingInside(double x,double y,double z,double t)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>
1391 inline double GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingOutside(double x,double y,double z,double t)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>
1399 inline void GenericInterpolateImageFunction<TImage>
EvaluateInside(double * v,double x,double y,double z,int vt)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>
1409 inline void GenericInterpolateImageFunction<TImage>
EvaluateOutside(double * v,double x,double y,double z,int vt)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>
1419 inline void GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingInside(double * v,double x,double y,double z,int vt)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>
1429 inline void GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingOutside(double * v,double x,double y,double z,int vt)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>
1439 inline void GenericInterpolateImageFunction<TImage>
EvaluateInside(Vector & v,double x,double y,double z,double t)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>
1447 inline void GenericInterpolateImageFunction<TImage>
EvaluateOutside(Vector & v,double x,double y,double z,double t)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>
1455 inline void GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingInside(Vector & v,double x,double y,double z,double t)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>
1463 inline void GenericInterpolateImageFunction<TImage>
EvaluateWithPaddingOutside(Vector & v,double x,double y,double z,double t)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
1473