... ... @@ -4,6 +4,48 @@ namespace elsa { namespace math { /// Compute factorial \f$n!\f$ recursively constexpr inline index_t factorial(index_t n) noexcept { return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n; } /// Compute binomial coefficient constexpr inline index_t binom(index_t n, index_t k) noexcept { return (k > n) ? 0 : (k == 0 || k == n) ? 1 : (k == 1 || k == n - 1) ? n : (k + k < n) ? (binom(n - 1, k - 1) * n) / k : (binom(n - 1, k) * n) / (n - k); } /// Compute Heaviside-function /// \f[ /// x \mapsto /// \begin{cases} /// 0: & x < 0 \\ /// c: & x = 0 \\ /// 1: & x > 0 /// \end{cases} /// \f] template constexpr data_t heaviside(data_t x1, data_t c) { if (x1 == 0) { return c; } else if (x1 < 0) { return 0; } else { return 1; } } } // namespace math /// proposed in Y. Meyer, Oscillating Patterns in Image Processing and Nonlinear Evolution /// Equations. AMS, 2001 template ... ...
 #pragma once #include "elsaDefines.h" #include "Assertions.h" #include "Math.hpp" #include #include "spdlog/fmt/bundled/core.h" #include "spdlog/fmt/fmt.h" namespace elsa { namespace bspline { /// @brief Evaluate the 1-dimensional B-Spline of degree m, with m + 2 equally spaced knots /// /// This is based on the implementation given as in e.g.: /// Fast B-spline transforms for continuous image representation and interpolation, Unser /// et. al. (1991), equation 2.2 /// /// @param x coordinate to evaluate 1-dimensional B-Spline at /// @param m order of B-Spline template constexpr data_t bspline1d_evaluate(data_t x, index_t m) noexcept { const auto xs = x + (m + 1) / data_t{2}; data_t res = 0; for (int n = 0; n <= m + 1; ++n) { const auto tmp1 = math::heaviside(xs - n, 0); const auto tmp2 = std::pow(xs - n, m); const auto tmp3 = math::binom(m + 1, n); const auto tmp4 = std::pow(-1, n) / math::factorial(m); res += tmp1 * tmp2 * tmp3 * tmp4; } return res; } /// @brief Evaluate n-dimensional B-Spline of degree m. As B-Splines are separable, this is /// just the product of 1-dimensional B-Splines. /// /// @param x n-dimensional coordinate to evaluate B-Spline at /// @param m order of B-Spline template constexpr data_t nd_bspline_evaluate(const Vector_t& x, index_t m) noexcept { data_t res = bspline1d_evaluate(x[0], m); for (int i = 1; i < x.size(); ++i) { res *= bspline1d_evaluate(x[i], m); } return res; } /// @brief Evaluate n-dimensional B-Spline at a given coordinate for the first dimension, /// and at the center (i.e. 0) at all the other dimensions. This is particular useful as /// an approximation during the calculation of the line integral /// /// @param x 1-dimensional coordinate to evaluate B-Spline at /// @param m order of B-Spline /// @param dim dimension of B-Spline template constexpr data_t nd_bspline_centered(data_t x, int m, int dim) noexcept { data_t res = bspline1d_evaluate(x, m); for (int i = 1; i < dim; ++i) { const auto inc = bspline1d_evaluate(0., m); res *= inc; } return res; } } // namespace bspline /// @brief Represent a B-Spline basis function of a given dimension and order template class BSpline { public: BSpline(index_t dim, index_t order); data_t operator()(Vector_t x); index_t order() const; index_t dim() const; private: /// Dimension of B-Spline index_t dim_; /// Order of B-Spline index_t order_; }; /// @brief Represent a projected B-Spline basis function of a given dimension and order. /// Projected B-Splines are again B-Spline of n-1 dimensions. Using the fact, that B-Splines /// are close to symmetrical, we can approximate the projection only based on distance. template class ProjectedBSpline { public: ProjectedBSpline(index_t dim, index_t order); data_t operator()(data_t s); index_t order() const; index_t dim() const; private: /// Dimension of B-Spline index_t dim_; /// Order of B-Spline index_t order_; }; } // namespace elsa