LCOV - code coverage report
Current view: top level - projectors - LutProjector.h (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 0 62 0.0 %
Date: 2022-08-04 03:43:28 Functions: 0 24 0.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "elsaDefines.h"
       4             : #include "Timer.h"
       5             : #include "Luts.hpp"
       6             : #include "SliceTraversal.h"
       7             : #include "LinearOperator.h"
       8             : #include "VolumeDescriptor.h"
       9             : #include "DetectorDescriptor.h"
      10             : #include "DataContainer.h"
      11             : #include "BoundingBox.h"
      12             : #include "Logger.h"
      13             : #include "Blobs.h"
      14             : #include "CartesianIndices.h"
      15             : 
      16             : #include "XrayProjector.h"
      17             : 
      18             : #include "spdlog/fmt/bundled/core.h"
      19             : #include "spdlog/fmt/fmt.h"
      20             : #include "spdlog/fmt/ostr.h"
      21             : 
      22             : namespace elsa
      23             : {
      24             :     template <typename data_t, typename Derived>
      25             :     class LutProjector;
      26             : 
      27             :     template <typename data_t = real_t>
      28             :     class BlobProjector;
      29             : 
      30             :     template <typename data_t = real_t>
      31             :     class BSplineProjector;
      32             : 
      33             :     template <typename data_t>
      34             :     struct XrayProjectorInnerTypes<BlobProjector<data_t>> {
      35             :         using value_type = data_t;
      36             :         using forward_tag = ray_driven_tag;
      37             :         using backward_tag = ray_driven_tag;
      38             :     };
      39             : 
      40             :     template <typename data_t>
      41             :     struct XrayProjectorInnerTypes<BSplineProjector<data_t>> {
      42             :         using value_type = data_t;
      43             :         using forward_tag = ray_driven_tag;
      44             :         using backward_tag = ray_driven_tag;
      45             :     };
      46             : 
      47             :     template <typename data_t, typename Derived>
      48             :     class LutProjector : public XrayProjector<Derived>
      49             :     {
      50             :     public:
      51             :         using self_type = LutProjector<data_t, Derived>;
      52             :         using base_type = XrayProjector<Derived>;
      53             :         using value_type = typename base_type::value_type;
      54             :         using forward_tag = typename base_type::forward_tag;
      55             :         using backward_tag = typename base_type::backward_tag;
      56             : 
      57           0 :         LutProjector(const VolumeDescriptor& domainDescriptor,
      58             :                      const DetectorDescriptor& rangeDescriptor)
      59           0 :             : base_type(domainDescriptor, rangeDescriptor)
      60             :         {
      61             :             // sanity checks
      62           0 :             auto dim = domainDescriptor.getNumberOfDimensions();
      63           0 :             if (dim < 2 || dim > 3) {
      64           0 :                 throw InvalidArgumentError("LutProjector: only supporting 2d/3d operations");
      65             :             }
      66             : 
      67           0 :             if (dim != rangeDescriptor.getNumberOfDimensions()) {
      68           0 :                 throw InvalidArgumentError(
      69             :                     "LutProjector: domain and range dimension need to match");
      70             :             }
      71             : 
      72           0 :             if (rangeDescriptor.getNumberOfGeometryPoses() == 0) {
      73           0 :                 throw InvalidArgumentError("LutProjector: rangeDescriptor without any geometry");
      74             :             }
      75           0 :         }
      76             : 
      77             :         /// default destructor
      78           0 :         ~LutProjector() override = default;
      79             : 
      80             :     private:
      81             :         /// apply the binary method (i.e. forward projection)
      82           0 :         data_t traverseRayForward(const BoundingBox& boundingbox, const RealRay_t& ray,
      83             :                                   const DataContainer<data_t>& x) const
      84             :         {
      85           0 :             const IndexVector_t lower = boundingbox._min.template cast<index_t>();
      86           0 :             const IndexVector_t upper = boundingbox._max.template cast<index_t>();
      87           0 :             const auto support = this->self().support();
      88             : 
      89           0 :             index_t leadingdir = 0;
      90           0 :             ray.direction().array().cwiseAbs().maxCoeff(&leadingdir);
      91             : 
      92           0 :             IndexVector_t distvec = IndexVector_t::Constant(lower.size(), support);
      93           0 :             distvec[leadingdir] = 0;
      94             : 
      95           0 :             auto rangeVal = data_t(0);
      96             : 
      97             :             // Expand bounding box as rays have larger support now
      98           0 :             auto aabb = boundingbox;
      99           0 :             aabb._min.array() -= static_cast<real_t>(support);
     100           0 :             aabb._min[leadingdir] += static_cast<real_t>(support);
     101             : 
     102           0 :             aabb._max.array() += static_cast<real_t>(support);
     103           0 :             aabb._max[leadingdir] -= static_cast<real_t>(support);
     104             : 
     105             :             // Keep this here, as it saves us a couple of allocations on clang
     106           0 :             CartesianIndices neighbours(upper);
     107             : 
     108             :             // --> setup traversal algorithm
     109           0 :             SliceTraversal traversal(boundingbox, ray);
     110             : 
     111           0 :             for (const auto& curVoxel : traversal) {
     112           0 :                 neighbours = neighbours_in_slice(curVoxel, distvec, lower, upper);
     113           0 :                 for (auto neighbour : neighbours) {
     114             :                     // Correct position, such that the distance is still correct
     115           0 :                     const auto correctedPos = neighbour.template cast<real_t>().array() + 0.5;
     116           0 :                     const auto distance = ray.distance(correctedPos);
     117           0 :                     const auto weight = this->self().weight(distance);
     118             : 
     119           0 :                     rangeVal += weight * x(neighbour);
     120             :                 }
     121             :             }
     122             : 
     123           0 :             return rangeVal;
     124           0 :         }
     125             : 
     126           0 :         void traverseRayBackward(const BoundingBox& boundingbox, const RealRay_t& ray,
     127             :                                  const value_type& detectorValue, DataContainer<data_t>& Aty) const
     128             :         {
     129           0 :             const IndexVector_t lower = boundingbox._min.template cast<index_t>();
     130           0 :             const IndexVector_t upper = boundingbox._max.template cast<index_t>();
     131           0 :             const auto support = this->self().support();
     132             : 
     133           0 :             index_t leadingdir = 0;
     134           0 :             ray.direction().array().cwiseAbs().maxCoeff(&leadingdir);
     135             : 
     136           0 :             IndexVector_t distvec = IndexVector_t::Constant(lower.size(), support);
     137           0 :             distvec[leadingdir] = 0;
     138             : 
     139             :             // Expand bounding box as rays have larger support now
     140           0 :             auto aabb = boundingbox;
     141           0 :             aabb._min.array() -= static_cast<real_t>(support);
     142           0 :             aabb._min[leadingdir] += static_cast<real_t>(support);
     143             : 
     144           0 :             aabb._max.array() += static_cast<real_t>(support);
     145           0 :             aabb._max[leadingdir] -= static_cast<real_t>(support);
     146             : 
     147             :             // Keep this here, as it saves us a couple of allocations on clang
     148           0 :             CartesianIndices neighbours(upper);
     149             : 
     150             :             // --> setup traversal algorithm
     151           0 :             SliceTraversal traversal(aabb, ray);
     152             : 
     153           0 :             for (const auto& curVoxel : traversal) {
     154           0 :                 neighbours = neighbours_in_slice(curVoxel, distvec, lower, upper);
     155           0 :                 for (auto neighbour : neighbours) {
     156             :                     // Correct position, such that the distance is still correct
     157           0 :                     const auto correctedPos = neighbour.template cast<real_t>().array() + 0.5;
     158           0 :                     const auto distance = ray.distance(correctedPos);
     159           0 :                     const auto weight = this->self().weight(distance);
     160             : 
     161           0 : #pragma omp atomic
     162           0 :                     Aty(neighbour) += weight * detectorValue;
     163             :                 }
     164             :             }
     165           0 :         }
     166             : 
     167             :         /// implement the polymorphic clone operation
     168             :         LutProjector<data_t, Derived>* _cloneImpl() const
     169             :         {
     170             :             return new LutProjector(downcast<VolumeDescriptor>(*this->_domainDescriptor),
     171             :                                     downcast<DetectorDescriptor>(*this->_rangeDescriptor));
     172             :         }
     173             : 
     174             :         /// implement the polymorphic comparison operation
     175             :         bool _isEqual(const LinearOperator<data_t>& other) const
     176             :         {
     177             :             if (!LinearOperator<data_t>::isEqual(other))
     178             :                 return false;
     179             : 
     180             :             auto otherOp = downcast_safe<LutProjector>(&other);
     181             :             return static_cast<bool>(otherOp);
     182             :         }
     183             : 
     184             :         friend class XrayProjector<Derived>;
     185             :     };
     186             : 
     187             :     template <typename data_t>
     188             :     class BlobProjector : public LutProjector<data_t, BlobProjector<data_t>>
     189             :     {
     190             :     public:
     191             :         using self_type = BlobProjector<data_t>;
     192             : 
     193             :         BlobProjector(data_t radius, data_t alpha, data_t order,
     194             :                       const VolumeDescriptor& domainDescriptor,
     195             :                       const DetectorDescriptor& rangeDescriptor);
     196             : 
     197             :         BlobProjector(const VolumeDescriptor& domainDescriptor,
     198             :                       const DetectorDescriptor& rangeDescriptor);
     199             : 
     200           0 :         data_t weight(data_t distance) const { return lut_(distance); }
     201             : 
     202           0 :         index_t support() const { return static_cast<index_t>(std::ceil(lut_.radius())); }
     203             : 
     204             :         /// implement the polymorphic clone operation
     205             :         BlobProjector<data_t>* _cloneImpl() const;
     206             : 
     207             :         /// implement the polymorphic comparison operation
     208             :         bool _isEqual(const LinearOperator<data_t>& other) const;
     209             : 
     210             :     private:
     211             :         ProjectedBlobLut<data_t, 100> lut_;
     212             : 
     213             :         using Base = LutProjector<data_t, BlobProjector<data_t>>;
     214             : 
     215             :         friend class XrayProjector<self_type>;
     216             :     };
     217             : 
     218             :     template <typename data_t>
     219             :     class BSplineProjector : public LutProjector<data_t, BSplineProjector<data_t>>
     220             :     {
     221             :     public:
     222             :         using self_type = BlobProjector<data_t>;
     223             : 
     224             :         BSplineProjector(data_t degree, const VolumeDescriptor& domainDescriptor,
     225             :                          const DetectorDescriptor& rangeDescriptor);
     226             : 
     227             :         BSplineProjector(const VolumeDescriptor& domainDescriptor,
     228             :                          const DetectorDescriptor& rangeDescriptor);
     229             : 
     230             :         data_t weight(data_t distance) const;
     231             : 
     232             :         index_t support() const;
     233             : 
     234             :         /// implement the polymorphic clone operation
     235             :         BSplineProjector<data_t>* _cloneImpl() const;
     236             : 
     237             :         /// implement the polymorphic comparison operation
     238             :         bool _isEqual(const LinearOperator<data_t>& other) const;
     239             : 
     240             :     private:
     241             :         ProjectedBSplineLut<data_t, 100> lut_;
     242             : 
     243             :         using Base = LutProjector<data_t, BSplineProjector<data_t>>;
     244             : 
     245             :         friend class XrayProjector<self_type>;
     246             :     };
     247             : } // namespace elsa

Generated by: LCOV version 1.14