20 #ifndef MIRTK_CSplineInterpolateImageFunction_HXX 21 #define MIRTK_CSplineInterpolateImageFunction_HXX 23 #include "mirtk/CSplineInterpolateImageFunction.h" 25 #include "mirtk/Math.h" 26 #include "mirtk/VoxelCast.h" 27 #include "mirtk/InterpolateImageFunction.hxx" 38 template <
class TImage>
39 inline typename GenericCSplineInterpolateImageFunction<TImage>::Real
42 const Real xi = abs(x);
43 const Real xii = xi * xi;
44 const Real xiii = xii * xi;
45 if (xi < 1)
return xiii - 2 * xii + 1;
46 else if (xi < 2)
return -xiii + 5 * xii - 8 * xi + 4;
55 template <
class TImage>
62 template <
class TImage>
69 template <
class TImage>
73 Superclass::Initialize(coeff);
76 switch (this->NumberOfDimensions()) {
79 this->_t2 = this->Input()->T() - 3;
82 this->_z2 = this->Input()->Z() - 3;
85 this->_y2 = this->Input()->Y() - 3;
87 this->_x2 = this->Input()->X() - 3;
96 template <
class TImage>
100 i =
ifloor(x) - 1, I = i + 3;
108 template <
class TImage>
109 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
111 ::Get2D(
double x,
double y,
double z,
double t)
const 118 if (k < 0 || k >= this->Input()->Z() ||
119 l < 0 || l >= this->Input()->T()) {
120 return voxel_cast<VoxelType>(this->DefaultValue());
123 const int i1 = i - 1;
124 const int j1 = j - 1;
125 const int i2 = i + 2;
126 const int j2 = j + 2;
128 RealType val = voxel_cast<RealType>(0);
131 for (j = j1; j <= j2; ++j) {
132 if (0 <= j && j < this->Input()->Y()) {
133 wy = CSpline(Real(y - j));
134 for (i = i1; i <= i2; ++i) {
135 if (0 <= i && i < this->Input()->X()) {
136 w = CSpline(Real(x - i)) * wy;
137 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
144 if (nrm > 1e-3) val /= nrm;
145 else val = voxel_cast<RealType>(this->DefaultValue());
147 return voxel_cast<VoxelType>(val);
151 template <
class TImage>
152 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
161 if (k < 0 || k >= this->Input()->Z() ||
162 l < 0 || l >= this->Input()->T()) {
163 return voxel_cast<VoxelType>(this->DefaultValue());
166 const int i1 = i - 1;
167 const int j1 = j - 1;
168 const int i2 = i + 2;
169 const int j2 = j + 2;
171 RealType val = voxel_cast<RealType>(0);
172 Real fgw(0), bgw(0), wy, w;
174 for (j = j1; j <= j2; ++j) {
175 wy = CSpline(Real(y - j));
176 for (i = i1; i <= i2; ++i) {
177 w = CSpline(Real(x - i)) * wy;
178 if (this->Input()->IsInsideForeground(i, j, k, l)) {
179 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
187 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
188 return voxel_cast<VoxelType>(this->DefaultValue());
190 return voxel_cast<VoxelType>(val / fgw);
194 template <
class TImage>
template <
class TOtherImage>
195 inline typename TOtherImage::VoxelType
197 ::Get2D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 199 typedef typename TOtherImage::VoxelType VoxelType;
200 typedef typename TOtherImage::RealType RealType;
207 const int i1 = i - 1;
208 const int j1 = j - 1;
209 const int i2 = i + 2;
210 const int j2 = j + 2;
212 RealType val = voxel_cast<RealType>(0);
215 for (j = j1; j <= j2; ++j) {
216 wy = CSpline(Real(y - j));
217 for (i = i1; i <= i2; ++i) {
218 w = CSpline(Real(x - i)) * wy;
219 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
224 if (nrm > 1e-3) val /= nrm;
225 else val = voxel_cast<RealType>(this->DefaultValue());
227 return voxel_cast<VoxelType>(val);
231 template <
class TImage>
template <
class TOtherImage>
232 inline typename TOtherImage::VoxelType
236 typedef typename TOtherImage::VoxelType VoxelType;
237 typedef typename TOtherImage::RealType RealType;
244 const int i1 = i - 1;
245 const int j1 = j - 1;
246 const int i2 = i + 2;
247 const int j2 = j + 2;
249 RealType val = voxel_cast<RealType>(0);
250 Real fgw(0), bgw(0), wy, w;
252 for (j = j1; j <= j2; ++j) {
253 wy = CSpline(Real(y - j));
254 for (i = i1; i <= i2; ++i) {
255 w = CSpline(Real(x - i)) * wy;
256 if (input->IsForeground(i, j, k, l)) {
257 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
265 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
266 return voxel_cast<VoxelType>(this->DefaultValue());
268 return voxel_cast<VoxelType>(val / fgw);
272 template <
class TImage>
273 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
275 ::Get3D(
double x,
double y,
double z,
double t)
const 282 if (l < 0 || l >= this->Input()->T()) {
283 return voxel_cast<VoxelType>(this->DefaultValue());
286 const int i1 = i - 1;
287 const int j1 = j - 1;
288 const int k1 = k - 1;
289 const int i2 = i + 2;
290 const int j2 = j + 2;
291 const int k2 = k + 2;
293 RealType val = voxel_cast<RealType>(0);
294 Real nrm(0), wz, wyz, w;
296 for (k = k1; k <= k2; ++k) {
297 if (0 <= k && k < this->Input()->Z()) {
298 wz = CSpline(Real(z - k));
299 for (j = j1; j <= j2; ++j) {
300 if (0 <= j && j < this->Input()->Y()) {
301 wyz = CSpline(Real(y - j)) * wz;
302 for (i = i1; i <= i2; ++i) {
303 if (0 <= i && i < this->Input()->X()) {
304 w = CSpline(Real(x - i)) * wyz;
305 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
314 if (nrm > 1e-3) val /= nrm;
315 else val = voxel_cast<RealType>(this->DefaultValue());
317 return voxel_cast<VoxelType>(val);
321 template <
class TImage>
322 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
331 if (l < 0 || l >= this->Input()->T()) {
332 return voxel_cast<VoxelType>(this->DefaultValue());
335 const int i1 = i - 1;
336 const int j1 = j - 1;
337 const int k1 = k - 1;
338 const int i2 = i + 2;
339 const int j2 = j + 2;
340 const int k2 = k + 2;
342 RealType val = voxel_cast<RealType>(0);
343 Real fgw(0), bgw(0), wz, wyz, w;
345 for (k = k1; k <= k2; ++k) {
346 wz = CSpline(Real(z - k));
347 for (j = j1; j <= j2; ++j) {
348 wyz = CSpline(Real(y - j)) * wz;
349 for (i = i1; i <= i2; ++i) {
350 w = CSpline(Real(x - i)) * wyz;
351 if (this->Input()->IsInsideForeground(i, j, k, l)) {
352 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
361 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
362 return voxel_cast<VoxelType>(this->DefaultValue());
364 return voxel_cast<VoxelType>(val / fgw);
368 template <
class TImage>
template <
class TOtherImage>
369 inline typename TOtherImage::VoxelType
371 ::Get3D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 373 typedef typename TOtherImage::VoxelType VoxelType;
374 typedef typename TOtherImage::RealType RealType;
381 const int i1 = i - 1;
382 const int j1 = j - 1;
383 const int k1 = k - 1;
384 const int i2 = i + 2;
385 const int j2 = j + 2;
386 const int k2 = k + 2;
388 RealType val = voxel_cast<RealType>(0);
389 Real nrm(0), wz, wyz, w;
391 for (k = k1; k <= k2; ++k) {
392 wz = CSpline(Real(z - k));
393 for (j = j1; j <= j2; ++j) {
394 wyz = CSpline(Real(y - j)) * wz;
395 for (i = i1; i < i2; ++i) {
396 w = CSpline(Real(x - i)) * wyz;
397 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
403 if (nrm > 1e-3) val /= nrm;
404 else val = voxel_cast<RealType>(this->DefaultValue());
406 return voxel_cast<VoxelType>(val);
410 template <
class TImage>
template <
class TOtherImage>
411 inline typename TOtherImage::VoxelType
415 typedef typename TOtherImage::VoxelType VoxelType;
416 typedef typename TOtherImage::RealType RealType;
423 const int i1 = i - 1;
424 const int j1 = j - 1;
425 const int k1 = k - 1;
426 const int i2 = i + 2;
427 const int j2 = j + 2;
428 const int k2 = k + 2;
430 RealType val = voxel_cast<RealType>(0);
431 Real fgw(0), bgw(0), wz, wyz, w;
433 for (k = k1; k <= k2; ++k) {
434 wz = CSpline(Real(z - k));
435 for (j = j1; j <= j2; ++j) {
436 wyz = CSpline(Real(y - j)) * wz;
437 for (i = i1; i < i2; ++i) {
438 w = CSpline(Real(x - i)) * wyz;
439 if (input->IsForeground(i, j, k, l)) {
440 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
449 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
450 return voxel_cast<VoxelType>(this->DefaultValue());
452 return voxel_cast<VoxelType>(val / fgw);
456 template <
class TImage>
457 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
459 ::Get4D(
double x,
double y,
double z,
double t)
const 466 const int i1 = i - 1;
467 const int j1 = j - 1;
468 const int k1 = k - 1;
469 const int l1 = l - 1;
470 const int i2 = i + 2;
471 const int j2 = j + 2;
472 const int k2 = k + 2;
473 const int l2 = l + 2;
475 RealType val = voxel_cast<RealType>(0);
476 Real nrm(0), wt, wzt, wyzt, w;
478 for (l = l1; l <= l2; ++l) {
479 if (0 <= l && l < this->Input()->T()) {
480 wt = CSpline(Real(t - l));
481 for (k = k1; k <= k2; ++k) {
482 if (0 <= k && k < this->Input()->Z()) {
483 wzt = CSpline(Real(z - k)) * wt;
484 for (j = j1; j <= j2; ++j) {
485 if (0 <= j && j < this->Input()->Y()) {
486 wyzt = CSpline(Real(y - j)) * wzt;
487 for (i = i1; i <= i2; ++i) {
488 if (0 <= i && i < this->Input()->X()) {
489 w = CSpline(Real(x - i)) * wyzt;
490 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
501 if (nrm > 1e-3) val /= nrm;
502 else val = voxel_cast<RealType>(this->DefaultValue());
504 return voxel_cast<VoxelType>(val);
508 template <
class TImage>
509 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
518 const int i1 = i - 1;
519 const int j1 = j - 1;
520 const int k1 = k - 1;
521 const int l1 = l - 1;
522 const int i2 = i + 2;
523 const int j2 = j + 2;
524 const int k2 = k + 2;
525 const int l2 = l + 2;
527 RealType val = voxel_cast<RealType>(0);
528 Real fgw(0), bgw(0), wt, wzt, wyzt, w;
530 for (l = l1; l <= l2; ++l) {
531 wt = CSpline(Real(t - l));
532 for (k = k1; k <= k2; ++k) {
533 wzt = CSpline(Real(z - k)) * wt;
534 for (j = j1; j <= j2; ++j) {
535 wyzt = CSpline(Real(y - j)) * wzt;
536 for (i = i1; i <= i2; ++i) {
537 w = CSpline(Real(x - i)) * wyzt;
538 if (this->Input()->IsInsideForeground(i, j, k, l)) {
539 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
549 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
550 return voxel_cast<VoxelType>(this->DefaultValue());
552 return voxel_cast<VoxelType>(val / fgw);
556 template <
class TImage>
template <
class TOtherImage>
557 inline typename TOtherImage::VoxelType
559 ::Get4D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 561 typedef typename TOtherImage::VoxelType VoxelType;
562 typedef typename TOtherImage::RealType RealType;
569 const int i1 = i - 1;
570 const int j1 = j - 1;
571 const int k1 = k - 1;
572 const int l1 = l - 1;
573 const int i2 = i + 2;
574 const int j2 = j + 2;
575 const int k2 = k + 2;
576 const int l2 = l + 2;
578 RealType val = voxel_cast<RealType>(0);
579 Real nrm(0), wt, wzt, wyzt, w;
581 for (l = l1; l <= l2; ++l) {
582 wt = CSpline(Real(t - l));
583 for (k = k1; k <= k2; ++k) {
584 wzt = CSpline(Real(z - k)) * wt;
585 for (j = j1; j <= j2; ++j) {
586 wyzt = CSpline(Real(y - j)) * wzt;
587 for (i = i1; i <= i2; ++i) {
588 w = CSpline(Real(x - i)) * wyzt;
589 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
596 if (nrm > 1e-3) val /= nrm;
597 else val = voxel_cast<RealType>(this->DefaultValue());
599 return voxel_cast<VoxelType>(val);
603 template <
class TImage>
template <
class TOtherImage>
604 inline typename TOtherImage::VoxelType
608 typedef typename TOtherImage::VoxelType VoxelType;
609 typedef typename TOtherImage::RealType RealType;
616 const int i1 = i - 1;
617 const int j1 = j - 1;
618 const int k1 = k - 1;
619 const int l1 = l - 1;
620 const int i2 = i + 2;
621 const int j2 = j + 2;
622 const int k2 = k + 2;
623 const int l2 = l + 2;
625 RealType val = voxel_cast<RealType>(0);
626 Real fgw(0), bgw(0), wt, wzt, wyzt, w;
628 for (l = l1; l <= l2; ++l) {
629 wt = CSpline(Real(t - l));
630 for (k = k1; k <= k2; ++k) {
631 wzt = CSpline(Real(z - k)) * wt;
632 for (j = j1; j <= j2; ++j) {
633 wyzt = CSpline(Real(y - j)) * wzt;
634 for (i = i1; i <= i2; ++i) {
635 w = CSpline(Real(x - i)) * wyzt;
636 if (input->IsForeground(i, j, k, l)) {
637 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
647 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
648 return voxel_cast<VoxelType>(this->DefaultValue());
650 return voxel_cast<VoxelType>(val / fgw);
654 template <
class TImage>
655 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
657 ::Get(
double x,
double y,
double z,
double t)
const 659 switch (this->NumberOfDimensions()) {
660 case 3:
return Get3D(x, y, z, t);
661 case 2:
return Get2D(x, y, z, t);
662 default:
return Get4D(x, y, z, t);
667 template <
class TImage>
668 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
672 switch (this->NumberOfDimensions()) {
673 case 3:
return GetWithPadding3D(x, y, z, t);
674 case 2:
return GetWithPadding2D(x, y, z, t);
675 default:
return GetWithPadding4D(x, y, z, t);
680 template <
class TImage>
template <
class TOtherImage>
681 inline typename TOtherImage::VoxelType
683 ::Get(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 685 switch (this->NumberOfDimensions()) {
686 case 3:
return Get3D(input, x, y, z, t);
687 case 2:
return Get2D(input, x, y, z, t);
688 default:
return Get4D(input, x, y, z, t);
693 template <
class TImage>
template <
class TOtherImage>
694 inline typename TOtherImage::VoxelType
698 switch (this->NumberOfDimensions()) {
699 case 3:
return GetWithPadding3D(input, x, y, z, t);
700 case 2:
return GetWithPadding2D(input, x, y, z, t);
701 default:
return GetWithPadding4D(input, x, y, z, t);
706 template <
class TImage>
707 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
711 return Get(this->Input(), x, y, z, t);
715 template <
class TImage>
716 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
720 if (this->Extrapolator()) {
721 return Get(this->Extrapolator(), x, y, z, t);
723 return Get(x, y, z, t);
728 template <
class TImage>
729 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
733 return GetWithPadding(this->Input(), x, y, z, t);
737 template <
class TImage>
738 inline typename GenericCSplineInterpolateImageFunction<TImage>::VoxelType
742 if (this->Extrapolator()) {
743 return GetWithPadding(this->Extrapolator(), x, y, z, t);
745 return GetWithPadding(x, y, z, t);
752 #endif // MIRTK_CSplineInterpolateImageFunction_HXX virtual VoxelType GetWithPaddingInside(double, double, double=0, double=0) const
VoxelType GetWithPadding4D(double, double, double=0, double=0) const
GenericCSplineInterpolateImageFunction()
Default constructor.
virtual VoxelType GetInside(double, double, double=0, double=0) const
string Get(const ParameterList ¶ms, string name)
Get parameter value from parameters list.
virtual void Initialize()
virtual ~GenericCSplineInterpolateImageFunction()
Destructor.
VoxelType Get4D(double, double, double=0, double=0) const
VoxelType Get2D(double, double, double=0, double=0) const
virtual VoxelType GetWithPadding(double, double, double=0, double=0) const
VoxelType Get3D(double, double, double=0, double=0) const
MIRTKCU_API int ifloor(T x)
Round floating-point value to next smaller integer and cast to int.
static Real CSpline(Real)
Cubic spline function.
virtual VoxelType GetOutside(double, double, double=0, double=0) const
Evaluate generic image at an arbitrary location (in pixels)
MIRTKCU_API bool AreEqual(double a, double b, double tol=1e-12)
Determine equality of two floating point numbers.
VoxelType GetWithPadding3D(double, double, double=0, double=0) const
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
VoxelType Get(double, double, double=0, double=0) const
virtual void BoundingInterval(double, int &, int &) const
virtual VoxelType GetWithPaddingOutside(double, double, double=0, double=0) const
VoxelType GetWithPadding2D(double, double, double=0, double=0) const