LCOV - code coverage report
Current view: top level - elsa/core/Descriptors - DetectorDescriptor.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 67 68 98.5 %
Date: 2024-05-16 04:22:26 Functions: 10 10 100.0 %

          Line data    Source code
       1             : #include "DetectorDescriptor.h"
       2             : 
       3             : namespace elsa
       4             : {
       5             :     DetectorDescriptor::DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
       6             :                                            const std::vector<Geometry>& geometryList)
       7             :         : DataDescriptor(numOfCoeffsPerDim), _geometry(geometryList)
       8        5779 :     {
       9             :         // TODO Clarify: What about empty geometryList? Do we want to support it, or throw an
      10             :         // exception?
      11        5779 :     }
      12             : 
      13             :     DetectorDescriptor::DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
      14             :                                            const RealVector_t& spacingPerDim,
      15             :                                            const std::vector<Geometry>& geometryList)
      16             :         : DataDescriptor(numOfCoeffsPerDim, spacingPerDim), _geometry(geometryList)
      17       50629 :     {
      18       50629 :     }
      19             : 
      20             :     RealRay_t DetectorDescriptor::computeRayFromDetectorCoord(const index_t detectorIndex) const
      21      225695 :     {
      22             : 
      23             :         // Return empty, if access out of bounds
      24      225695 :         assert(detectorIndex < getNumberOfCoefficients()
      25      225695 :                && "PlanarDetectorDescriptor::computeRayToDetector(index_t): Assumption "
      26      225695 :                   "detectorIndex smaller than number of coeffs, broken");
      27             : 
      28      225695 :         auto coord = getCoordinateFromIndex(detectorIndex);
      29      225695 :         return computeRayFromDetectorCoord(coord);
      30      225695 :     }
      31             : 
      32             :     RealRay_t DetectorDescriptor::computeRayFromDetectorCoord(const IndexVector_t coord) const
      33      230088 :     {
      34             :         // Assume all of the coordinates are inside of the volume
      35             :         // auto tmp = (coord.array() < getNumberOfCoefficientsPerDimension().array());
      36             :         // assert(tmp.all()
      37             :         // && "DetectorDescriptor::computeRayToDetector(IndexVector_t): Assumption coord "
      38             :         // "in bound wrong");
      39             : 
      40      230088 :         auto dim = getNumberOfDimensions();
      41             : 
      42             :         // Assume dimension of coord is equal to dimension of descriptor
      43      230088 :         assert(dim == coord.size());
      44             : 
      45             :         // Cast to real_t and shift to center of pixel
      46      230088 :         auto detectorCoord = coord.head(dim - 1).template cast<real_t>().array() + 0.5;
      47             : 
      48             :         // Last dimension is always the pose index
      49      230088 :         auto poseIndex = coord[dim - 1];
      50             : 
      51      230088 :         return computeRayFromDetectorCoord(detectorCoord, poseIndex);
      52      230088 :     }
      53             : 
      54             :     const std::vector<Geometry>& DetectorDescriptor::getGeometry() const
      55       40609 :     {
      56       40609 :         return _geometry;
      57       40609 :     }
      58             : 
      59             :     index_t DetectorDescriptor::getNumberOfGeometryPoses() const
      60       65463 :     {
      61       65463 :         return static_cast<index_t>(_geometry.size());
      62       65463 :     }
      63             : 
      64             :     Geometry DetectorDescriptor::getGeometryAt(const index_t index) const
      65       10079 :     {
      66       10079 :         return _geometry.at(asUnsigned(index));
      67       10079 :     }
      68             : 
      69             :     bool DetectorDescriptor::isEqual(const DataDescriptor& other) const
      70          70 :     {
      71          70 :         if (!DataDescriptor::isEqual(other))
      72           0 :             return false;
      73             : 
      74             :         // static cast as type checked in base comparison
      75          70 :         const auto& otherBlock = downcast<const DetectorDescriptor>(other);
      76             : 
      77          70 :         return _geometry == otherBlock._geometry;
      78          70 :     }
      79             : 
      80             :     RealRay_t DetectorDescriptor::computeRayFromDetectorCoord(const RealVector_t& detectorCoord,
      81             :                                                               const index_t poseIndex) const
      82      234399 :     {
      83             :         // Assert that for all dimension of detectorCoord is in bounds and poseIndex can
      84             :         // be index in the _geometry. If not the calculation will not be correct, but
      85             :         // as this is the hot path, I don't want exceptions and unpacking everything
      86             :         // We'll just have to ensure, that we don't mess up in our hot path! :-)
      87      234399 :         assert((detectorCoord.block(0, 0, getNumberOfDimensions() - 1, 0).array()
      88      234399 :                 < getNumberOfCoefficientsPerDimension()
      89      234399 :                       .block(0, 0, getNumberOfDimensions() - 1, 0)
      90      234399 :                       .template cast<real_t>()
      91      234399 :                       .array())
      92      234399 :                    .all()
      93      234399 :                && "PlanarDetectorDescriptor::computeRayToDetector: Assumption detectorCoord in "
      94      234399 :                   "bounds, wrong");
      95      234399 :         assert(asUnsigned(poseIndex) < _geometry.size()
      96      234399 :                && "PlanarDetectorDescriptor::computeRayToDetector: Assumption poseIndex smaller "
      97      234399 :                   "than number of poses, wrong");
      98             : 
      99      234399 :         auto dim = getNumberOfDimensions();
     100             : 
     101             :         // get the pose of trajectory
     102      234399 :         auto geometry = _geometry[asUnsigned(poseIndex)];
     103             : 
     104      234399 :         auto projInvMatrix = geometry.getInverseProjectionMatrix();
     105             : 
     106             :         // homogeneous coordinates [p;1], with p in detector space
     107      234399 :         RealVector_t homogeneousPixelCoord(dim);
     108      234399 :         homogeneousPixelCoord << detectorCoord, 1;
     109             : 
     110             :         // Camera center is always the ray origin
     111      234399 :         auto ro = geometry.getCameraCenter();
     112             : 
     113      234399 :         auto rd = (projInvMatrix * homogeneousPixelCoord) // Matrix-Vector multiplication
     114      234399 :                       .head(dim)                          // Transform to non-homogeneous
     115      234399 :                       .normalized();                      // normalize vector
     116             : 
     117      234399 :         return RealRay_t(ro, rd);
     118      234399 :     }
     119             : 
     120             :     std::pair<RealVector_t, real_t>
     121             :         DetectorDescriptor::projectAndScaleVoxelOnDetector(const RealVector_t& voxelCoord,
     122             :                                                            const index_t poseIndex) const
     123         504 :     {
     124         504 :         assert(asUnsigned(poseIndex) < _geometry.size()
     125         504 :                && "PlanarDetectorDescriptor::computeRayToDetector: Assumption poseIndex smaller "
     126         504 :                   "than number of poses, wrong");
     127             : 
     128             :         // get the pose of trajectory
     129         504 :         const auto& geometry = _geometry[asUnsigned(poseIndex)];
     130             : 
     131         504 :         auto homogeneousVoxelCoord = voxelCoord.homogeneous();
     132             : 
     133             :         // Project voxel center onto detector
     134         504 :         RealVector_t center =
     135         504 :             (geometry.getProjectionMatrix() * homogeneousVoxelCoord).hnormalized();
     136             : 
     137         504 :         auto scaling = geometry.getSourceDetectorDistance()
     138         504 :                        / (geometry.getExtrinsicMatrix() * homogeneousVoxelCoord).norm();
     139             : 
     140         504 :         return {std::move(center), scaling};
     141         504 :     }
     142             : } // namespace elsa

Generated by: LCOV version 1.14