LCOV - code coverage report
Current view: top level - elsa/projectors - BSplines.h (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 58 62 93.5 %
Date: 2024-12-21 07:37:52 Functions: 64 71 90.1 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "elsaDefines.h"
       4             : #include "Assertions.h"
       5             : #include "Math.hpp"
       6             : #include "Luts.hpp"
       7             : 
       8             : #include <cmath>
       9             : 
      10             : namespace elsa
      11             : {
      12             :     namespace bspline
      13             :     {
      14             :         /// @brief Evaluate the 1-dimensional B-Spline of degree m, with m + 2 equally spaced knots
      15             :         ///
      16             :         /// This is based on the implementation given as in e.g.:
      17             :         /// Fast B-spline transforms for continuous image representation and interpolation, Unser
      18             :         /// et. al. (1991), equation 2.2
      19             :         ///
      20             :         /// @param x coordinate to evaluate 1-dimensional B-Spline at
      21             :         /// @param m order of B-Spline
      22             :         template <typename data_t>
      23             :         constexpr data_t bspline1d_evaluate(data_t x, index_t m) noexcept
      24      993052 :         {
      25      993052 :             const auto xs = x + static_cast<data_t>(m + 1) / data_t{2};
      26      993052 :             data_t res = 0;
      27             : 
      28     4329466 :             for (int n = 0; n <= m + 1; ++n) {
      29     3336414 :                 data_t nf = static_cast<data_t>(n);
      30     3336414 :                 const auto tmp1 = math::heaviside<data_t>(xs - nf, 0);
      31     3336414 :                 const auto tmp2 = std::pow<data_t>(xs - nf, m);
      32     3336414 :                 const auto tmp3 = static_cast<data_t>(math::binom(m + 1, n));
      33     3336414 :                 const auto tmp4 = std::pow<data_t>(-1, n) / static_cast<data_t>(math::factorial(m));
      34     3336414 :                 res += static_cast<data_t>(tmp1 * tmp2 * tmp3 * tmp4);
      35     3336414 :             }
      36             : 
      37      993052 :             return res;
      38      993052 :         }
      39             : 
      40             :         /// @brief Evaluate the 1-dimensional B-Spline Derivative of degree m
      41             :         ///
      42             :         /// @param x coordinate to evaluate 1-dimensional B-Spline at
      43             :         /// @param m order of B-Spline
      44             :         template <typename data_t>
      45             :         constexpr data_t bsplineDerivative1d_evaluate(data_t x, index_t m) noexcept
      46      328210 :         {
      47      328210 :             return bspline1d_evaluate(x + 0.5, m - 1) - bspline1d_evaluate(x - 0.5, m - 1);
      48      328210 :         }
      49             : 
      50             :         /// @brief Evaluate n-dimensional B-Spline of degree m. As B-Splines are separable, this is
      51             :         /// just the product of 1-dimensional B-Splines.
      52             :         ///
      53             :         /// @param x n-dimensional coordinate to evaluate B-Spline at
      54             :         /// @param m order of B-Spline
      55             :         template <typename data_t>
      56             :         constexpr data_t nd_bspline_evaluate(const Vector_t<data_t>& x, index_t m) noexcept
      57             :         {
      58             :             data_t res = bspline1d_evaluate(x[0], m);
      59             :             for (int i = 1; i < x.size(); ++i) {
      60             :                 res *= bspline1d_evaluate(x[i], m);
      61             :             }
      62             :             return res;
      63             :         }
      64             : 
      65             :         /// @brief Evaluate n-dimensional B-Spline at a given coordinate for the first dimension,
      66             :         /// and at the center (i.e. `0`) at all the other dimensions. This is particular useful as
      67             :         /// an approximation during the calculation of the line integral
      68             :         ///
      69             :         /// @param x 1-dimensional coordinate to evaluate B-Spline at
      70             :         /// @param m order of B-Spline
      71             :         /// @param dim dimension of B-Spline
      72             :         template <typename data_t>
      73             :         constexpr data_t nd_bspline_centered(data_t x, index_t m, index_t dim) noexcept
      74      164648 :         {
      75      164648 :             data_t res = bspline1d_evaluate<data_t>(x, m);
      76      222369 :             for (int i = 1; i < dim; ++i) {
      77       57721 :                 const auto inc = bspline1d_evaluate<data_t>(0.f, m);
      78       57721 :                 res *= inc;
      79       57721 :             }
      80      164648 :             return res;
      81      164648 :         }
      82             : 
      83             :         /// @brief Evaluate the derivative of an n-dimensional B-Spline at a given coordinate for
      84             :         /// the first dimension, and at the center (i.e. `0`) at all the other dimensions. This is
      85             :         /// particular useful as an approximation during the calculation of the line integral
      86             :         ///
      87             :         /// @param x 1-dimensional coordinate to evaluate B-Spline at
      88             :         /// @param m order of B-Spline
      89             :         /// @param dim dimension of B-Spline
      90             :         template <typename data_t>
      91             :         constexpr data_t nd_bspline_derivative_centered(data_t x, int m, int dim) noexcept
      92      328210 :         {
      93      328210 :             data_t res = bsplineDerivative1d_evaluate(x, m);
      94      442410 :             for (int i = 1; i < dim; ++i) {
      95      114200 :                 const auto inc = bspline1d_evaluate(0., m);
      96      114200 :                 res *= inc;
      97      114200 :             }
      98      328210 :             return res;
      99      328210 :         }
     100             : 
     101             :         static constexpr index_t DEFAULT_ORDER = 2;
     102             :     } // namespace bspline
     103             : 
     104             :     /// @brief Represent a B-Spline basis function of a given dimension and order
     105             :     template <typename data_t>
     106             :     class BSpline
     107             :     {
     108             :     public:
     109             :         BSpline(index_t dim, index_t order);
     110             : 
     111             :         data_t operator()(Vector_t<data_t> x);
     112             : 
     113             :         data_t derivative(data_t s);
     114             : 
     115             :         index_t order() const;
     116             : 
     117             :         data_t radius() const;
     118             : 
     119             :         index_t dim() const;
     120             : 
     121             :     private:
     122             :         /// Dimension of B-Spline
     123             :         index_t dim_;
     124             : 
     125             :         /// Order of B-Spline
     126             :         index_t order_;
     127             :     };
     128             : 
     129             :     /// @brief Represent a projected B-Spline basis function of a given dimension and order.
     130             :     /// Projected B-Splines are again B-Spline of n-1 dimensions. Using the fact, that B-Splines
     131             :     /// are close to symmetrical, we can approximate the projection only based on distance.
     132             :     template <typename data_t, size_t N = DEFAULT_PROJECTOR_LUT_SIZE>
     133             :     class ProjectedBSpline
     134             :     {
     135             :     public:
     136             :         constexpr ProjectedBSpline(index_t dim, index_t order)
     137             :             : dim_(dim),
     138             :               order_(order),
     139             :               radius_((order + 1) * 0.5),
     140      164404 :               lut_([this](data_t s) { return this->operator()<true>(s); }, radius_),
     141             :               derivative_lut_(
     142      164404 :                   [this](data_t s) { return order_ > 0 ? this->derivative<true>(s) : 0; }, radius_),
     143             :               normalized_gradient_lut_(
     144      164404 :                   [this](data_t s) { return order_ > 0 ? this->normalized_gradient(s) : 0; },
     145             :                   radius_)
     146        1668 :         {
     147        1668 :         }
     148             : 
     149             :         template <bool accurate = false>
     150             :         constexpr data_t operator()(data_t x) const
     151      171478 :         {
     152      171478 :             if constexpr (accurate)
     153      164648 :                 return bspline::nd_bspline_centered(x, order_, dim_ - 1);
     154        6830 :             else
     155        6830 :                 return lut_(std::abs(x));
     156      171478 :         }
     157             : 
     158             :         template <bool accurate = false>
     159             :         constexpr data_t derivative(data_t x) const
     160      164206 :         {
     161      164206 :             if constexpr (accurate)
     162      164206 :                 return bspline::nd_bspline_derivative_centered(x, order_, dim_ - 1);
     163      164206 :             else
     164      164206 :                 return derivative_lut_(std::abs(x)) * math::sgn(x);
     165      164206 :         }
     166             : 
     167             :         constexpr data_t normalized_gradient(data_t x) const
     168      164004 :         {
     169             :             // compute f'(x)/x
     170      164004 :             if (x == 0)
     171        1660 :                 x = 1e-10;
     172      164004 :             return bspline::nd_bspline_derivative_centered(x, order_, dim_ - 1) / x;
     173      164004 :         }
     174             : 
     175           2 :         constexpr index_t dim() const { return dim_; }
     176             : 
     177           2 :         constexpr index_t order() const { return order_; }
     178             : 
     179           0 :         constexpr data_t radius() const { return radius_; }
     180             : 
     181        1662 :         constexpr const Lut<data_t, N>& get_lut() const { return lut_; }
     182             : 
     183           2 :         constexpr const Lut<data_t, N>& get_derivative_lut() const { return derivative_lut_; }
     184             : 
     185             :         constexpr const Lut<data_t, N>& get_normalized_gradient_lut() const
     186           0 :         {
     187           0 :             return normalized_gradient_lut_;
     188           0 :         }
     189             : 
     190             :     private:
     191             :         /// Dimension of B-Spline
     192             :         index_t dim_;
     193             : 
     194             :         /// Order of B-Spline
     195             :         index_t order_;
     196             : 
     197             :         /// Radius of B-Spline
     198             :         data_t radius_;
     199             : 
     200             :         /// LUT for projected B-Spline
     201             :         Lut<data_t, N> lut_;
     202             : 
     203             :         /// LUT for projected derivative
     204             :         Lut<data_t, N> derivative_lut_;
     205             : 
     206             :         /// LUT for projected normalized gradient
     207             :         Lut<data_t, N> normalized_gradient_lut_;
     208             :     };
     209             : } // namespace elsa

Generated by: LCOV version 1.14