Line data Source code
1 : #pragma once 2 : 3 : #include "LinearOperator.h" 4 : #include "Geometry.h" 5 : #include "BoundingBox.h" 6 : 7 : #include "VolumeDescriptor.h" 8 : #include "DetectorDescriptor.h" 9 : 10 : #include <vector> 11 : #include <utility> 12 : 13 : #include <Eigen/Geometry> 14 : 15 : namespace elsa 16 : { 17 : /** 18 : * @brief Operator representing the discretized X-ray transform in 2d/3d using a simplistic 19 : * binary hit/miss method. 20 : * 21 : * @author Tobias Lasser - initial code, modernization 22 : * @author David Frank - rewrite and fixes 23 : * @author Maximilian Hornung - modularization 24 : * @author Nikola Dinev - fixes 25 : * 26 : * @tparam data_t data type for the domain and range of the operator, defaulting to real_t 27 : * 28 : * The volume is traversed along the rays as specified by the Geometry. Each ray is traversed in 29 : * a continguous fashion (i.e. along long voxel borders, not diagonally) and each traversed 30 : * voxel is counted as a hit with weight 1. 31 : * 32 : * The geometry is represented as a list of projection matrices (see class Geometry), one for 33 : * each acquisition pose. 34 : * 35 : * Forward projection is accomplished using apply(), backward projection using applyAdjoint(). 36 : * This projector is matched. 37 : * 38 : * Warning: This method is not particularly accurate! 39 : */ 40 : template <typename data_t = real_t> 41 : class BinaryMethod : public LinearOperator<data_t> 42 : { 43 : public: 44 : /** 45 : * @brief Constructor for the binary voxel traversal method. 46 : * 47 : * @param[in] domainDescriptor describing the domain of the operator (the volume) 48 : * @param[in] rangeDescriptor describing the range of the operator (the sinogram) 49 : * 50 : * The domain is expected to be 2 or 3 dimensional (volSizeX, volSizeY, [volSizeZ]), 51 : * the range is expected to be matching the domain (detSizeX, [detSizeY], acqPoses). 52 : */ 53 : // BinaryMethod(const DataDescriptor& domainDescriptor, const DataDescriptor& 54 : // rangeDescriptor, const std::vector<Geometry>& geometryList); 55 : 56 : BinaryMethod(const VolumeDescriptor& domainDescriptor, 57 : const DetectorDescriptor& rangeDescriptor); 58 : 59 : /// default destructor 60 46 : ~BinaryMethod() override = default; 61 : 62 : protected: 63 : /// default copy constructor, hidden from non-derived classes to prevent potential slicing 64 : BinaryMethod(const BinaryMethod<data_t>&) = default; 65 : 66 : /// apply the binary method (i.e. forward projection) 67 : void applyImpl(const DataContainer<data_t>& x, DataContainer<data_t>& Ax) const override; 68 : 69 : /// apply the adjoint of the binary method (i.e. backward projection) 70 : void applyAdjointImpl(const DataContainer<data_t>& y, 71 : DataContainer<data_t>& Aty) const override; 72 : 73 : /// implement the polymorphic clone operation 74 : BinaryMethod<data_t>* cloneImpl() const override; 75 : 76 : /// implement the polymorphic comparison operation 77 : bool isEqual(const LinearOperator<data_t>& other) const override; 78 : 79 : private: 80 : /// the bounding box of the volume 81 : BoundingBox _boundingBox; 82 : 83 : /// Reference to DetectorDescriptor stored in LinearOperator 84 : DetectorDescriptor& _detectorDescriptor; 85 : 86 : /// Reference to VolumeDescriptor stored in LinearOperator 87 : VolumeDescriptor& _volumeDescriptor; 88 : 89 : /// the traversal routine (for both apply/applyAdjoint) 90 : template <bool adjoint> 91 : void traverseVolume(const DataContainer<data_t>& vector, 92 : DataContainer<data_t>& result) const; 93 : 94 : /// the traversal routine (for both apply/applyAdjoint) for a particular number of 95 : /// dimensions 96 : template <bool adjoint, int dim> 97 : void doTraverseVolume(const DataContainer<data_t>& vector, 98 : DataContainer<data_t>& result) const; 99 : 100 : /// lift from base class 101 : using LinearOperator<data_t>::_domainDescriptor; 102 : using LinearOperator<data_t>::_rangeDescriptor; 103 : }; 104 : 105 : } // namespace elsa