20 #ifndef MIRTK_FastLinearImageGradientFunction_HXX 21 #define MIRTK_FastLinearImageGradientFunction_HXX 23 #include "mirtk/FastLinearImageGradientFunction.h" 24 #include "mirtk/ImageGradientFunction.hxx" 35 template <
class TImage>
42 template <
class TImage>
49 template <
class TImage>
53 Superclass::Initialize(coeff);
56 switch (this->NumberOfDimensions()) {
59 this->_t2 =
fdec(this->Input()->T() - 1);
62 this->_z2 =
fdec(this->Input()->Z() - 1);
65 this->_y2 =
fdec(this->Input()->Y() - 1);
67 this->_x2 =
fdec(this->Input()->X() - 1);
76 template <
class TImage>
88 template <
class TImage>
93 w[1] =
static_cast<Real
>(x) - static_cast<Real>(i);
94 w[0] =
static_cast<Real
>(1) - w[1];
103 template <
class TImage>
106 ::Get2D(
double x,
double y,
double z,
double t)
const 108 Real wx[2], wy[2], wd[2] = {Real(-1), Real(1)};
109 const int i = ComputeWeights(x, wx);
110 const int j = ComputeWeights(y, wy);
114 if (k < 0 || k >= this->Input()->Z() ||
115 l < 0 || l >= this->Input()->T()) {
116 return this->DefaultValue();
123 for (
int b = 0; b <= 1; ++b) {
125 if (0 <= jb && jb < this->Input()->Y()) {
126 for (
int a = 0; a <= 1; ++a) {
128 if (0 <= ia && ia < this->Input()->X()) {
129 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, k, l));
130 val.
_x += wd[a] * wy[b] * coeff;
131 val.
_y += wx[a] * wd[b] * coeff;
132 nrm += wx[a] * wy[b];
138 if (nrm > 1e-3) val /= nrm;
139 else val = this->DefaultValue();
145 template <
class TImage>
150 Real wx[2], wy[2], wd[2] = {Real(-1), Real(1)};
151 const int i = ComputeWeights(x, wx);
152 const int j = ComputeWeights(y, wy);
156 if (k < 0 || k >= this->Input()->Z() ||
157 l < 0 || l >= this->Input()->T()) {
158 return this->DefaultValue();
165 for (
int b = 0; b <= 1; ++b) {
167 for (
int a = 0; a <= 1; ++a) {
169 if (this->Input()->IsInsideForeground(ia, jb, k, l)) {
170 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, k, l));
171 val.
_x += wd[a] * wy[b] * coeff;
172 val.
_y += wx[a] * wd[b] * coeff;
174 return this->DefaultValue();
183 template <
class TImage>
template <
class TOtherImage>
186 ::Get2D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 188 Real wx[2], wy[2], wd[2] = {Real(-1), Real(1)};
189 const int i = ComputeWeights(x, wx);
190 const int j = ComputeWeights(y, wy);
198 for (
int b = 0; b <= 1; ++b) {
200 for (
int a = 0; a <= 1; ++a) {
202 coeff = voxel_cast<Real>(input->Get(ia, jb, k, l));
203 val.
_x += wd[a] * wy[b] * coeff;
204 val.
_y += wx[a] * wd[b] * coeff;
212 template <
class TImage>
template <
class TOtherImage>
217 Real wx[2], wy[2], wd[2] = {Real(-1), Real(1)};
218 const int i = ComputeWeights(x, wx);
219 const int j = ComputeWeights(y, wy);
223 if (k < 0 || k >= input->Z() ||
224 l < 0 || l >= input->T()) {
225 return this->DefaultValue();
232 for (
int b = 0; b <= 1; ++b) {
234 for (
int a = 0; a <= 1; ++a) {
236 if (input->IsForeground(ia, jb, k, l)) {
237 coeff = voxel_cast<Real>(input->Get(ia, jb, k, l));
238 val.
_x += wd[a] * wy[b] * coeff;
239 val.
_y += wx[a] * wd[b] * coeff;
241 return this->DefaultValue();
250 template <
class TImage>
253 ::Get3D(
double x,
double y,
double z,
double t)
const 255 Real wx[2], wy[2], wz[2], wd[2] = {Real(-1), Real(1)};
256 const int i = ComputeWeights(x, wx);
257 const int j = ComputeWeights(y, wy);
258 const int k = ComputeWeights(z, wz);
261 if (l < 0 || l >= this->Input()->T()) {
262 return this->DefaultValue();
269 for (
int c = 0; c <= 1; ++c) {
271 if (0 <= kc && kc < this->Input()->Z()) {
272 for (
int b = 0; b <= 1; ++b) {
274 if (0 <= jb && jb < this->Input()->Y()) {
275 for (
int a = 0; a <= 1; ++a) {
277 if (0 <= ia && ia < this->Input()->X()) {
278 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, kc, l));
279 val.
_x += wd[a] * wy[b] * wz[c] * coeff;
280 val.
_y += wx[a] * wd[b] * wz[c] * coeff;
281 val.
_z += wx[a] * wy[b] * wd[c] * coeff;
282 nrm += wx[a] * wy[b] * wz[c];
290 if (nrm > 1e-3) val /= nrm;
291 else val = this->DefaultValue();
297 template <
class TImage>
302 Real wx[2], wy[2], wz[2], wd[2] = {Real(-1), Real(1)};
303 const int i = ComputeWeights(x, wx);
304 const int j = ComputeWeights(y, wy);
305 const int k = ComputeWeights(z, wz);
308 if (l < 0 || l >= this->Input()->T()) {
309 return this->DefaultValue();
316 for (
int c = 0; c <= 1; ++c) {
318 for (
int b = 0; b <= 1; ++b) {
320 for (
int a = 0; a <= 1; ++a) {
322 if (this->Input()->IsInsideForeground(ia, jb, kc, l)) {
323 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, kc, l));
324 val.
_x += wd[a] * wy[b] * wz[c] * coeff;
325 val.
_y += wx[a] * wd[b] * wz[c] * coeff;
326 val.
_z += wx[a] * wy[b] * wd[c] * coeff;
328 return this->DefaultValue();
338 template <
class TImage>
template <
class TOtherImage>
341 ::Get3D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 343 Real wx[2], wy[2], wz[2], wd[2] = {Real(-1), Real(1)};
344 const int i = ComputeWeights(x, wx);
345 const int j = ComputeWeights(y, wy);
346 const int k = ComputeWeights(z, wz);
353 for (
int c = 0; c <= 1; ++c) {
355 for (
int b = 0; b <= 1; ++b) {
357 for (
int a = 0; a <= 1; ++a) {
359 coeff = voxel_cast<Real>(input->Get(ia, jb, kc, l));
360 val.
_x += wd[a] * wy[b] * wz[c] * coeff;
361 val.
_y += wx[a] * wd[b] * wz[c] * coeff;
362 val.
_z += wx[a] * wy[b] * wd[c] * coeff;
371 template <
class TImage>
template <
class TOtherImage>
376 Real wx[2], wy[2], wz[2], wd[2] = {Real(-1), Real(1)};
377 const int i = ComputeWeights(x, wx);
378 const int j = ComputeWeights(y, wy);
379 const int k = ComputeWeights(z, wz);
382 if (l < 0 || l >= input->T()) {
383 return this->DefaultValue();
390 for (
int c = 0; c <= 1; ++c) {
392 for (
int b = 0; b <= 1; ++b) {
394 for (
int a = 0; a <= 1; ++a) {
396 if (input->IsForeground(ia, jb, kc, l)) {
397 coeff = voxel_cast<Real>(input->Get(ia, jb, kc, l));
398 val.
_x += wd[a] * wy[b] * wz[c] * coeff;
399 val.
_y += wx[a] * wd[b] * wz[c] * coeff;
400 val.
_z += wx[a] * wy[b] * wd[c] * coeff;
402 return this->DefaultValue();
412 template <
class TImage>
415 ::Get4D(
double x,
double y,
double z,
double t)
const 417 Real wx[2], wy[2], wz[2], wt[2], wd[2] = {Real(-1), Real(1)};
418 const int i = ComputeWeights(x, wx);
419 const int j = ComputeWeights(y, wy);
420 const int k = ComputeWeights(z, wz);
421 const int l = ComputeWeights(t, wt);
427 for (
int d = 0; d <= 1; ++d) {
429 if (0 <= ld && ld < this->Input()->T()) {
430 for (
int c = 0; c <= 1; ++c) {
432 if (0 <= kc && kc < this->Input()->Z()) {
433 for (
int b = 0; b <= 1; ++b) {
435 if (0 <= jb && jb < this->Input()->Y()) {
436 for (
int a = 0; a <= 1; ++a) {
438 if (0 <= ia && ia < this->Input()->X()) {
439 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, kc, ld));
440 val.
_x += wd[a] * wy[b] * wz[c] * wt[d] * coeff;
441 val.
_y += wx[a] * wd[b] * wz[c] * wt[d] * coeff;
442 val.
_z += wx[a] * wy[b] * wd[c] * wt[d] * coeff;
443 nrm += wx[a] * wy[b] * wz[c] * wt[d];
453 if (nrm > 1e-3) val /= nrm;
454 else val = this->DefaultValue();
460 template <
class TImage>
465 Real wx[2], wy[2], wz[2], wt[2], wd[2] = {Real(-1), Real(1)};
466 const int i = ComputeWeights(x, wx);
467 const int j = ComputeWeights(y, wy);
468 const int k = ComputeWeights(z, wz);
469 const int l = ComputeWeights(t, wt);
475 for (
int d = 0; d <= 1; ++d) {
477 for (
int c = 0; c <= 1; ++c) {
479 for (
int b = 0; b <= 1; ++b) {
481 for (
int a = 0; a <= 1; ++a) {
483 if (this->Input()->IsInsideForeground(ia, jb, kc, ld)) {
484 coeff = voxel_cast<Real>(this->Input()->Get(ia, jb, kc, ld));
485 val.
_x += wd[a] * wy[b] * wz[c] * wt[d] * coeff;
486 val.
_y += wx[a] * wd[b] * wz[c] * wt[d] * coeff;
487 val.
_z += wx[a] * wy[b] * wd[c] * wt[d] * coeff;
489 return this->DefaultValue();
500 template <
class TImage>
template <
class TOtherImage>
503 ::Get4D(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 505 Real wx[2], wy[2], wz[2], wt[2], wd[2] = {Real(-1), Real(1)};
506 const int i = ComputeWeights(x, wx);
507 const int j = ComputeWeights(y, wy);
508 const int k = ComputeWeights(z, wz);
509 const int l = ComputeWeights(t, wt);
515 for (
int d = 0; d <= 1; ++d) {
517 for (
int c = 0; c <= 1; ++c) {
519 for (
int b = 0; b <= 1; ++b) {
521 for (
int a = 0; a <= 1; ++a) {
523 coeff = voxel_cast<Real>(input->Get(ia, jb, kc, ld));
524 val.
_x += wd[a] * wy[b] * wz[c] * wt[d] * coeff;
525 val.
_y += wx[a] * wd[b] * wz[c] * wt[d] * coeff;
526 val.
_z += wx[a] * wy[b] * wd[c] * wt[d] * coeff;
536 template <
class TImage>
template <
class TOtherImage>
541 Real wx[2], wy[2], wz[2], wt[2], wd[2] = {Real(-1), Real(1)};
542 const int i = ComputeWeights(x, wx);
543 const int j = ComputeWeights(y, wy);
544 const int k = ComputeWeights(z, wz);
545 const int l = ComputeWeights(t, wt);
551 for (
int d = 0; d <= 1; ++d) {
553 for (
int c = 0; c <= 1; ++c) {
555 for (
int b = 0; b <= 1; ++b) {
557 for (
int a = 0; a <= 1; ++a) {
559 if (input->IsForeground(ia, jb, kc, ld)) {
560 coeff = voxel_cast<Real>(input->Get(ia, jb, kc, ld));
561 val.
_x += wd[a] * wy[b] * wz[c] * wt[d] * coeff;
562 val.
_y += wx[a] * wd[b] * wz[c] * wt[d] * coeff;
563 val.
_z += wx[a] * wy[b] * wd[c] * wt[d] * coeff;
565 return this->DefaultValue();
576 template <
class TImage>
579 ::Get(
double x,
double y,
double z,
double t)
const 581 switch (this->NumberOfDimensions()) {
582 case 3:
return Get3D(x, y, z, t);
583 case 2:
return Get2D(x, y, z, t);
584 default:
return Get4D(x, y, z, t);
589 template <
class TImage>
594 switch (this->NumberOfDimensions()) {
595 case 3:
return GetWithPadding3D(x, y, z, t);
596 case 2:
return GetWithPadding2D(x, y, z, t);
597 default:
return GetWithPadding4D(x, y, z, t);
602 template <
class TImage>
template <
class TOtherImage>
605 ::Get(
const TOtherImage *input,
double x,
double y,
double z,
double t)
const 607 switch (this->NumberOfDimensions()) {
608 case 3:
return Get3D(input, x, y, z, t);
609 case 2:
return Get2D(input, x, y, z, t);
610 default:
return Get4D(input, x, y, z, t);
615 template <
class TImage>
template <
class TOtherImage>
620 switch (this->NumberOfDimensions()) {
621 case 3:
return GetWithPadding3D(input, x, y, z, t);
622 case 2:
return GetWithPadding2D(input, x, y, z, t);
623 default:
return GetWithPadding4D(input, x, y, z, t);
628 template <
class TImage>
633 return Get(this->Input(), x, y, z, t);
637 template <
class TImage>
642 if (this->Extrapolator()) {
643 return Get(this->Extrapolator(), x, y, z, t);
645 return Get(x, y, z, t);
650 template <
class TImage>
655 return GetWithPadding(this->Input(), x, y, z, t);
659 template <
class TImage>
664 if (this->Extrapolator()) {
665 return GetWithPadding(this->Extrapolator(), x, y, z, t);
667 return GetWithPadding(x, y, z, t);
674 #endif // MIRTK_FastLinearImageGradientFunction_HXX virtual GradientType GetWithPadding(double, double, double=0, double=0) const
GradientType Get2D(double, double, double=0, double=0) const
virtual ~GenericFastLinearImageGradientFunction()
Destructor.
GradientType Get3D(double, double, double=0, double=0) const
string Get(const ParameterList ¶ms, string name)
Get parameter value from parameters list.
virtual GradientType GetOutside(double, double, double=0, double=0) const
Evaluate generic image at an arbitrary location (in pixels)
GenericFastLinearImageGradientFunction()
Default constructor.
virtual GradientType GetWithPaddingInside(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 void Initialize(bool=false)
Initialize interpolation function.
MIRTKCU_API double fdec(double f)
GradientType GetWithPadding3D(double, double, double=0, double=0) const
static int ComputeWeights(double, Real[2])
virtual void BoundingInterval(double, int &, int &) const
GradientType GetWithPadding4D(double, double, double=0, double=0) const
MIRTKCU_API int iround(T x)
Round floating-point value and cast to int.
virtual GradientType Get(double, double, double=0, double=0) const
GradientType GetWithPadding2D(double, double, double=0, double=0) const
GradientType Get4D(double, double, double=0, double=0) const
virtual GradientType GetInside(double, double, double=0, double=0) const
virtual GradientType GetWithPaddingOutside(double, double, double=0, double=0) const