17#ifndef __interp_linear_h__
18#define __interp_linear_h__
96 template <
class ImageType, LinearInterpProcessingType PType>
99 using typename Base<ImageType>::value_type;
112 ssize_t
clamp (ssize_t x, ssize_t dim)
const {
114 if (x >= dim)
return (dim-1);
120 template <
class ImageType, LinearInterpProcessingType PType>
129 template <
class ImageType>
137 using coef_type =
typename LinearBase::coef_type;
139 using LinearBase::clamp;
140 using LinearBase::bounds;
141 using LinearBase::eps;
149 template <
class VectorType>
150 bool voxel (
const VectorType& pos) {
155 for (
size_t i = 0; i < 3; ++i) {
156 if (pos[i] < 0.0 || pos[i] >
bounds[i]-0.5)
160 coef_type x_weights[2] = { coef_type(1 - f[0]), coef_type(f[0]) };
161 coef_type y_weights[2] = { coef_type(1 - f[1]), coef_type(f[1]) };
162 coef_type z_weights[2] = { coef_type(1 - f[2]), coef_type(f[2]) };
165 for (ssize_t z = 0; z < 2; ++z) {
166 for (ssize_t y = 0; y < 2; ++y) {
167 coef_type partial_weight = y_weights[y] * z_weights[z];
168 for (ssize_t x = 0; x < 2; ++x) {
169 factors[i] = x_weights[x] * partial_weight;
171 if (factors[i] <
eps)
184 template <
class VectorType>
191 template <
class VectorType>
202 Eigen::Matrix<value_type, 8, 1> coeff_vec;
205 for (ssize_t z = 0; z < 2; ++z) {
207 for (ssize_t y = 0; y < 2; ++y) {
209 for (ssize_t x = 0; x < 2; ++x) {
216 return coeff_vec.dot (factors);
221 Eigen::Matrix<value_type, Eigen::Dynamic, 1> row (
size_t axis) {
223 Eigen::Matrix<value_type, Eigen::Dynamic, 1> out_of_bounds_row (ImageType::size(
axis));
224 out_of_bounds_row.setOnes();
226 return out_of_bounds_row;
231 Eigen::Matrix<value_type, Eigen::Dynamic, 8> coeff_matrix ( ImageType::size(3), 8 );
234 for (ssize_t z = 0; z < 2; ++z) {
236 for (ssize_t y = 0; y < 2; ++y) {
238 for (ssize_t x = 0; x < 2; ++x) {
240 coeff_matrix.col (i++) = ImageType::row (
axis);
245 return coeff_matrix * factors;
255 template <
class ImageType>
263 using coef_type =
typename LinearBase::coef_type;
265 using LinearBase::clamp;
266 using LinearBase::bounds;
267 using LinearBase::voxelsize;
271 out_of_bounds_vec (value_when_out_of_bounds, value_when_out_of_bounds, value_when_out_of_bounds),
277 template <
class VectorType>
278 bool voxel (
const VectorType& pos) {
283 for (
size_t i = 0; i < 3; ++i) {
284 if (pos[i] < 0.0 || pos[i] >
bounds[i]-0.5)
288 coef_type x_weights[2] = {coef_type(1 - f[0]), coef_type(f[0])};
289 coef_type y_weights[2] = {coef_type(1 - f[1]), coef_type(f[1])};
290 coef_type z_weights[2] = {coef_type(1 - f[2]), coef_type(f[2])};
294 coef_type diff_weights[2] = {-0.5, 0.5};
297 for (ssize_t z = 0; z < 2; ++z) {
298 for (ssize_t y = 0; y < 2; ++y) {
299 coef_type partial_weight = y_weights[y] * z_weights[z];
300 coef_type partial_weight_dy = diff_weights[y] * z_weights[z];
301 coef_type partial_weight_dz = y_weights[y] * diff_weights[z];
303 for (ssize_t x = 0; x < 2; ++x) {
304 weights_matrix(i,0) = diff_weights[x] * partial_weight;
305 weights_matrix(i,1) = x_weights[x] * partial_weight_dy;
306 weights_matrix(i,2) = x_weights[x] * partial_weight_dz;
318 template <
class VectorType>
325 template <
class VectorType>
331 FORCE_INLINE Eigen::Matrix<value_type, 1, 3> gradient () {
333 return out_of_bounds_vec;
337 Eigen::Matrix<coef_type, 1, 8> coeff_vec;
340 for (ssize_t z = 0; z < 2; ++z) {
342 for (ssize_t y = 0; y < 2; ++y) {
344 for (ssize_t x = 0; x < 2; ++x) {
351 return coeff_vec * weights_matrix;
355 Eigen::Matrix<default_type, Eigen::Dynamic, Eigen::Dynamic> gradient_wrt_scanner() {
356 return gradient().template cast<default_type>() * wrt_scanner_transform;
360 Eigen::Matrix<coef_type, Eigen::Dynamic, 3> gradient_row() {
362 Eigen::Matrix<coef_type, Eigen::Dynamic, 3> out_of_bounds_matrix (ImageType::size(3), 3);
363 out_of_bounds_matrix.setOnes();
365 return out_of_bounds_matrix;
368 assert (ImageType::ndim() == 4);
372 Eigen::Matrix<value_type, Eigen::Dynamic, 8> coeff_matrix (ImageType::size(3), 8);
375 for (ssize_t z = 0; z < 2; ++z) {
377 for (ssize_t y = 0; y < 2; ++y) {
379 for (ssize_t x = 0; x < 2; ++x) {
381 coeff_matrix.col (i++) = ImageType::row (3);
386 return coeff_matrix * weights_matrix;
391 Eigen::Matrix<default_type, Eigen::Dynamic, 3> gradient_row_wrt_scanner() {
392 return gradient_row().template cast<default_type>() * wrt_scanner_transform;
404 template <
class ImageType>
406 public LinearInterpBase <ImageType, LinearInterpProcessingType::ValueAndDerivative>
412 using coef_type =
typename LinearBase::coef_type;
414 using LinearBase::clamp;
415 using LinearBase::bounds;
416 using LinearBase::voxelsize;
422 if (ImageType::ndim() == 4) {
423 out_of_bounds_vec.resize(ImageType::size(3), 1);
424 out_of_bounds_matrix.resize(ImageType::size(3), 3);
426 out_of_bounds_vec.resize(1, 1);
427 out_of_bounds_matrix.resize(1, 3);
429 out_of_bounds_vec.fill(value_when_out_of_bounds);
430 out_of_bounds_matrix.fill(value_when_out_of_bounds);
433 value_type
value () { assert( 0 &&
"do not call value() on ValueAndDerivative interpolator." ); }
437 template <
class VectorType>
438 bool voxel (
const VectorType& pos) {
443 for (
size_t i = 0; i < 3; ++i) {
444 if (pos[i] < 0.0 || pos[i] >
bounds[i]-0.5)
448 coef_type x_weights[2] = { coef_type(1 - f[0]), coef_type(f[0]) };
449 coef_type y_weights[2] = { coef_type(1 - f[1]), coef_type(f[1]) };
450 coef_type z_weights[2] = { coef_type(1 - f[2]), coef_type(f[2]) };
454 coef_type diff_weights[2] = {coef_type(-0.5), coef_type(0.5) };
457 for (ssize_t z = 0; z < 2; ++z) {
458 for (ssize_t y = 0; y < 2; ++y) {
459 coef_type partial_weight = y_weights[y] * z_weights[z];
460 coef_type partial_weight_dy = diff_weights[y] * z_weights[z];
461 coef_type partial_weight_dz = y_weights[y] * diff_weights[z];
463 for (ssize_t x = 0; x < 2; ++x) {
465 weights_matrix(i,0) = diff_weights[x] * partial_weight;
466 weights_matrix(i,1) = x_weights[x] * partial_weight_dy;
467 weights_matrix(i,2) = x_weights[x] * partial_weight_dz;
469 weights_matrix(i,3) = x_weights[x] * partial_weight;
481 template <
class VectorType>
488 template <
class VectorType>
494 void value_and_gradient (value_type&
value, Eigen::Matrix<coef_type, 1, 3>& gradient) {
496 value = out_of_bounds_vec(0);
497 gradient.fill(out_of_bounds_vec(0));
503 Eigen::Matrix<value_type, 1, 8> coeff_vec;
506 for (ssize_t z = 0; z < 2; ++z) {
508 for (ssize_t y = 0; y < 2; ++y) {
510 for (ssize_t x = 0; x < 2; ++x) {
518 Eigen::Matrix<value_type, 1, 4> grad_and_value (coeff_vec * weights_matrix);
520 gradient = grad_and_value.head(3);
521 value = grad_and_value[3];
524 void value_and_gradient_wrt_scanner (value_type&
value, Eigen::Matrix<coef_type, 1, 3>& gradient) {
526 value = out_of_bounds_vec(0);
527 gradient.fill(out_of_bounds_vec(0));
530 value_and_gradient(
value, gradient);
531 gradient = (gradient.template cast<default_type>() * wrt_scanner_transform).
eval();
535 void value_and_gradient_row (Eigen::Matrix<value_type, Eigen::Dynamic, 1>&
value, Eigen::Matrix<value_type, Eigen::Dynamic, 3>& gradient) {
537 value = out_of_bounds_vec;
538 gradient = out_of_bounds_matrix;
542 assert (ImageType::ndim() == 4);
546 Eigen::Matrix<value_type, Eigen::Dynamic, 8> coeff_matrix (ImageType::size(3), 8);
549 for (ssize_t z = 0; z < 2; ++z) {
551 for (ssize_t y = 0; y < 2; ++y) {
553 for (ssize_t x = 0; x < 2; ++x) {
555 coeff_matrix.col (i++) = ImageType::row (3);
560 Eigen::Matrix<value_type, Eigen::Dynamic, 4> grad_and_value (coeff_matrix * weights_matrix);
561 gradient = grad_and_value.block(0, 0, ImageType::size(3), 3);
562 value = grad_and_value.col(3);
565 void value_and_gradient_row_wrt_scanner (Eigen::Matrix<value_type, Eigen::Dynamic, 1>&
value, Eigen::Matrix<value_type, Eigen::Dynamic, 3>& gradient) {
567 value = out_of_bounds_vec;
568 gradient = out_of_bounds_matrix;
571 value_and_gradient_row(
value, gradient);
572 gradient = (gradient.template cast<default_type>() * wrt_scanner_transform).
eval();
585 template <
typename ImageType>
588 template <
class ImageType,
typename... Args>
This class defines the interface for classes that perform image interpolation.
Eigen::Vector3d intravoxel_offset(const VectorType &pos)
Eigen::Matrix< coef_type, 8, 3 > weights_matrix
const Eigen::Matrix< default_type, 3, 3 > wrt_scanner_transform
const Eigen::Matrix< coef_type, 1, 3 > out_of_bounds_vec
Eigen::Matrix< coef_type, 8, 1 > factors
Eigen::Matrix< default_type, 3, 3 > wrt_scanner_transform
Eigen::Matrix< coef_type, Eigen::Dynamic, 1 > out_of_bounds_vec
Eigen::Matrix< value_type, 8, 4 > weights_matrix
Eigen::Matrix< coef_type, Eigen::Dynamic, 3 > out_of_bounds_matrix
ssize_t clamp(ssize_t x, ssize_t dim) const
constexpr I floor(const T x)
template function with cast to different type
VectorType::Scalar value(const VectorType &coefs, typename VectorType::Scalar cos_elevation, typename VectorType::Scalar cos_azimuth, typename VectorType::Scalar sin_azimuth, int lmax)
Linear< ImageType > make_linear(const ImageType &parent, Args &&... args)
LinearInterpProcessingType
T eval(const double *coef, const int order, const T lower, const T upper, const T x)
MR::default_type value_type
This class provides access to the voxel intensities of a data set, using tri-linear interpolation.