CubicBSplineInterpolateImageFunction.hxx
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_CubicBSplineInterpolateImageFunction_HXX
21 #define MIRTK_CubicBSplineInterpolateImageFunction_HXX
22 
23 #include "mirtk/CubicBSplineInterpolateImageFunction.h"
24 
25 #include "mirtk/Math.h"
26 #include "mirtk/InterpolateImageFunction.hxx"
27 #include "mirtk/ImageToInterpolationCoefficients.h"
28 
29 
30 namespace mirtk {
31 
32 
33 // =============================================================================
34 // Construction/Destruction
35 // =============================================================================
36 
37 // -----------------------------------------------------------------------------
38 template <class TImage>
41 :
42  _UseInputCoefficients(false),
43  _InfiniteCoefficient(nullptr)
44 {
45  // Default extrapolation mode is to apply the mirror boundary condition
46  // which is also assumed when converting an input image to spline coefficients
47  this->Extrapolator(ExtrapolatorType::New(Extrapolation_Mirror), true);
48 }
49 
50 // -----------------------------------------------------------------------------
51 template <class TImage>
54 {
55  delete _InfiniteCoefficient;
56 }
57 
58 // -----------------------------------------------------------------------------
59 template <class TImage>
61 ::Initialize(bool coeff)
62 {
63  // Initialize base class
64  Superclass::Initialize(coeff);
65 
66  // Domain on which cubic B-spline interpolation is defined
67  const double margin = 2.0;
68  switch (this->NumberOfDimensions()) {
69  case 4:
70  this->_t1 = fdec(margin);
71  this->_t2 = this->Input()->T() - margin - 1;
72  case 3:
73  this->_z1 = fdec(margin);
74  this->_z2 = this->Input()->Z() - margin - 1;
75  default:
76  this->_y1 = fdec(margin);
77  this->_y2 = this->Input()->Y() - margin - 1;
78  this->_x1 = fdec(margin);
79  this->_x2 = this->Input()->X() - margin - 1;
80  }
81 
82  // Initialize coefficient image
83  RealType *data = nullptr;
84  _UseInputCoefficients = coeff;
85  if (_UseInputCoefficients && this->Input()->GetDataType() == voxel_info<RealType>::type()) {
86  data = reinterpret_cast<RealType *>(const_cast<void *>(this->Input()->GetDataPointer()));
87  }
88  _Coefficient.Initialize(this->Input()->Attributes(), data);
89  this->Update();
90 
91  // Initialize infinite coefficient image (i.e., extrapolator)
92  if (!_InfiniteCoefficient || _InfiniteCoefficient->ExtrapolationMode() != this->ExtrapolationMode()) {
93  delete _InfiniteCoefficient;
94  _InfiniteCoefficient = CoefficientExtrapolator::New(this->ExtrapolationMode(), &_Coefficient);
95  }
96  if (_InfiniteCoefficient) {
97  _InfiniteCoefficient->Input(&_Coefficient);
98  _InfiniteCoefficient->Initialize();
99  }
100 
101  // Compute strides for fast iteration over coefficient image
102  //_s1 = 1;
103  _s2 = this->Input()->X() - 4;
104  _s3 = (this->Input()->Y() - 4) * this->Input()->X();
105  _s4 = (this->Input()->Z() - 4) * this->Input()->Y() * this->Input()->X();
106 }
107 
108 
109 // -----------------------------------------------------------------------------
110 template <class TImage>
112 {
113  if (_Coefficient.GetDataPointer() != this->Input()->GetDataPointer()) {
114  _Coefficient = *(this->Input());
115  if (!_UseInputCoefficients) {
116  Real poles[2];
117  int npoles;
118  SplinePoles(3, poles, npoles);
120  switch (this->NumberOfDimensions()) {
121  case 4: ConvertToInterpolationCoefficientsT(_Coefficient, poles, npoles);
122  case 3: ConvertToInterpolationCoefficientsZ(_Coefficient, poles, npoles);
123  default: ConvertToInterpolationCoefficientsY(_Coefficient, poles, npoles);
124  ConvertToInterpolationCoefficientsX(_Coefficient, poles, npoles);
125  }
126  }
127  }
128 }
129 
130 // =============================================================================
131 // Domain checks
132 // =============================================================================
133 
134 // -----------------------------------------------------------------------------
135 template <class TImage>
137 ::BoundingInterval(double x, int &i, int &I) const
138 {
139  i = ifloor(x), I = i + 3;
140 }
141 
142 // =============================================================================
143 // Evaluation
144 // =============================================================================
145 
146 // -----------------------------------------------------------------------------
147 template <class TImage>
148 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
150 ::Get2D(double x, double y, double z, double t) const
151 {
152  int i = ifloor(x);
153  int j = ifloor(y);
154  int k = iround(z);
155  int l = iround(t);
156 
157  if (k < 0 || k >= _Coefficient.Z() ||
158  l < 0 || l >= _Coefficient.T()) {
159  return voxel_cast<VoxelType>(this->DefaultValue());
160  }
161 
162  Real wx[4]; Kernel::Weights(Real(x - i), wx);
163  Real wy[4]; Kernel::Weights(Real(y - j), wy);
164 
165  --i, --j;
166 
167  RealType val = voxel_cast<RealType>(0);
168 
169  int ia, jb;
170  for (int b = 0; b <= 3; ++b) {
171  jb = j + b;
172  DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
173  for (int a = 0; a <= 3; ++a) {
174  ia = i + a;
175  DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
176  val += wx[a] * wy[b] * _Coefficient(ia, jb, k, l);
177  }
178  }
179 
180  return voxel_cast<VoxelType>(val);
181 }
182 
183 // -----------------------------------------------------------------------------
184 template <class TImage>
185 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
187 ::GetWithPadding2D(double x, double y, double z, double t) const
188 {
189  int i = ifloor(x);
190  int j = ifloor(y);
191  int k = iround(z);
192  int l = iround(t);
193 
194  if (k < 0 || k >= _Coefficient.Z() ||
195  l < 0 || l >= _Coefficient.T()) {
196  return voxel_cast<VoxelType>(this->DefaultValue());
197  }
198 
199  Real wx[4]; Kernel::Weights(Real(x - i), wx);
200  Real wy[4]; Kernel::Weights(Real(y - j), wy);
201 
202  --i, --j;
203 
204  RealType val = voxel_cast<RealType>(0);
205  Real fgw(0), bgw(0), w;
206 
207  int ia, jb;
208  for (int b = 0; b <= 3; ++b) {
209  jb = j + b;
210  DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
211  for (int a = 0; a <= 3; ++a) {
212  ia = i + a;
213  DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
214  w = wx[a] * wy[b];
215  val += w * _Coefficient(ia, jb, k, l);
216  if (this->Input()->IsInsideForeground(i + a, j + b, k, l)) {
217  fgw += w;
218  } else {
219  bgw += w;
220  }
221  }
222  }
223 
224  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
225  val = voxel_cast<RealType>(this->DefaultValue());
226  }
227  return voxel_cast<VoxelType>(val);
228 }
229 
230 // -----------------------------------------------------------------------------
231 template <class TImage> template <class TCoefficient>
232 inline typename TCoefficient::VoxelType
234 ::Get2D(const TCoefficient *coeff, double x, double y, double z, double t) const
235 {
236  typedef typename TCoefficient::VoxelType VoxelType;
237  typedef typename TCoefficient::RealType RealType;
238 
239  int i = ifloor(x);
240  int j = ifloor(y);
241  int k = iround(z);
242  int l = iround(t);
243 
244  Real wx[4]; Kernel::Weights(Real(x - i), wx);
245  Real wy[4]; Kernel::Weights(Real(y - j), wy);
246 
247  --i, --j;
248 
249  RealType val = voxel_cast<RealType>(0);
250 
251  int jb;
252  for (int b = 0; b <= 3; ++b) {
253  jb = j + b;
254  val += wx[0] * wy[b] * voxel_cast<RealType>(coeff->Get(i, jb, k, l));
255  val += wx[1] * wy[b] * voxel_cast<RealType>(coeff->Get(i+1, jb, k, l));
256  val += wx[2] * wy[b] * voxel_cast<RealType>(coeff->Get(i+2, jb, k, l));
257  val += wx[3] * wy[b] * voxel_cast<RealType>(coeff->Get(i+3, jb, k, l));
258  }
259 
260  return voxel_cast<VoxelType>(val);
261 }
262 
263 // -----------------------------------------------------------------------------
264 template <class TImage> template <class TOtherImage, class TCoefficient>
265 inline typename TCoefficient::VoxelType
267 ::GetWithPadding2D(const TOtherImage *input, const TCoefficient *coeff,
268  double x, double y, double z, double t) const
269 {
270  typedef typename TCoefficient::VoxelType VoxelType;
271  typedef typename TCoefficient::RealType RealType;
272 
273  int i = ifloor(x);
274  int j = ifloor(y);
275  int k = iround(z);
276  int l = iround(t);
277 
278  Real wx[4]; Kernel::Weights(Real(x - i), wx);
279  Real wy[4]; Kernel::Weights(Real(y - j), wy);
280 
281  --i, --j;
282 
283  RealType val = voxel_cast<RealType>(0);
284  Real fgw(0), bgw(0), w;
285 
286  int ia, jb;
287  for (int b = 0; b <= 3; ++b) {
288  jb = j + b;
289  for (int a = 0; a <= 3; ++a) {
290  ia = i + a;
291  w = wx[0] * wy[b];
292  val += w * voxel_cast<RealType>(coeff->Get(ia, jb, k, l));
293  if (input->IsForeground(ia, jb, k, l)) {
294  fgw += w;
295  } else {
296  bgw += w;
297  }
298  }
299  }
300 
301  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
302  val = voxel_cast<RealType>(this->DefaultValue());
303  }
304  return voxel_cast<VoxelType>(val);
305 }
306 
307 // -----------------------------------------------------------------------------
308 template <class TImage>
309 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
311 ::Get3D(double x, double y, double z, double t) const
312 {
313  int i = ifloor(x);
314  int j = ifloor(y);
315  int k = ifloor(z);
316  int l = iround(t);
317 
318  if (l < 0 || l >= _Coefficient.T()) {
319  return voxel_cast<VoxelType>(this->DefaultValue());
320  }
321 
322  Real wx[4]; Kernel::Weights(Real(x - i), wx);
323  Real wy[4]; Kernel::Weights(Real(y - j), wy);
324  Real wz[4]; Kernel::Weights(Real(z - k), wz);
325 
326  --i, --j, --k;
327 
328  RealType val = voxel_cast<RealType>(0);
329  Real wyz;
330 
331  int ia, jb, kc;
332  for (int c = 0; c <= 3; ++c) {
333  kc = k + c;
334  DefaultExtrapolator::Apply(kc, _Coefficient.Z() - 1);
335  for (int b = 0; b <= 3; ++b) {
336  jb = j + b;
337  DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
338  wyz = wy[b] * wz[c];
339  for (int a = 0; a <= 3; ++a) {
340  ia = i + a;
341  DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
342  val += wx[a] * wyz * _Coefficient(ia, jb, kc, l);
343  }
344  }
345  }
346 
347  return voxel_cast<VoxelType>(val);
348 }
349 
350 // -----------------------------------------------------------------------------
351 template <class TImage>
352 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
354 ::GetWithPadding3D(double x, double y, double z, double t) const
355 {
356  int i = ifloor(x);
357  int j = ifloor(y);
358  int k = ifloor(z);
359  int l = iround(t);
360 
361  if (l < 0 || l >= _Coefficient.T()) {
362  return voxel_cast<VoxelType>(this->DefaultValue());
363  }
364 
365  Real wx[4]; Kernel::Weights(Real(x - i), wx);
366  Real wy[4]; Kernel::Weights(Real(y - j), wy);
367  Real wz[4]; Kernel::Weights(Real(z - k), wz);
368 
369  --i, --j, --k;
370 
371  RealType val = voxel_cast<RealType>(0);
372  Real fgw(0), bgw(0), wyz, w;
373 
374  int ia, jb, kc;
375  for (int c = 0; c <= 3; ++c) {
376  kc = k + c;
377  for (int b = 0; b <= 3; ++b) {
378  jb = j + b;
379  wyz = wy[b] * wz[c];
380  for (int a = 0; a <= 3; ++a) {
381  ia = i + a;
382  w = wx[a] * wyz;
383  val += w * _Coefficient(ia, jb, kc, l);
384  if (this->Input()->IsInsideForeground(ia, jb, kc, l)) {
385  fgw += w;
386  } else {
387  bgw += w;
388  }
389  }
390  }
391  }
392 
393  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
394  val = voxel_cast<RealType>(this->DefaultValue());
395  }
396  return voxel_cast<VoxelType>(val);
397 }
398 
399 // -----------------------------------------------------------------------------
400 template <class TImage> template <class TCoefficient>
401 inline typename TCoefficient::VoxelType
403 ::Get3D(const TCoefficient *coeff, double x, double y, double z, double t) const
404 {
405  typedef typename TCoefficient::VoxelType VoxelType;
406  typedef typename TCoefficient::RealType RealType;
407 
408  int i = ifloor(x);
409  int j = ifloor(y);
410  int k = ifloor(z);
411  int l = iround(t);
412 
413  Real wx[4]; Kernel::Weights(Real(x - i), wx);
414  Real wy[4]; Kernel::Weights(Real(y - j), wy);
415  Real wz[4]; Kernel::Weights(Real(z - k), wz);
416 
417  --i, --j, --k;
418 
419  RealType val = voxel_cast<RealType>(0);
420 
421  int jb, kc;
422  Real wyz;
423  for (int c = 0; c <= 3; ++c) {
424  kc = k + c;
425  for (int b = 0; b <= 3; ++b) {
426  jb = j + b;
427  wyz = wy[b] * wz[c];
428  val += wx[0] * wyz * voxel_cast<RealType>(coeff->Get(i, jb, kc, l));
429  val += wx[1] * wyz * voxel_cast<RealType>(coeff->Get(i+1, jb, kc, l));
430  val += wx[2] * wyz * voxel_cast<RealType>(coeff->Get(i+2, jb, kc, l));
431  val += wx[3] * wyz * voxel_cast<RealType>(coeff->Get(i+3, jb, kc, l));
432  }
433  }
434 
435  return voxel_cast<VoxelType>(val);
436 }
437 
438 // -----------------------------------------------------------------------------
439 template <class TImage> template <class TOtherImage, class TCoefficient>
440 inline typename TCoefficient::VoxelType
442 ::GetWithPadding3D(const TOtherImage *input, const TCoefficient *coeff,
443  double x, double y, double z, double t) const
444 {
445  typedef typename TCoefficient::VoxelType VoxelType;
446  typedef typename TCoefficient::RealType RealType;
447 
448  int i = ifloor(x);
449  int j = ifloor(y);
450  int k = ifloor(z);
451  int l = iround(t);
452 
453  Real wx[4]; Kernel::Weights(Real(x - i), wx);
454  Real wy[4]; Kernel::Weights(Real(y - j), wy);
455  Real wz[4]; Kernel::Weights(Real(z - k), wz);
456 
457  --i, --j, --k;
458 
459  RealType val = voxel_cast<RealType>(0);
460  Real fgw(0), bgw(0), wyz, w;
461 
462  int ia, jb, kc;
463  for (int c = 0; c <= 3; ++c) {
464  kc = k + c;
465  for (int b = 0; b <= 3; ++b) {
466  jb = j + b;
467  wyz = wy[b] * wz[c];
468  for (int a = 0; a <= 3; ++a) {
469  ia = i + a;
470  w = wx[0] * wyz;
471  val += w * voxel_cast<RealType>(coeff->Get(ia, jb, kc, l));
472  if (input->IsForeground(ia, jb, kc, l)) {
473  fgw += w;
474  } else {
475  bgw += w;
476  }
477  }
478  }
479  }
480 
481  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
482  val = voxel_cast<RealType>(this->DefaultValue());
483  }
484  return voxel_cast<VoxelType>(val);
485 }
486 
487 // -----------------------------------------------------------------------------
488 template <class TImage>
489 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
491 ::Get4D(double x, double y, double z, double t) const
492 {
493  int i = ifloor(x);
494  int j = ifloor(y);
495  int k = ifloor(z);
496  int l = ifloor(t);
497 
498  Real wx[4]; Kernel::Weights(Real(x - i), wx);
499  Real wy[4]; Kernel::Weights(Real(y - j), wy);
500  Real wz[4]; Kernel::Weights(Real(z - k), wz);
501  Real wt[4]; Kernel::Weights(Real(t - l), wt);
502 
503  --i, --j, --k, --l;
504 
505  RealType val = voxel_cast<RealType>(0);
506  Real wzt, wyzt;
507 
508  int ia, jb, kc, ld;
509  for (int d = 0; d <= 3; ++d) {
510  ld = l + d;
511  DefaultExtrapolator::Apply(ld, _Coefficient.T() - 1);
512  for (int c = 0; c <= 3; ++c) {
513  kc = k + c;
514  DefaultExtrapolator::Apply(kc, _Coefficient.Z() - 1);
515  wzt = wz[c] * wt[d];
516  for (int b = 0; b <= 3; ++b) {
517  jb = j + b;
518  DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
519  wyzt = wy[b] * wzt;
520  for (int a = 0; a <= 3; ++a) {
521  ia = i + a;
522  DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
523  val += wx[a] * wyzt * _Coefficient(ia, jb, kc, ld);
524  }
525  }
526  }
527  }
528 
529  return voxel_cast<VoxelType>(val);
530 }
531 
532 // -----------------------------------------------------------------------------
533 template <class TImage>
534 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
536 ::GetWithPadding4D(double x, double y, double z, double t) const
537 {
538  int i = ifloor(x);
539  int j = ifloor(y);
540  int k = ifloor(z);
541  int l = ifloor(t);
542 
543  Real wx[4]; Kernel::Weights(Real(x - i), wx);
544  Real wy[4]; Kernel::Weights(Real(y - j), wy);
545  Real wz[4]; Kernel::Weights(Real(z - k), wz);
546  Real wt[4]; Kernel::Weights(Real(t - l), wt);
547 
548  --i, --j, --k, --l;
549 
550  RealType val = voxel_cast<RealType>(0);
551  Real fgw(0), bgw(0), wzt, wyzt, w;
552 
553  int ia, jb, kc, ld;
554  for (int d = 0; d <= 3; ++d) {
555  ld = l + d;
556  for (int c = 0; c <= 3; ++c) {
557  kc = k + c;
558  wzt = wz[c] * wt[d];
559  for (int b = 0; b <= 3; ++b) {
560  jb = j + b;
561  wyzt = wy[b] * wzt;
562  for (int a = 0; a <= 3; ++a) {
563  ia = i + a;
564  w = wx[a] * wyzt;
565  val += w * _Coefficient(ia, jb, kc, ld);
566  if (this->Input()->IsInsideForeground(ia, jb, kc, ld)) {
567  fgw += w;
568  } else {
569  bgw += w;
570  }
571  }
572  }
573  }
574  }
575 
576  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
577  val = voxel_cast<RealType>(this->DefaultValue());
578  }
579  return voxel_cast<VoxelType>(val);
580 }
581 
582 // -----------------------------------------------------------------------------
583 template <class TImage> template <class TCoefficient>
584 inline typename TCoefficient::VoxelType
586 ::Get4D(const TCoefficient *coeff, double x, double y, double z, double t) const
587 {
588  typedef typename TCoefficient::VoxelType VoxelType;
589  typedef typename TCoefficient::RealType RealType;
590 
591  int i = ifloor(x);
592  int j = ifloor(y);
593  int k = ifloor(z);
594  int l = ifloor(t);
595 
596  Real wx[4]; Kernel::Weights(Real(x - i), wx);
597  Real wy[4]; Kernel::Weights(Real(y - j), wy);
598  Real wz[4]; Kernel::Weights(Real(z - k), wz);
599  Real wt[4]; Kernel::Weights(Real(t - l), wt);
600 
601  --i, --j, --k, --l;
602 
603  RealType val = voxel_cast<RealType>(0);
604 
605  int jb, kc, ld;
606  Real wzt, wyzt;
607  for (int d = 0; d <= 3; ++d) {
608  ld = l + d;
609  for (int c = 0; c <= 3; ++c) {
610  kc = k + c;
611  wzt = wz[c] * wt[d];
612  for (int b = 0; b <= 3; ++b) {
613  jb = j + b;
614  wyzt = wy[b] * wzt;
615  val += wx[0] * wyzt * voxel_cast<RealType>(coeff->Get(i, jb, kc, ld));
616  val += wx[1] * wyzt * voxel_cast<RealType>(coeff->Get(i+1, jb, kc, ld));
617  val += wx[2] * wyzt * voxel_cast<RealType>(coeff->Get(i+2, jb, kc, ld));
618  val += wx[3] * wyzt * voxel_cast<RealType>(coeff->Get(i+3, jb, kc, ld));
619  }
620  }
621  }
622 
623  return voxel_cast<VoxelType>(val);
624 }
625 
626 // -----------------------------------------------------------------------------
627 template <class TImage> template <class TOtherImage, class TCoefficient>
628 inline typename TCoefficient::VoxelType
630 ::GetWithPadding4D(const TOtherImage *input, const TCoefficient *coeff,
631  double x, double y, double z, double t) const
632 {
633  int i = ifloor(x);
634  int j = ifloor(y);
635  int k = ifloor(z);
636  int l = ifloor(t);
637 
638  Real wx[4]; Kernel::Weights(Real(x - i), wx);
639  Real wy[4]; Kernel::Weights(Real(y - j), wy);
640  Real wz[4]; Kernel::Weights(Real(z - k), wz);
641  Real wt[4]; Kernel::Weights(Real(t - l), wt);
642 
643  --i, --j, --k, --l;
644 
645  RealType val = voxel_cast<RealType>(0);
646  Real fgw(0), bgw(0), wzt, wyzt, w;
647 
648  int ia, jb, kc, ld;
649  for (int d = 0; d <= 3; ++d) {
650  ld = l + d;
651  for (int c = 0; c <= 3; ++c) {
652  kc = k + c;
653  wzt = wz[c] + wt[d];
654  for (int b = 0; b <= 3; ++b) {
655  jb = j + b;
656  wyzt = wy[b] * wzt;
657  for (int a = 0; a <= 3; ++a) {
658  ia = i + a;
659  w = wx[0] * wyzt;
660  val += w * voxel_cast<RealType>(coeff->Get(ia, jb, kc, ld));
661  if (input->IsForeground(ia, jb, kc, ld)) {
662  fgw += w;
663  } else {
664  bgw += w;
665  }
666  }
667  }
668  }
669  }
670 
671  if (bgw > fgw || AreEqual(bgw, fgw, 1e-3)) {
672  val = voxel_cast<RealType>(this->DefaultValue());
673  }
674  return voxel_cast<VoxelType>(val);
675 }
676 
677 // -----------------------------------------------------------------------------
678 template <class TImage>
679 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
681 ::Get(double x, double y, double z, double t) const
682 {
683  switch (this->NumberOfDimensions()) {
684  case 3: return Get3D(x, y, z, t);
685  case 2: return Get2D(x, y, z, t);
686  default: return Get4D(x, y, z, t);
687  }
688 }
689 
690 // -----------------------------------------------------------------------------
691 template <class TImage>
692 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
694 ::GetWithPadding(double x, double y, double z, double t) const
695 {
696  switch (this->NumberOfDimensions()) {
697  case 3: return GetWithPadding3D(x, y, z, t);
698  case 2: return GetWithPadding2D(x, y, z, t);
699  default: return GetWithPadding4D(x, y, z, t);
700  }
701 }
702 
703 // -----------------------------------------------------------------------------
704 template <class TImage> template <class TOtherImage>
705 inline typename TOtherImage::VoxelType
707 ::Get(const TOtherImage *coeff, double x, double y, double z, double t) const
708 {
709  switch (this->NumberOfDimensions()) {
710  case 3: return Get3D(coeff, x, y, z, t);
711  case 2: return Get2D(coeff, x, y, z, t);
712  default: return Get4D(coeff, x, y, z, t);
713  }
714 }
715 
716 // -----------------------------------------------------------------------------
717 template <class TImage> template <class TOtherImage, class TCoefficient>
718 inline typename TCoefficient::VoxelType
720 ::GetWithPadding(const TOtherImage *input, const TCoefficient *coeff,
721  double x, double y, double z, double t) const
722 {
723  switch (this->NumberOfDimensions()) {
724  case 3: return GetWithPadding3D(input, coeff, x, y, z, t);
725  case 2: return GetWithPadding2D(input, coeff, x, y, z, t);
726  default: return GetWithPadding4D(input, coeff, x, y, z, t);
727  }
728 }
729 
730 // -----------------------------------------------------------------------------
731 template <class TImage>
732 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
734 ::GetInside2D(double x, double y, double z, double t) const
735 {
736  int i = ifloor(x);
737  int j = ifloor(y);
738  int k = iround(z);
739  int l = iround(t);
740 
741  Real wx[4]; Kernel::Weights(Real(x - i), wx);
742  Real wy[4]; Kernel::Weights(Real(y - j), wy);
743 
744  --i, --j;
745 
746  RealType val = voxel_cast<RealType>(0);
747  const RealType *coeff = _Coefficient.Data(i, j, k, l);
748 
749  for (int b = 0; b <= 3; ++b, coeff += _s2) {
750  val += wx[0] * wy[b] * (*coeff), ++coeff;
751  val += wx[1] * wy[b] * (*coeff), ++coeff;
752  val += wx[2] * wy[b] * (*coeff), ++coeff;
753  val += wx[3] * wy[b] * (*coeff), ++coeff;
754  }
755 
756  return voxel_cast<VoxelType>(val);
757 }
758 
759 // -----------------------------------------------------------------------------
760 template <class TImage>
761 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
763 ::GetInside3D(double x, double y, double z, double t) const
764 {
765  int i = ifloor(x);
766  int j = ifloor(y);
767  int k = ifloor(z);
768  int l = iround(t);
769 
770  Real wx[4]; Kernel::Weights(Real(x - i), wx);
771  Real wy[4]; Kernel::Weights(Real(y - j), wy);
772  Real wz[4]; Kernel::Weights(Real(z - k), wz);
773 
774  --i, --j, --k;
775 
776  RealType val = voxel_cast<RealType>(0);
777  const RealType *coeff = _Coefficient.Data(i, j, k, l);
778 
779  Real wyz;
780  for (int c = 0; c <= 3; ++c, coeff += _s3) {
781  for (int b = 0; b <= 3; ++b, coeff += _s2) {
782  wyz = wy[b] * wz[c];
783  val += wx[0] * wyz * (*coeff), ++coeff;
784  val += wx[1] * wyz * (*coeff), ++coeff;
785  val += wx[2] * wyz * (*coeff), ++coeff;
786  val += wx[3] * wyz * (*coeff), ++coeff;
787  }
788  }
789 
790  return voxel_cast<VoxelType>(val);
791 }
792 
793 // -----------------------------------------------------------------------------
794 template <class TImage>
795 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
797 ::GetInside4D(double x, double y, double z, double t) const
798 {
799  int i = ifloor(x);
800  int j = ifloor(y);
801  int k = ifloor(z);
802  int l = ifloor(t);
803 
804  Real wx[4]; Kernel::Weights(Real(x - i), wx);
805  Real wy[4]; Kernel::Weights(Real(y - j), wy);
806  Real wz[4]; Kernel::Weights(Real(z - k), wz);
807  Real wt[4]; Kernel::Weights(Real(t - l), wt);
808 
809  --i, --j, --k, --l;
810 
811  RealType val = voxel_cast<RealType>(0);
812  const RealType *coeff = _Coefficient.Data(i, j, k, l);
813 
814  Real wzt, wyzt;
815  for (int d = 0; d <= 3; ++d, coeff += _s4) {
816  for (int c = 0; c <= 3; ++c, coeff += _s3) {
817  wzt = wz[c] * wt[d];
818  for (int b = 0; b <= 3; ++b, coeff += _s2) {
819  wyzt = wy[b] * wzt;
820  val += wx[0] * wyzt * (*coeff), ++coeff;
821  val += wx[1] * wyzt * (*coeff), ++coeff;
822  val += wx[2] * wyzt * (*coeff), ++coeff;
823  val += wx[3] * wyzt * (*coeff), ++coeff;
824  }
825  }
826  }
827 
828  return voxel_cast<VoxelType>(val);
829 }
830 
831 // -----------------------------------------------------------------------------
832 template <class TImage>
833 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
835 ::GetInside(double x, double y, double z, double t) const
836 {
837  // Use faster coefficient iteration than Get(Coefficient(), x, y, z, t)
838  switch (this->NumberOfDimensions()) {
839  case 3: return GetInside3D(x, y, z, t);
840  case 2: return GetInside2D(x, y, z, t);
841  default: return GetInside4D(x, y, z, t);
842  }
843 }
844 
845 // -----------------------------------------------------------------------------
846 template <class TImage>
847 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
849 ::GetOutside(double x, double y, double z, double t) const
850 {
851  if (_InfiniteCoefficient) {
852  return voxel_cast<VoxelType>(Get(_InfiniteCoefficient, x, y, z, t));
853  } else {
854  return Get(x, y, z, t);
855  }
856 }
857 
858 // -----------------------------------------------------------------------------
859 template <class TImage>
860 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
862 ::GetWithPaddingInside(double x, double y, double z, double t) const
863 {
864  switch (this->NumberOfDimensions()) {
865  case 3: return voxel_cast<VoxelType>(GetWithPadding3D(this->Input(), &_Coefficient, x, y, z, t));
866  case 2: return voxel_cast<VoxelType>(GetWithPadding2D(this->Input(), &_Coefficient, x, y, z, t));
867  default: return voxel_cast<VoxelType>(GetWithPadding4D(this->Input(), &_Coefficient, x, y, z, t));
868  }
869 }
870 
871 // -----------------------------------------------------------------------------
872 template <class TImage>
873 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
875 ::GetWithPaddingOutside(double x, double y, double z, double t) const
876 {
877  if (this->Extrapolator() && _InfiniteCoefficient) {
878  return voxel_cast<VoxelType>(GetWithPadding(this->Extrapolator(), _InfiniteCoefficient, x, y, z, t));
879  } else {
880  return GetWithPadding(x, y, z, t);
881  }
882 }
883 
884 
885 } // namespace mirtk
886 
887 #endif // MIRTK_CubicBSplineInterpolateImageFunction_HXX
virtual VoxelType GetInside2D(double, double, double=0, double=0) const
Evaluate generic 2D image without handling boundary conditions.
void SplinePoles(int degree, TReal pole[2], int &npoles)
Recover spline poles from a lookup table.
VoxelType Get(double, double, double=0, double=0) const
string Get(const ParameterList &params, string name)
Get parameter value from parameters list.
Definition: Object.h:202
virtual VoxelType GetInside4D(double, double, double=0, double=0) const
Evaluate generic 4D image without handling boundary conditions.
virtual VoxelType GetWithPaddingInside(double, double, double=0, double=0) const
void FillBackgroundBeforeConversionToSplineCoefficients(GenericImage< TData > &image)
Fill background by front propagation of foreground.
MIRTKCU_API int ifloor(T x)
Round floating-point value to next smaller integer and cast to int.
Definition: Math.h:154
MIRTKCU_API double fdec(double f)
Definition: Math.h:188
Definition: IOConfig.h:41
virtual VoxelType GetInside(double, double, double=0, double=0) const
VoxelType Get2D(double, double, double=0, double=0) const
VoxelType GetWithPadding3D(double, double, double=0, double=0) const
virtual VoxelType GetWithPadding(double, double, double=0, double=0) const
VoxelType Get4D(double, double, double=0, double=0) const
ExtrapolationMode
Image extrapolation modes.
virtual VoxelType GetWithPaddingOutside(double, double, double=0, double=0) const
MIRTKCU_API bool AreEqual(double a, double b, double tol=1e-12)
Determine equality of two floating point numbers.
Definition: Math.h:115
VoxelType Get3D(double, double, double=0, double=0) const
VoxelType GetWithPadding4D(double, double, double=0, double=0) const
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
Definition: Math.h:170
virtual VoxelType GetOutside(double, double, double=0, double=0) const
Evaluate generic image at an arbitrary location (in pixels)
VoxelType GetWithPadding2D(double, double, double=0, double=0) const
virtual VoxelType GetInside3D(double, double, double=0, double=0) const
Evaluate generic 3D image without handling boundary conditions.