21 #ifndef MIRTK_GaussianInterpolateImageFunction_HXX 22 #define MIRTK_GaussianInterpolateImageFunction_HXX 24 #include "mirtk/GaussianInterpolateImageFunction.h" 25 #include "mirtk/InterpolateImageFunction.hxx" 27 #include "mirtk/Math.h" 28 #include "mirtk/VoxelCast.h" 29 #include "mirtk/ScalarGaussian.h" 40 template <
class TImage>
45 _RadiusX(.0), _RadiusY(.0), _RadiusZ(.0), _RadiusT(.0),
46 _dx (.0), _dy (.0), _dz (.0), _dt (.0)
51 template <
class TImage>
55 Superclass::Initialize(coeff);
58 this->Input()->GetPixelSize(_dx, _dy, _dz, _dt);
61 _RadiusX = _RadiusY = _RadiusZ = _RadiusT = .0;
62 switch (this->NumberOfDimensions()) {
63 case 4: _RadiusT = round(ceil(3.0 * _Sigma/_dt));
64 case 3: _RadiusZ = round(ceil(3.0 * _Sigma/_dz));
65 default: _RadiusY = round(ceil(3.0 * _Sigma/_dy));
66 _RadiusX = round(ceil(3.0 * _Sigma/_dx));
71 this->_x2 = this->Input()->X() - _RadiusX - 1;
73 this->_y2 = this->Input()->Y() - _RadiusY - 1;
75 this->_z2 = this->Input()->Z() - _RadiusZ - 1;
77 this->_t2 = this->Input()->T() - _RadiusT - 1;
81 template <
class TImage>
85 double r = max(_RadiusX, max(_RadiusY, max(_RadiusZ, _RadiusT)));
90 template <
class TImage>
93 int &j1,
int &j2)
const 100 template <
class TImage>
103 int &j1,
int &j2,
int &k2)
const 111 template <
class TImage>
114 int &i1,
int &i2,
int &k1,
int &l1,
115 int &j1,
int &j2,
int &k2,
int &l2)
const 128 template <
class TImage>
129 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
131 ::Get2D(
double x,
double y,
double z,
double t)
const 136 if (k < 0 || k >= this->Input()->Z() ||
137 l < 0 || l >= this->Input()->T()) {
138 return voxel_cast<VoxelType>(this->DefaultValue());
141 const int i1 =
ifloor(x - _RadiusX);
142 const int j1 =
ifloor(y - _RadiusY);
143 const int i2 =
ifloor(x + _RadiusX);
144 const int j2 =
ifloor(y + _RadiusY);
150 RealType val = voxel_cast<RealType>(0);
153 for (
int j = j1; j <= j2; ++j) {
154 if (0 <= j && j < this->Input()->Y()) {
155 for (
int i = i1; i <= i2; ++i) {
156 if (0 <= i && i < this->Input()->X()) {
157 w =
static_cast<Real
>(kernel.
Evaluate(i, j));
158 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
165 if (nrm > 1e-3) val /= nrm;
166 else val = voxel_cast<RealType>(this->DefaultValue());
168 return voxel_cast<VoxelType>(val);
172 template <
class TImage>
173 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
180 if (k < 0 || k >= this->Input()->Z() ||
181 l < 0 || l >= this->Input()->T()) {
182 return voxel_cast<VoxelType>(this->DefaultValue());
185 const int i1 =
ifloor(x - _RadiusX);
186 const int j1 =
ifloor(y - _RadiusY);
187 const int i2 =
ifloor(x + _RadiusX);
188 const int j2 =
ifloor(y + _RadiusY);
194 RealType val = voxel_cast<RealType>(0);
195 Real fgw(0), bgw(0), w;
197 for (
int j = j1; j <= j2; ++j) {
198 for (
int i = i1; i <= i2; ++i) {
199 w =
static_cast<Real
>(kernel.
Evaluate(i, j));
200 if (this->Input()->IsInsideForeground(i, j, k, l)) {
201 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
209 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
210 return voxel_cast<VoxelType>(this->DefaultValue());
212 return voxel_cast<VoxelType>(val / fgw);
216 template <
class TImage>
template <
class TOtherImage>
217 inline typename TOtherImage::VoxelType
219 ::Get2D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 221 typedef typename TOtherImage::VoxelType VoxelType;
222 typedef typename TOtherImage::RealType RealType;
227 const int i1 =
ifloor(x - _RadiusX);
228 const int j1 =
ifloor(y - _RadiusY);
229 const int i2 =
ifloor(x + _RadiusX);
230 const int j2 =
ifloor(y + _RadiusY);
236 RealType val = voxel_cast<RealType>(0);
239 for (
int j = j1; j <= j2; ++j) {
240 for (
int i = i1; i <= i2; ++i) {
241 w =
static_cast<Real
>(kernel.
Evaluate(i, j));
242 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
247 if (nrm > 1e-3) val /= nrm;
248 else val = voxel_cast<RealType>(this->DefaultValue());
250 return voxel_cast<VoxelType>(val);
254 template <
class TImage>
template <
class TOtherImage>
255 inline typename TOtherImage::VoxelType
259 typedef typename TOtherImage::VoxelType VoxelType;
260 typedef typename TOtherImage::RealType RealType;
265 const int i1 =
ifloor(x - _RadiusX);
266 const int j1 =
ifloor(y - _RadiusY);
267 const int i2 =
ifloor(x + _RadiusX);
268 const int j2 =
ifloor(y + _RadiusY);
274 RealType val = voxel_cast<RealType>(0);
275 Real fgw(0), bgw(0), w;
277 for (
int j = j1; j <= j2; ++j) {
278 for (
int i = i1; i <= i2; ++i) {
279 w =
static_cast<Real
>(kernel.
Evaluate(i, j));
280 if (input->IsForeground(i, j, k, l)) {
281 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
289 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
290 return voxel_cast<VoxelType>(this->DefaultValue());
292 return voxel_cast<VoxelType>(val / fgw);
296 template <
class TImage>
297 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
299 ::Get3D(
double x,
double y,
double z,
double t)
const 303 if (l < 0 || l >= this->Input()->T()) {
304 return voxel_cast<VoxelType>(this->DefaultValue());
307 const int i1 =
ifloor(x - _RadiusX);
308 const int j1 =
ifloor(y - _RadiusY);
309 const int k1 =
ifloor(z - _RadiusZ);
310 const int i2 =
ifloor(x + _RadiusX);
311 const int j2 =
ifloor(y + _RadiusY);
312 const int k2 =
ifloor(z + _RadiusZ);
315 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, x, y, z);
318 RealType val = voxel_cast<RealType>(0);
321 for (
int k = k1; k <= k2; ++k) {
322 if (0 <= k && k < this->Input()->Z()) {
323 for (
int j = j1; j <= j2; ++j) {
324 if (0 <= j && j < this->Input()->Y()) {
325 for (
int i = i1; i <= i2; ++i) {
326 if (0 <= i && i < this->Input()->X()) {
327 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k));
328 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
337 if (nrm > 1e-3) val /= nrm;
338 else val = voxel_cast<RealType>(this->DefaultValue());
340 return voxel_cast<VoxelType>(val);
344 template <
class TImage>
345 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
351 if (l < 0 || l >= this->Input()->T()) {
352 return voxel_cast<VoxelType>(this->DefaultValue());
355 const int i1 =
ifloor(x - _RadiusX);
356 const int j1 =
ifloor(y - _RadiusY);
357 const int k1 =
ifloor(z - _RadiusZ);
358 const int i2 =
ifloor(x + _RadiusX);
359 const int j2 =
ifloor(y + _RadiusY);
360 const int k2 =
ifloor(z + _RadiusZ);
363 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, x, y, z);
366 RealType val = voxel_cast<RealType>(0);
367 Real fgw(0), bgw(0), w;
369 for (
int k = k1; k <= k2; ++k) {
370 for (
int j = j1; j <= j2; ++j) {
371 for (
int i = i1; i <= i2; ++i) {
372 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k));
373 if (this->Input()->IsInsideForeground(i, j, k, l)) {
374 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
383 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
384 return voxel_cast<VoxelType>(this->DefaultValue());
386 return voxel_cast<VoxelType>(val / fgw);
390 template <
class TImage>
template <
class TOtherImage>
391 inline typename TOtherImage::VoxelType
393 ::Get3D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 395 typedef typename TOtherImage::VoxelType VoxelType;
396 typedef typename TOtherImage::RealType RealType;
400 const int i1 =
ifloor(x - _RadiusX);
401 const int j1 =
ifloor(y - _RadiusY);
402 const int k1 =
ifloor(z - _RadiusZ);
403 const int i2 =
ifloor(x + _RadiusX);
404 const int j2 =
ifloor(y + _RadiusY);
405 const int k2 =
ifloor(z + _RadiusZ);
408 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, x, y, z);
411 RealType val = voxel_cast<RealType>(0);
414 for (
int k = k1; k <= k2; ++k) {
415 for (
int j = j1; j <= j2; ++j) {
416 for (
int i = i1; i <= i2; ++i) {
417 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k));
418 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
424 if (nrm > 1e-3) val /= nrm;
425 else val = voxel_cast<RealType>(this->DefaultValue());
427 return voxel_cast<VoxelType>(val);
431 template <
class TImage>
template <
class TOtherImage>
432 inline typename TOtherImage::VoxelType
436 typedef typename TOtherImage::VoxelType VoxelType;
437 typedef typename TOtherImage::RealType RealType;
441 const int i1 =
ifloor(x - _RadiusX);
442 const int j1 =
ifloor(y - _RadiusY);
443 const int k1 =
ifloor(z - _RadiusZ);
444 const int i2 =
ifloor(x + _RadiusX);
445 const int j2 =
ifloor(y + _RadiusY);
446 const int k2 =
ifloor(z + _RadiusZ);
449 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, x, y, z);
452 RealType val = voxel_cast<RealType>(0);
453 Real fgw(0), bgw(0), w;
455 for (
int k = k1; k <= k2; ++k) {
456 for (
int j = j1; j <= j2; ++j) {
457 for (
int i = i1; i <= i2; ++i) {
458 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k));
459 if (input->IsForeground(i, j, k, l)) {
460 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
469 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
470 return voxel_cast<VoxelType>(this->DefaultValue());
472 return voxel_cast<VoxelType>(val / fgw);
476 template <
class TImage>
477 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
479 ::Get4D(
double x,
double y,
double z,
double t)
const 481 const int i1 =
ifloor(x - _RadiusX);
482 const int j1 =
ifloor(y - _RadiusY);
483 const int k1 =
ifloor(z - _RadiusZ);
484 const int l1 =
ifloor(t - _RadiusT);
485 const int i2 =
ifloor(x + _RadiusX);
486 const int j2 =
ifloor(y + _RadiusY);
487 const int k2 =
ifloor(z + _RadiusZ);
488 const int l2 =
ifloor(t + _RadiusT);
491 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, _Sigma/_dt, x, y, z, t);
494 RealType val = voxel_cast<RealType>(0);
497 for (
int l = l1; l <= l2; ++l) {
498 if (0 <= l && l < this->Input()->T()) {
499 for (
int k = k1; k <= k2; ++k) {
500 if (0 <= k && k < this->Input()->Z()) {
501 for (
int j = j1; j <= j2; ++j) {
502 if (0 <= j && j < this->Input()->Y()) {
503 for (
int i = i1; i <= i2; ++i) {
504 if (0 <= i && i < this->Input()->X()) {
505 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k, l));
506 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
517 if (nrm > 1e-3) val /= nrm;
518 else val = voxel_cast<RealType>(this->DefaultValue());
520 return voxel_cast<VoxelType>(val);
524 template <
class TImage>
525 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
529 const int i1 =
ifloor(x - _RadiusX);
530 const int j1 =
ifloor(y - _RadiusY);
531 const int k1 =
ifloor(z - _RadiusZ);
532 const int l1 =
ifloor(t - _RadiusT);
533 const int i2 =
ifloor(x + _RadiusX);
534 const int j2 =
ifloor(y + _RadiusY);
535 const int k2 =
ifloor(z + _RadiusZ);
536 const int l2 =
ifloor(t + _RadiusT);
539 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, _Sigma/_dt, x, y, z, t);
542 RealType val = voxel_cast<RealType>(0);
543 Real fgw(0), bgw(0), w;
545 for (
int l = l1; l <= l2; ++l) {
546 for (
int k = k1; k <= k2; ++k) {
547 for (
int j = j1; j <= j2; ++j) {
548 for (
int i = i1; i <= i2; ++i) {
549 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k, l));
550 if (this->Input()->IsInsideForeground(i, j, k, l)) {
551 val += w * voxel_cast<RealType>(this->Input()->Get(i, j, k, l));
561 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
562 return voxel_cast<VoxelType>(this->DefaultValue());
564 return voxel_cast<VoxelType>(val / fgw);
568 template <
class TImage>
template <
class TOtherImage>
569 inline typename TOtherImage::VoxelType
571 ::Get4D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 573 typedef typename TOtherImage::VoxelType VoxelType;
574 typedef typename TOtherImage::RealType RealType;
576 const int i1 =
ifloor(x - _RadiusX);
577 const int j1 =
ifloor(y - _RadiusY);
578 const int k1 =
ifloor(z - _RadiusZ);
579 const int l1 =
ifloor(t - _RadiusT);
581 const int i2 =
ifloor(x + _RadiusX);
582 const int j2 =
ifloor(y + _RadiusY);
583 const int k2 =
ifloor(z + _RadiusZ);
584 const int l2 =
ifloor(t + _RadiusT);
587 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, _Sigma/_dt, x, y, z, t);
590 RealType val = voxel_cast<RealType>(0);
593 for (
int l = l1; l <= l2; ++l) {
594 for (
int k = k1; k <= k2; ++k) {
595 for (
int j = j1; j <= j2; ++j) {
596 for (
int i = i1; i <= i2; ++i) {
597 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k, l));
598 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
605 if (nrm > 1e-3) val /= nrm;
606 else val = voxel_cast<RealType>(this->DefaultValue());
608 return voxel_cast<VoxelType>(val);
612 template <
class TImage>
template <
class TOtherImage>
613 inline typename TOtherImage::VoxelType
617 typedef typename TOtherImage::VoxelType VoxelType;
618 typedef typename TOtherImage::RealType RealType;
620 const int i1 =
ifloor(x - _RadiusX);
621 const int j1 =
ifloor(y - _RadiusY);
622 const int k1 =
ifloor(z - _RadiusZ);
623 const int l1 =
ifloor(t - _RadiusT);
625 const int i2 =
ifloor(x + _RadiusX);
626 const int j2 =
ifloor(y + _RadiusY);
627 const int k2 =
ifloor(z + _RadiusZ);
628 const int l2 =
ifloor(t + _RadiusT);
631 ScalarGaussian kernel(_Sigma/_dx, _Sigma/_dy, _Sigma/_dz, _Sigma/_dt, x, y, z, t);
634 RealType val = voxel_cast<RealType>(0);
635 Real fgw(0), bgw(0), w;
637 for (
int l = l1; l <= l2; ++l) {
638 for (
int k = k1; k <= k2; ++k) {
639 for (
int j = j1; j <= j2; ++j) {
640 for (
int i = i1; i <= i2; ++i) {
641 w =
static_cast<Real
>(kernel.
Evaluate(i, j, k, l));
642 if (input->IsForeground(i, j, k, l)) {
643 val += w * voxel_cast<RealType>(input->Get(i, j, k, l));
653 if (bgw > fgw ||
AreEqual(bgw, fgw, 1e-3)) {
654 return voxel_cast<VoxelType>(this->DefaultValue());
656 return voxel_cast<VoxelType>(val / fgw);
660 template <
class TImage>
661 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
663 ::Get(
double x,
double y,
double z,
double t)
const 665 switch (this->NumberOfDimensions()) {
666 case 3:
return Get3D(x, y, z, t);
667 case 2:
return Get2D(x, y, z, t);
668 default:
return Get4D(x, y, z, t);
673 template <
class TImage>
674 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
678 switch (this->NumberOfDimensions()) {
679 case 3:
return GetWithPadding3D(x, y, z, t);
680 case 2:
return GetWithPadding2D(x, y, z, t);
681 default:
return GetWithPadding4D(x, y, z, t);
686 template <
class TImage>
template <
class TOtherImage>
687 inline typename TOtherImage::VoxelType
689 ::Get(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 691 switch (this->NumberOfDimensions()) {
692 case 3:
return Get3D(input, x, y, z, t);
693 case 2:
return Get2D(input, x, y, z, t);
694 default:
return Get4D(input, x, y, z, t);
699 template <
class TImage>
template <
class TOtherImage>
700 inline typename TOtherImage::VoxelType
704 switch (this->NumberOfDimensions()) {
705 case 3:
return GetWithPadding3D(input, x, y, z, t);
706 case 2:
return GetWithPadding2D(input, x, y, z, t);
707 default:
return GetWithPadding4D(input, x, y, z, t);
712 template <
class TImage>
713 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
717 return Get(this->Input(), x, y, z, t);
721 template <
class TImage>
722 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
726 if (this->Extrapolator()) {
727 return Get(this->Extrapolator(), x, y, z, t);
729 return Get(x, y, z, t);
734 template <
class TImage>
735 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
739 return GetWithPadding(this->Input(), x, y, z, t);
743 template <
class TImage>
744 inline typename GenericGaussianInterpolateImageFunction<TImage>::VoxelType
748 if (this->Extrapolator()) {
749 return GetWithPadding(this->Extrapolator(), x, y, z, t);
751 return GetWithPadding(x, y, z, t);
758 #endif // MIRTK_GaussianInterpolateImageFunction_HXX virtual VoxelType GetWithPadding(double, double, double=0, double=0) const
VoxelType GetWithPadding2D(double, double, double=0, double=0) const
virtual VoxelType GetWithPaddingInside(double, double, double=0, double=0) const
string Get(const ParameterList ¶ms, string name)
Get parameter value from parameters list.
VoxelType Get(double, double, double=0, double=0) const
virtual void Initialize()
virtual void BoundingBox(double, double, int &, int &, int &, int &) const
Returns discrete boundaries of local 2D image region needed for interpolation.
VoxelType Get2D(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.
virtual VoxelType GetOutside(double, double, double=0, double=0) const
Evaluate generic image at an arbitrary location (in pixels)
VoxelType GetWithPadding4D(double, double, double=0, double=0) const
virtual VoxelType GetWithPaddingOutside(double, double, double=0, double=0) const
virtual void BoundingInterval(double, int &, int &) const
MIRTKCU_API bool AreEqual(double a, double b, double tol=1e-12)
Determine equality of two floating point numbers.
VoxelType Get4D(double, double, double=0, double=0) const
virtual double Evaluate(double)
Evaluate 1D Gaussian.
VoxelType GetWithPadding3D(double, double, double=0, double=0) const
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
GenericGaussianInterpolateImageFunction(double=1.0)
Default constructor.
VoxelType Get3D(double, double, double=0, double=0) const
virtual VoxelType GetInside(double, double, double=0, double=0) const