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_ExtrapolateImageFunction_H
21 #define MIRTK_ExtrapolateImageFunction_H
22 
23 #include "mirtk/ExtrapolationMode.h"
24 #include "mirtk/Vector.h"
25 #include "mirtk/VoxelCast.h"
26 #include "mirtk/BaseImage.h"
27 #include "mirtk/ImageFunction.h"
28 
29 
30 namespace mirtk {
31 
32 
33 /**
34  * Abstract base class for discrete image extrapolation
35  *
36  * This abstract base class defines a common interface for image functions
37  * which provide a value at each discrete image location, especially also
38  * those which are outside the finite domain on which the image is defined.
39  * At these outside voxels, the image function extrapolates the image values,
40  * thus extending an image function to an infinite discrete lattice. An image
41  * extrapolate image function is mainly used indirectly through an instance of
42  * InterpolateImageFunction. Image values at continuous voxel positions
43  * are interpolated by the interpolate image function using the extrapolated
44  * image values at discrete lattice points.
45  */
46 class ExtrapolateImageFunction : public ImageFunction
47 {
48   mirtkAbstractMacro(ExtrapolateImageFunction);
49 
50   // ---------------------------------------------------------------------------
51   // Construction/Destruction
52 
53 protected:
54 
55   /// Default constructor
56   ExtrapolateImageFunction();
57 
58 public:
59 
60   /// Destructor
61   virtual ~ExtrapolateImageFunction();
62 
63   /// Construct extrapolator or return NULL if \p mode is \c Extrapolation_None
64   static ExtrapolateImageFunction *New(ExtrapolationMode mode,
65                                        const BaseImage * = NULL);
66 
67   // ---------------------------------------------------------------------------
68   // Initialization
69 
70   /// Get extrapolation mode corresponding to this extrapolator
71   virtual enum ExtrapolationMode ExtrapolationMode() const = 0;
72 
73   // ---------------------------------------------------------------------------
74   // Emulation of selected BaseImage functions
75 
76   // The following wrapper functions enable the subclasses of
77   // InterpolateImageFunction to use a template function for the
78   // implementation of EvaluateInside and EvaluateOutside where the only
79   // difference is the image type used to access the image values.
80 
81   const ImageAttributes &Attributes() const; ///< Attributes of input image
82 
83   int X() const; ///< Size of input image in x dimension
84   int Y() const; ///< Size of input image in y dimension
85   int Z() const; ///< Size of input image in z dimension
86   int T() const; ///< Size of input image in t dimension
87   int N() const; ///< Number of vector components per image voxel
88 
89   double XSize() const; ///< Voxel size of input image in x dimension
90   double YSize() const; ///< Voxel size of input image in y dimension
91   double ZSize() const; ///< Voxel size of input image in z dimension
92   double TSize() const; ///< Voxel size of input image in t dimension
93 
94   /// Whether the extrapolated value is identical to the background
95   /// value of the input image. If the input uses a background mask
96   /// instead, only subclasses of IndexExtrapolateImageFunction
97   /// can determine whether the voxel at the transformed location
98   /// is in the foreground region.
99   virtual bool IsForeground(int, int, int = 0, int = 0) const;
100 
101   // ---------------------------------------------------------------------------
102   // Image function interface
103 
104   /// Get scalar image value at the nearest discrete image location
105   double Evaluate(double, double, double = 0, double = 0) const;
106 
107   /// Get scalar image value at the nearest discrete image location
108   virtual double Evaluate(double, double, double = 0, double = 0);
109 
110   // ---------------------------------------------------------------------------
111   // Extrapolation of discrete image function
112 
113   /// Get scalar image value at an arbitrary discrete image location
114   double GetAsDouble(int) const;
115 
116   /// Get scalar image value at an arbitrary discrete image location
117   virtual double GetAsDouble(int, int, int = 0, int = 0) const = 0;
118 
119   /// Get vector image value at an arbitrary discrete image location
120   Vector GetAsVector(int) const;
121 
122   /// Get vector image value at an arbitrary discrete image location
123   Vector GetAsVector(int, int, int = 0, int = 0) const;
124 
125   /// Get vector image value at an arbitrary discrete image location
126   void GetAsVector(Vector &, int) const;
127 
128   /// Get vector image value at an arbitrary discrete image location
129   virtual void GetAsVector(Vector &, int, int, int = 0, int = 0) const = 0;
130 
131 };
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 // Generic extrapolation interface
135 ////////////////////////////////////////////////////////////////////////////////
136 
137 /**
138  * Generic base class for image extrapolation functions
139  *
140  * This base class is templated over the type of the input image to be extrapolated
141  * and thus subclasses can make use of image voxel type specific (non-virtual)
142  * getters to access the image data. No conversion of the voxel type to a uniform
143  * voxel type such as double scalar or vector type is required when the type of
144  * the image to be extrapolated is known. Otherwise, if the image type is unknown,
145  * use the abstract ExtrapolateImageFunction interface instead.
146  *
147  * \sa ExtrapolateImageFunction
148  */
149 template <class TImage>
150 class GenericExtrapolateImageFunction : public ExtrapolateImageFunction
151 {
152   mirtkAbstractMacro(GenericExtrapolateImageFunction);
153 
154   // ---------------------------------------------------------------------------
155   // Types
156 
157 public:
158 
159   typedef TImage                        ImageType; ///< Input image type
160   typedef typename ImageType::VoxelType VoxelType; ///< Input voxel type
161   typedef typename ImageType::RealType  RealType;  ///< Compatible floating-point type
162 
163   // ---------------------------------------------------------------------------
164   // Construction/Destruction
165 
166 protected:
167 
168   /// Default constructor
169   GenericExtrapolateImageFunction();
170 
171 public:
172 
173   /// Destructor
174   virtual ~GenericExtrapolateImageFunction();
175 
176   /// Construct extrapolator or return NULL if \p mode is \c Extrapolation_None
177   static GenericExtrapolateImageFunction *New(enum ExtrapolationMode,
178                                               const TImage * = NULL);
179 
180   // ---------------------------------------------------------------------------
181   // Initialization
182 
183   /// Set input image
184   virtual void Input(const BaseImage *);
185 
186   /// Get input image
187   const ImageType *Input() const;
188 
189   /// Initialize image function
190   virtual void Initialize();
191 
192   // ---------------------------------------------------------------------------
193   // Extrapolation of discrete image function
194 
195   /// Get image value at an arbitrary discrete image location
196   VoxelType Get(int) const;
197 
198   /// Get image value at an arbitrary discrete image location
199   virtual VoxelType Get(int, int, int = 0, int = 0) const = 0;
200 
201   /// Get image value at an arbitrary discrete image location
202   VoxelType operator ()(int) const;
203 
204   /// Get image value at an arbitrary discrete image location
205   VoxelType operator ()(int, int, int = 0, int = 0) const;
206 
207   // Import overloaded non-virtual member functions from base class
208   using ExtrapolateImageFunction::GetAsDouble;
209   using ExtrapolateImageFunction::GetAsVector;
210 
211   /// Get scalar image value at an arbitrary discrete image location
212   double GetAsDouble(int, int, int = 0, int = 0) const;
213 
214   /// Get vector image value at an arbitrary discrete image location
215   void GetAsVector(Vector &, int, int, int = 0, int = 0) const;
216 
217 };
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 // Index extrapolation interface
221 ////////////////////////////////////////////////////////////////////////////////
222 
223 /**
224  * Base class for generic voxel index extrapolation functions
225  *
226  * This abstract class is the base for extrapolate image functions which map
227  * any given discrete voxel coordinate to one, which is inside the finite image
228  * domain. The extrapolation function assigns the image value at the resulting
229  * voxel coordinate to the initially mapped discrete voxel.
230  *
231  * This base class is templated over the type of the input image to be extrapolated
232  * and thus subclasses can make use of image voxel type specific (non-virtual)
233  * getters to access the image data. No conversion of the voxel type to a uniform
234  * voxel type such as double scalar or vector type is required when the type of
235  * the image to be extrapolated is known. Otherwise, if the image type is unknown,
236  * use the abstract ExtrapolateImageFunction interface instead.
237  *
238  * \sa ExtrapolateImageFunction
239  */
240 template <class TImage>
241 class IndexExtrapolateImageFunction
242 : public GenericExtrapolateImageFunction<TImage>
243 {
244   mirtkAbstractMacro(IndexExtrapolateImageFunction);
245 
246   // ---------------------------------------------------------------------------
247   // Types
248 
249 public:
250 
251   typedef TImage                        ImageType; ///< Input image type
252   typedef typename ImageType::VoxelType VoxelType; ///< Input voxel type
253   typedef typename ImageType::RealType  RealType;  ///< Compatible floating-point type
254 
255   // ---------------------------------------------------------------------------
256   // Attributes
257 
258 protected:
259 
260   int _xmax; ///< Maximum index in x dimension
261   int _ymax; ///< Maximum index in y dimension
262   int _zmax; ///< Maximum index in z dimension
263   int _tmax; ///< Maximum index in t dimension
264 
265   // ---------------------------------------------------------------------------
266   // Construction/Destruction
267 
268 protected:
269 
270   /// Default constructor
271   IndexExtrapolateImageFunction();
272 
273 public:
274 
275   /// Destructor
276   virtual ~IndexExtrapolateImageFunction();
277 
278   // ---------------------------------------------------------------------------
279   // Initialization
280 
281   /// Initialize image function
282   virtual void Initialize();
283 
284   // ---------------------------------------------------------------------------
285   // Voxel index transformation
286 
287   /// Transform voxel index such that it is inside the range [0, max]
288   ///
289   /// \param[in,out] idx Voxel index.
290   /// \param[in]     max Maximum voxel index.
291   virtual void TransformIndex(int &idx, int max) const = 0;
292 
293   /// Transform voxel index in x dimension
294   void TransformX(int &) const;
295 
296   /// Transform voxel index in y dimension
297   void TransformY(int &) const;
298 
299   /// Transform voxel index in z dimension
300   void TransformZ(int &) const;
301 
302   /// Transform voxel index in t dimension
303   virtual void TransformT(int &l) const;
304 
305   /// Transform voxel index in x dimension
306   void TransformX(int &, int) const;
307 
308   /// Transform voxel index in y dimension
309   void TransformY(int &, int) const;
310 
311   /// Transform voxel index in z dimension
312   void TransformZ(int &, int) const;
313 
314   /// Transform voxel index in t dimension
315   virtual void TransformT(int &l, int c) const;
316 
317   /// Transform 2D voxel index
318   void Transform(int &, int &) const;
319 
320   /// Transform 3D voxel index
321   void Transform(int &, int &, int &) const;
322 
323   /// Transform 4D voxel index
324   void Transform(int &, int &, int &, int &) const;
325 
326   // ---------------------------------------------------------------------------
327   // Extrapolation of discrete image function
328 
329   /// Whether voxel whose value is used is inside the foreground
330   virtual bool IsForeground(int, int, int = 0, int = 0) const;
331 
332   // Import overloaded non-virtual member functions from base class
333   using GenericExtrapolateImageFunction<TImage>::Get;
334 
335   /// Get image value at an arbitrary discrete image location
336   virtual VoxelType Get(int, int, int = 0, int = 0) const;
337 
338 };
339 
340 ////////////////////////////////////////////////////////////////////////////////
341 // Auxiliary macro for subclass implementation
342 ////////////////////////////////////////////////////////////////////////////////
343 
344 // -----------------------------------------------------------------------------
345 #define mirtkExtrapolatorMacro(clsname, mode)                                  \
346     mirtkObjectMacro(clsname);                                                 \
347   public:                                                                      \
348     /** Get extrapolation mode implemented by this extrapolator */             \
349     inline virtual enum ExtrapolationMode ExtrapolationMode() const            \
350     { return mode; }                                                           \
351     /** Get extrapolation mode implemented by this class */                    \
352     inline static  enum ExtrapolationMode ExtrapolationType()                  \
353     { return mode; }                                                           \
354   private:
355 
356 // -----------------------------------------------------------------------------
357 #define mirtkGenericExtrapolatorMacro(clsname, mode)                           \
358   mirtkExtrapolatorMacro(clsname, mode);                                       \
359   public:                                                                      \
360     /** Input image type */                                                    \
361     typedef TImage                          ImageType;                         \
362     /** Input voxel type */                                                    \
363     typedef typename ImageType::VoxelType   VoxelType;                         \
364     /** Compatible floating-point type */                                      \
365     typedef typename ImageType::RealType    RealType;                          \
366     /* Import overloaded non-virtual member functions from base class */       \
367     using GenericExtrapolateImageFunction<TImage>::Get;                        \
368   private:
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 // Inline definitions -- ExtrapolateImageFunction
372 ////////////////////////////////////////////////////////////////////////////////
373 
374 // -----------------------------------------------------------------------------
Attributes()375 inline const ImageAttributes &ExtrapolateImageFunction::Attributes() const
376 {
377   return Input()->Attributes();
378 }
379 
380 // -----------------------------------------------------------------------------
X()381 inline int ExtrapolateImageFunction::X() const
382 {
383   return Input()->X();
384 }
385 
386 // -----------------------------------------------------------------------------
Y()387 inline int ExtrapolateImageFunction::Y() const
388 {
389   return Input()->Y();
390 }
391 
392 // -----------------------------------------------------------------------------
Z()393 inline int ExtrapolateImageFunction::Z() const
394 {
395   return Input()->Z();
396 }
397 
398 // -----------------------------------------------------------------------------
T()399 inline int ExtrapolateImageFunction::T() const
400 {
401   return Input()->T();
402 }
403 
404 // -----------------------------------------------------------------------------
N()405 inline int ExtrapolateImageFunction::N() const
406 {
407   return Input()->N();
408 }
409 
410 // -----------------------------------------------------------------------------
XSize()411 inline double ExtrapolateImageFunction::XSize() const
412 {
413   return Input()->XSize();
414 }
415 
416 // -----------------------------------------------------------------------------
YSize()417 inline double ExtrapolateImageFunction::YSize() const
418 {
419   return Input()->YSize();
420 }
421 
422 // -----------------------------------------------------------------------------
ZSize()423 inline double ExtrapolateImageFunction::ZSize() const
424 {
425   return Input()->ZSize();
426 }
427 
428 // -----------------------------------------------------------------------------
TSize()429 inline double ExtrapolateImageFunction::TSize() const
430 {
431   return Input()->TSize();
432 }
433 
434 // -----------------------------------------------------------------------------
435 inline double ExtrapolateImageFunction
Evaluate(double x,double y,double z,double t)436 ::Evaluate(double x, double y, double z, double t) const
437 {
438   return this->GetAsDouble(static_cast<int>(round(x)),
439                            static_cast<int>(round(y)),
440                            static_cast<int>(round(z)),
441                            static_cast<int>(round(t)));
442 }
443 
444 // -----------------------------------------------------------------------------
445 inline double ExtrapolateImageFunction
Evaluate(double x,double y,double z,double t)446 ::Evaluate(double x, double y, double z, double t)
447 {
448   return const_cast<const ExtrapolateImageFunction *>(this)->Evaluate(x, y, z, t);
449 }
450 
451 // -----------------------------------------------------------------------------
GetAsDouble(int i,int j,int k,int l)452 inline double ExtrapolateImageFunction::GetAsDouble(int i, int j, int k, int l) const
453 {
454   // Must be implemented by subclass
455   return this->_DefaultValue;
456 }
457 
458 // -----------------------------------------------------------------------------
GetAsDouble(int idx)459 inline double ExtrapolateImageFunction::GetAsDouble(int idx) const
460 {
461   int i, j, k, l;
462   Input()->IndexToVoxel(idx, i, j, k, l);
463   return this->GetAsDouble(i, j, k, l);
464 }
465 
466 // -----------------------------------------------------------------------------
467 inline void ExtrapolateImageFunction
GetAsVector(Vector & v,int i,int j,int k,int l)468 ::GetAsVector(Vector &v, int i, int j, int k, int l) const
469 {
470   // Must be implemented by subclass
471   v = Vector(N(), this->_DefaultValue);
472 }
473 
474 // -----------------------------------------------------------------------------
GetAsVector(int i,int j,int k,int l)475 inline Vector ExtrapolateImageFunction::GetAsVector(int i, int j, int k, int l) const
476 {
477   Vector v;
478   this->GetAsVector(v, i, j, k, l);
479   return v;
480 }
481 
482 // -----------------------------------------------------------------------------
GetAsVector(Vector & v,int idx)483 inline void ExtrapolateImageFunction::GetAsVector(Vector &v, int idx) const
484 {
485   int i, j, k, l;
486   Input()->IndexToVoxel(idx, i, j, k, l);
487   this->GetAsVector(v, i, j, k, l);
488 }
489 
490 // -----------------------------------------------------------------------------
GetAsVector(int idx)491 inline Vector ExtrapolateImageFunction::GetAsVector(int idx) const
492 {
493   Vector v;
494   this->GetAsVector(v, idx);
495   return v;
496 }
497 
498 // -----------------------------------------------------------------------------
IsForeground(int i,int j,int k,int l)499 inline bool ExtrapolateImageFunction::IsForeground(int i, int j, int k, int l) const
500 {
501   if (!this->Input()->HasBackgroundValue()) return true;
502   const double value = this->GetAsDouble(i, j, k, l);
503   const double bg    = this->Input()->GetBackgroundValueAsDouble();
504   return (value != bg && (!IsNaN(value) || !IsNaN(bg)));
505 }
506 
507 ////////////////////////////////////////////////////////////////////////////////
508 // Inline definitions -- GenericExtrapolateImageFunction
509 ////////////////////////////////////////////////////////////////////////////////
510 
511 // -----------------------------------------------------------------------------
512 template <class TImage>
513 inline GenericExtrapolateImageFunction<TImage>
GenericExtrapolateImageFunction()514 ::GenericExtrapolateImageFunction()
515 {
516 }
517 
518 // -----------------------------------------------------------------------------
519 template <class TImage>
520 inline GenericExtrapolateImageFunction<TImage>
~GenericExtrapolateImageFunction()521 ::~GenericExtrapolateImageFunction()
522 {
523 }
524 
525 // -----------------------------------------------------------------------------
526 template <class TImage>
527 inline void GenericExtrapolateImageFunction<TImage>
Input(const BaseImage * input)528 ::Input(const BaseImage *input)
529 {
530   ExtrapolateImageFunction::Input(dynamic_cast<const ImageType *>(input));
531   if (input && !this->_Input) {
532     cerr << this->NameOfClass() << "::Input: Invalid input image type" << endl;
533     exit(1);
534   }
535 }
536 
537 // -----------------------------------------------------------------------------
538 template <class TImage>
Input()539 inline const TImage *GenericExtrapolateImageFunction<TImage>::Input() const
540 {
541   return reinterpret_cast<const TImage *>(this->_Input);
542 }
543 
544 // -----------------------------------------------------------------------------
545 template <class TImage>
Initialize()546 inline void GenericExtrapolateImageFunction<TImage>::Initialize()
547 {
548   // Initialize base class
549   ExtrapolateImageFunction::Initialize();
550   // Check type of input image -- also done by Input(const BaseImage *),
551   //                              but just in case SetInput() has been used.
552   if (!dynamic_cast<const ImageType *>(this->_Input)) {
553     cerr << this->NameOfClass() << "::Initialize: Invalid input image type" << endl;
554     exit(1);
555   }
556 }
557 
558 // -----------------------------------------------------------------------------
559 template <class TImage>
560 inline typename GenericExtrapolateImageFunction<TImage>::VoxelType
Get(int i,int j,int k,int l)561 GenericExtrapolateImageFunction<TImage>::Get(int i, int j, int k, int l) const
562 {
563   // Must be implemented by subclass
564   return voxel_cast<VoxelType>(this->_DefaultValue);
565 }
566 
567 // -----------------------------------------------------------------------------
568 template <class TImage>
569 inline typename GenericExtrapolateImageFunction<TImage>::VoxelType
Get(int idx)570 GenericExtrapolateImageFunction<TImage>::Get(int idx) const
571 {
572   int i, j, k, l;
573   Input()->IndexToVoxel(idx, i, j, k, l);
574   return this->Get(i, j, k, l);
575 }
576 
577 // -----------------------------------------------------------------------------
578 template <class TImage>
579 inline typename GenericExtrapolateImageFunction<TImage>::VoxelType
operator()580 GenericExtrapolateImageFunction<TImage>::operator ()(int idx) const
581 {
582   return this->Get(idx);
583 }
584 
585 // -----------------------------------------------------------------------------
586 template <class TImage>
587 inline typename GenericExtrapolateImageFunction<TImage>::VoxelType
588 GenericExtrapolateImageFunction<TImage>
operator()589 ::operator ()(int i, int j, int k, int l) const
590 {
591   return this->Get(i, j, k, l);
592 }
593 
594 // -----------------------------------------------------------------------------
595 template <class TImage>
596 inline double GenericExtrapolateImageFunction<TImage>
GetAsDouble(int i,int j,int k,int l)597 ::GetAsDouble(int i, int j, int k, int l) const
598 {
599   return voxel_cast<double>(this->Get(i, j, k, l));
600 }
601 
602 // -----------------------------------------------------------------------------
603 template <class TImage>
604 inline void GenericExtrapolateImageFunction<TImage>
GetAsVector(Vector & v,int i,int j,int k,int l)605 ::GetAsVector(Vector &v, int i, int j, int k, int l) const
606 {
607   v = voxel_cast<Vector>(this->Get(i, j, k, l));
608 }
609 
610 ////////////////////////////////////////////////////////////////////////////////
611 // Inline definitions -- IndexExtrapolateImageFunction
612 ////////////////////////////////////////////////////////////////////////////////
613 
614 // -----------------------------------------------------------------------------
615 template <class TImage>
IndexExtrapolateImageFunction()616 IndexExtrapolateImageFunction<TImage>::IndexExtrapolateImageFunction()
617 :
618   _xmax(0), _ymax(0), _zmax(0), _tmax(0)
619 {
620 }
621 
622 // -----------------------------------------------------------------------------
623 template <class TImage>
~IndexExtrapolateImageFunction()624 IndexExtrapolateImageFunction<TImage>::~IndexExtrapolateImageFunction()
625 {
626 }
627 
628 // -----------------------------------------------------------------------------
629 template <class TImage>
Initialize()630 void IndexExtrapolateImageFunction<TImage>::Initialize()
631 {
632   // Initialize base class
633   GenericExtrapolateImageFunction<TImage>::Initialize();
634   // Get range of indices
635   _xmax = this->X() - 1;
636   _ymax = this->Y() - 1;
637   _zmax = this->Z() - 1;
638   _tmax = this->T() - 1;
639 }
640 
641 // -----------------------------------------------------------------------------
642 template <class TImage>
TransformX(int & i)643 void IndexExtrapolateImageFunction<TImage>::TransformX(int &i) const
644 {
645   this->TransformIndex(i, _xmax);
646 }
647 
648 // -----------------------------------------------------------------------------
649 template <class TImage>
TransformY(int & j)650 void IndexExtrapolateImageFunction<TImage>::TransformY(int &j) const
651 {
652   this->TransformIndex(j, _ymax);
653 }
654 
655 // -----------------------------------------------------------------------------
656 template <class TImage>
TransformZ(int & k)657 void IndexExtrapolateImageFunction<TImage>::TransformZ(int &k) const
658 {
659   this->TransformIndex(k, _zmax);
660 }
661 
662 // -----------------------------------------------------------------------------
663 template <class TImage>
TransformT(int & l)664 void IndexExtrapolateImageFunction<TImage>::TransformT(int &l) const
665 {
666   this->TransformIndex(l, _tmax);
667 }
668 
669 // -----------------------------------------------------------------------------
670 template <class TImage>
TransformX(int & i,int c)671 void IndexExtrapolateImageFunction<TImage>::TransformX(int &i, int c) const
672 {
673   i = c;
674   this->TransformIndex(i, _xmax);
675 }
676 
677 // -----------------------------------------------------------------------------
678 template <class TImage>
TransformY(int & j,int c)679 void IndexExtrapolateImageFunction<TImage>::TransformY(int &j, int c) const
680 {
681   j = c;
682   this->TransformIndex(j, _ymax);
683 }
684 
685 // -----------------------------------------------------------------------------
686 template <class TImage>
TransformZ(int & k,int c)687 void IndexExtrapolateImageFunction<TImage>::TransformZ(int &k, int c) const
688 {
689   k = c;
690   this->TransformIndex(k, _zmax);
691 }
692 
693 // -----------------------------------------------------------------------------
694 template <class TImage>
TransformT(int & l,int c)695 void IndexExtrapolateImageFunction<TImage>::TransformT(int &l, int c) const
696 {
697   l = c;
698   this->TransformIndex(l, _tmax);
699 }
700 
701 // -----------------------------------------------------------------------------
702 template <class TImage>
Transform(int & i,int & j)703 void IndexExtrapolateImageFunction<TImage>::Transform(int &i, int &j) const
704 {
705   TransformX(i);
706   TransformY(j);
707 }
708 
709 // -----------------------------------------------------------------------------
710 template <class TImage>
Transform(int & i,int & j,int & k)711 void IndexExtrapolateImageFunction<TImage>::Transform(int &i, int &j, int &k) const
712 {
713   TransformX(i);
714   TransformY(j);
715   TransformZ(k);
716 }
717 
718 // -----------------------------------------------------------------------------
719 template <class TImage>
Transform(int & i,int & j,int & k,int & l)720 void IndexExtrapolateImageFunction<TImage>::Transform(int &i, int &j, int &k, int &l) const
721 {
722   TransformX(i);
723   TransformY(j);
724   TransformZ(k);
725   TransformT(l);
726 }
727 
728 // -----------------------------------------------------------------------------
729 template <class TImage>
730 inline bool IndexExtrapolateImageFunction<TImage>
IsForeground(int i,int j,int k,int l)731 ::IsForeground(int i, int j, int k, int l) const
732 {
733   Transform(i, j, k, l);
734   return this->Input()->IsForeground(i, j, k, l);
735 }
736 
737 // -----------------------------------------------------------------------------
738 template <class TImage>
739 inline typename IndexExtrapolateImageFunction<TImage>::VoxelType
Get(int i,int j,int k,int l)740 IndexExtrapolateImageFunction<TImage>::Get(int i, int j, int k, int l) const
741 {
742   Transform(i, j, k, l);
743   return this->Input()->Get(i, j, k, l);
744 }
745 
746 
747 } // namespace mirtk
748 
749 ////////////////////////////////////////////////////////////////////////////////
750 // Extrapolation functions
751 ////////////////////////////////////////////////////////////////////////////////
752 
753 #include "mirtk/ConstExtrapolateImageFunction.h"
754 #include "mirtk/ConstExtrapolateImageFunctionWithPeriodicTime.h"
755 #include "mirtk/NearestNeighborExtrapolateImageFunction.h"
756 #include "mirtk/RepeatExtrapolateImageFunction.h"
757 #include "mirtk/MirrorExtrapolateImageFunction.h"
758 
759 ////////////////////////////////////////////////////////////////////////////////
760 // Instantiation
761 ////////////////////////////////////////////////////////////////////////////////
762 
763 namespace mirtk {
764 
765 
766 // -----------------------------------------------------------------------------
767 template <class TImage>
768 GenericExtrapolateImageFunction<TImage> *
769 GenericExtrapolateImageFunction<TImage>
New(enum ExtrapolationMode mode,const TImage * image)770 ::New(enum ExtrapolationMode mode, const TImage *image)
771 {
772   GenericExtrapolateImageFunction<TImage> *p = NULL;
773   switch (mode) {
774     case Extrapolation_None:   { p = NULL;                                                         break; }
775     case Extrapolation_Const:  { p = new GenericConstExtrapolateImageFunction          <TImage>(); break; }
776     case Extrapolation_NN:     { p = new GenericNearestNeighborExtrapolateImageFunction<TImage>(); break; }
777     case Extrapolation_Repeat: { p = new GenericRepeatExtrapolateImageFunction         <TImage>(); break; }
778     case Extrapolation_Mirror: { p = new GenericMirrorExtrapolateImageFunction         <TImage>(); break; }
779     case Extrapolation_ConstWithPeriodicTime:
780       p = new GenericConstExtrapolateImageFunctionWithPeriodicTime<TImage>();
781       break;
782     default:
783    	  cerr << "GenericExtrapolateImageFunction::New: Unknown extrapolation mode: " << mode << endl;
784       exit(1);
785   }
786   if (p) p->Input(image);
787   return p;
788 }
789 
790 
791 } // namespace mirtk
792 
793 #endif // MIRTK_ExtrapolateImageFunction_H
794