20 #ifndef MIRTK_CubicBSplineInterpolateImageFunction_HXX 21 #define MIRTK_CubicBSplineInterpolateImageFunction_HXX 23 #include "mirtk/CubicBSplineInterpolateImageFunction.h" 25 #include "mirtk/Math.h" 26 #include "mirtk/InterpolateImageFunction.hxx" 27 #include "mirtk/ImageToInterpolationCoefficients.h" 38 template <
class TImage>
42 _UseInputCoefficients(false),
43 _InfiniteCoefficient(nullptr)
47 this->Extrapolator(ExtrapolatorType::New(Extrapolation_Mirror),
true);
51 template <
class TImage>
55 delete _InfiniteCoefficient;
59 template <
class TImage>
64 Superclass::Initialize(coeff);
67 const double margin = 2.0;
68 switch (this->NumberOfDimensions()) {
70 this->_t1 =
fdec(margin);
71 this->_t2 = this->Input()->T() - margin - 1;
73 this->_z1 =
fdec(margin);
74 this->_z2 = this->Input()->Z() - margin - 1;
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;
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()));
88 _Coefficient.Initialize(this->Input()->Attributes(), data);
92 if (!_InfiniteCoefficient || _InfiniteCoefficient->ExtrapolationMode() != this->
ExtrapolationMode()) {
93 delete _InfiniteCoefficient;
94 _InfiniteCoefficient = CoefficientExtrapolator::New(this->
ExtrapolationMode(), &_Coefficient);
96 if (_InfiniteCoefficient) {
97 _InfiniteCoefficient->Input(&_Coefficient);
98 _InfiniteCoefficient->Initialize();
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();
110 template <
class TImage>
113 if (_Coefficient.GetDataPointer() != this->Input()->GetDataPointer()) {
114 _Coefficient = *(this->Input());
115 if (!_UseInputCoefficients) {
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);
135 template <
class TImage>
147 template <
class TImage>
148 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
150 ::Get2D(
double x,
double y,
double z,
double t)
const 157 if (k < 0 || k >= _Coefficient.Z() ||
158 l < 0 || l >= _Coefficient.T()) {
159 return voxel_cast<VoxelType>(this->DefaultValue());
162 Real wx[4]; Kernel::Weights(Real(x - i), wx);
163 Real wy[4]; Kernel::Weights(Real(y - j), wy);
167 RealType val = voxel_cast<RealType>(0);
170 for (
int b = 0; b <= 3; ++b) {
172 DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
173 for (
int a = 0; a <= 3; ++a) {
175 DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
176 val += wx[a] * wy[b] * _Coefficient(ia, jb, k, l);
180 return voxel_cast<VoxelType>(val);
184 template <
class TImage>
185 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
194 if (k < 0 || k >= _Coefficient.Z() ||
195 l < 0 || l >= _Coefficient.T()) {
196 return voxel_cast<VoxelType>(this->DefaultValue());
199 Real wx[4]; Kernel::Weights(Real(x - i), wx);
200 Real wy[4]; Kernel::Weights(Real(y - j), wy);
204 RealType val = voxel_cast<RealType>(0);
205 Real fgw(0), bgw(0), w;
208 for (
int b = 0; b <= 3; ++b) {
210 DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
211 for (
int a = 0; a <= 3; ++a) {
213 DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
215 val += w * _Coefficient(ia, jb, k, l);
216 if (this->Input()->IsInsideForeground(i + a, j + b, k, l)) {
224 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
225 val = voxel_cast<RealType>(this->DefaultValue());
227 return voxel_cast<VoxelType>(val);
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 236 typedef typename TCoefficient::VoxelType VoxelType;
237 typedef typename TCoefficient::RealType RealType;
244 Real wx[4]; Kernel::Weights(Real(x - i), wx);
245 Real wy[4]; Kernel::Weights(Real(y - j), wy);
249 RealType val = voxel_cast<RealType>(0);
252 for (
int b = 0; b <= 3; ++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));
260 return voxel_cast<VoxelType>(val);
264 template <
class TImage>
template <
class TOtherImage,
class TCoefficient>
265 inline typename TCoefficient::VoxelType
268 double x,
double y,
double z,
double t)
const 270 typedef typename TCoefficient::VoxelType VoxelType;
271 typedef typename TCoefficient::RealType RealType;
278 Real wx[4]; Kernel::Weights(Real(x - i), wx);
279 Real wy[4]; Kernel::Weights(Real(y - j), wy);
283 RealType val = voxel_cast<RealType>(0);
284 Real fgw(0), bgw(0), w;
287 for (
int b = 0; b <= 3; ++b) {
289 for (
int a = 0; a <= 3; ++a) {
292 val += w * voxel_cast<RealType>(coeff->Get(ia, jb, k, l));
293 if (input->IsForeground(ia, jb, k, l)) {
301 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
302 val = voxel_cast<RealType>(this->DefaultValue());
304 return voxel_cast<VoxelType>(val);
308 template <
class TImage>
309 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
311 ::Get3D(
double x,
double y,
double z,
double t)
const 318 if (l < 0 || l >= _Coefficient.T()) {
319 return voxel_cast<VoxelType>(this->DefaultValue());
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);
328 RealType val = voxel_cast<RealType>(0);
332 for (
int c = 0; c <= 3; ++c) {
334 DefaultExtrapolator::Apply(kc, _Coefficient.Z() - 1);
335 for (
int b = 0; b <= 3; ++b) {
337 DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
339 for (
int a = 0; a <= 3; ++a) {
341 DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
342 val += wx[a] * wyz * _Coefficient(ia, jb, kc, l);
347 return voxel_cast<VoxelType>(val);
351 template <
class TImage>
352 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
361 if (l < 0 || l >= _Coefficient.T()) {
362 return voxel_cast<VoxelType>(this->DefaultValue());
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);
371 RealType val = voxel_cast<RealType>(0);
372 Real fgw(0), bgw(0), wyz, w;
375 for (
int c = 0; c <= 3; ++c) {
377 for (
int b = 0; b <= 3; ++b) {
380 for (
int a = 0; a <= 3; ++a) {
383 val += w * _Coefficient(ia, jb, kc, l);
384 if (this->Input()->IsInsideForeground(ia, jb, kc, l)) {
393 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
394 val = voxel_cast<RealType>(this->DefaultValue());
396 return voxel_cast<VoxelType>(val);
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 405 typedef typename TCoefficient::VoxelType VoxelType;
406 typedef typename TCoefficient::RealType RealType;
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);
419 RealType val = voxel_cast<RealType>(0);
423 for (
int c = 0; c <= 3; ++c) {
425 for (
int b = 0; b <= 3; ++b) {
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));
435 return voxel_cast<VoxelType>(val);
439 template <
class TImage>
template <
class TOtherImage,
class TCoefficient>
440 inline typename TCoefficient::VoxelType
443 double x,
double y,
double z,
double t)
const 445 typedef typename TCoefficient::VoxelType VoxelType;
446 typedef typename TCoefficient::RealType RealType;
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);
459 RealType val = voxel_cast<RealType>(0);
460 Real fgw(0), bgw(0), wyz, w;
463 for (
int c = 0; c <= 3; ++c) {
465 for (
int b = 0; b <= 3; ++b) {
468 for (
int a = 0; a <= 3; ++a) {
471 val += w * voxel_cast<RealType>(coeff->Get(ia, jb, kc, l));
472 if (input->IsForeground(ia, jb, kc, l)) {
481 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
482 val = voxel_cast<RealType>(this->DefaultValue());
484 return voxel_cast<VoxelType>(val);
488 template <
class TImage>
489 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
491 ::Get4D(
double x,
double y,
double z,
double t)
const 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);
505 RealType val = voxel_cast<RealType>(0);
509 for (
int d = 0; d <= 3; ++d) {
511 DefaultExtrapolator::Apply(ld, _Coefficient.T() - 1);
512 for (
int c = 0; c <= 3; ++c) {
514 DefaultExtrapolator::Apply(kc, _Coefficient.Z() - 1);
516 for (
int b = 0; b <= 3; ++b) {
518 DefaultExtrapolator::Apply(jb, _Coefficient.Y() - 1);
520 for (
int a = 0; a <= 3; ++a) {
522 DefaultExtrapolator::Apply(ia, _Coefficient.X() - 1);
523 val += wx[a] * wyzt * _Coefficient(ia, jb, kc, ld);
529 return voxel_cast<VoxelType>(val);
533 template <
class TImage>
534 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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);
550 RealType val = voxel_cast<RealType>(0);
551 Real fgw(0), bgw(0), wzt, wyzt, w;
554 for (
int d = 0; d <= 3; ++d) {
556 for (
int c = 0; c <= 3; ++c) {
559 for (
int b = 0; b <= 3; ++b) {
562 for (
int a = 0; a <= 3; ++a) {
565 val += w * _Coefficient(ia, jb, kc, ld);
566 if (this->Input()->IsInsideForeground(ia, jb, kc, ld)) {
576 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
577 val = voxel_cast<RealType>(this->DefaultValue());
579 return voxel_cast<VoxelType>(val);
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 588 typedef typename TCoefficient::VoxelType VoxelType;
589 typedef typename TCoefficient::RealType RealType;
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);
603 RealType val = voxel_cast<RealType>(0);
607 for (
int d = 0; d <= 3; ++d) {
609 for (
int c = 0; c <= 3; ++c) {
612 for (
int b = 0; b <= 3; ++b) {
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));
623 return voxel_cast<VoxelType>(val);
627 template <
class TImage>
template <
class TOtherImage,
class TCoefficient>
628 inline typename TCoefficient::VoxelType
631 double x,
double y,
double z,
double t)
const 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);
645 RealType val = voxel_cast<RealType>(0);
646 Real fgw(0), bgw(0), wzt, wyzt, w;
649 for (
int d = 0; d <= 3; ++d) {
651 for (
int c = 0; c <= 3; ++c) {
654 for (
int b = 0; b <= 3; ++b) {
657 for (
int a = 0; a <= 3; ++a) {
660 val += w * voxel_cast<RealType>(coeff->Get(ia, jb, kc, ld));
661 if (input->IsForeground(ia, jb, kc, ld)) {
671 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
672 val = voxel_cast<RealType>(this->DefaultValue());
674 return voxel_cast<VoxelType>(val);
678 template <
class TImage>
679 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
681 ::Get(
double x,
double y,
double z,
double t)
const 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);
691 template <
class TImage>
692 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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);
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 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);
717 template <
class TImage>
template <
class TOtherImage,
class TCoefficient>
718 inline typename TCoefficient::VoxelType
721 double x,
double y,
double z,
double t)
const 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);
731 template <
class TImage>
732 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
741 Real wx[4]; Kernel::Weights(Real(x - i), wx);
742 Real wy[4]; Kernel::Weights(Real(y - j), wy);
746 RealType val = voxel_cast<RealType>(0);
747 const RealType *coeff = _Coefficient.Data(i, j, k, l);
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;
756 return voxel_cast<VoxelType>(val);
760 template <
class TImage>
761 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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);
776 RealType val = voxel_cast<RealType>(0);
777 const RealType *coeff = _Coefficient.Data(i, j, k, l);
780 for (
int c = 0; c <= 3; ++c, coeff += _s3) {
781 for (
int b = 0; b <= 3; ++b, coeff += _s2) {
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;
790 return voxel_cast<VoxelType>(val);
794 template <
class TImage>
795 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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);
811 RealType val = voxel_cast<RealType>(0);
812 const RealType *coeff = _Coefficient.Data(i, j, k, l);
815 for (
int d = 0; d <= 3; ++d, coeff += _s4) {
816 for (
int c = 0; c <= 3; ++c, coeff += _s3) {
818 for (
int b = 0; b <= 3; ++b, coeff += _s2) {
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;
828 return voxel_cast<VoxelType>(val);
832 template <
class TImage>
833 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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);
846 template <
class TImage>
847 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
851 if (_InfiniteCoefficient) {
852 return voxel_cast<VoxelType>(
Get(_InfiniteCoefficient, x, y, z, t));
854 return Get(x, y, z, t);
859 template <
class TImage>
860 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
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));
872 template <
class TImage>
873 inline typename GenericCubicBSplineInterpolateImageFunction<TImage>::VoxelType
877 if (this->Extrapolator() && _InfiniteCoefficient) {
878 return voxel_cast<VoxelType>(GetWithPadding(this->Extrapolator(), _InfiniteCoefficient, x, y, z, t));
880 return GetWithPadding(x, y, z, t);
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 ¶ms, string name)
Get parameter value from parameters list.
virtual VoxelType GetInside4D(double, double, double=0, double=0) const
Evaluate generic 4D image without handling boundary conditions.
virtual void Update()
Update spline coefficients.
virtual void Initialize()
virtual VoxelType GetWithPaddingInside(double, double, double=0, double=0) const
virtual ~GenericCubicBSplineInterpolateImageFunction()
Destructor.
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.
MIRTKCU_API double fdec(double f)
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.
VoxelType Get3D(double, double, double=0, double=0) const
VoxelType GetWithPadding4D(double, double, double=0, double=0) const
GenericCubicBSplineInterpolateImageFunction()
Constructor.
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
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 void BoundingInterval(double, int &, int &) const
virtual VoxelType GetInside3D(double, double, double=0, double=0) const
Evaluate generic 3D image without handling boundary conditions.