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