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 50703 : { 18 50703 : } 19 : 20 : RealRay_t DetectorDescriptor::computeRayFromDetectorCoord(const index_t detectorIndex) const 21 226166 : { 22 : 23 : // Return empty, if access out of bounds 24 226166 : assert(detectorIndex < getNumberOfCoefficients() 25 226166 : && "PlanarDetectorDescriptor::computeRayToDetector(index_t): Assumption " 26 226166 : "detectorIndex smaller than number of coeffs, broken"); 27 : 28 226166 : auto coord = getCoordinateFromIndex(detectorIndex); 29 226166 : return computeRayFromDetectorCoord(coord); 30 226166 : } 31 : 32 : RealRay_t DetectorDescriptor::computeRayFromDetectorCoord(const IndexVector_t coord) const 33 229916 : { 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 229916 : auto dim = getNumberOfDimensions(); 41 : 42 : // Assume dimension of coord is equal to dimension of descriptor 43 229916 : assert(dim == coord.size()); 44 : 45 : // Cast to real_t and shift to center of pixel 46 229916 : auto detectorCoord = coord.head(dim - 1).template cast<real_t>().array() + 0.5; 47 : 48 : // Last dimension is always the pose index 49 229916 : auto poseIndex = coord[dim - 1]; 50 : 51 229916 : return computeRayFromDetectorCoord(detectorCoord, poseIndex); 52 229916 : } 53 : 54 : const std::vector<Geometry>& DetectorDescriptor::getGeometry() const 55 40631 : { 56 40631 : return _geometry; 57 40631 : } 58 : 59 : index_t DetectorDescriptor::getNumberOfGeometryPoses() const 60 71354 : { 61 71354 : return static_cast<index_t>(_geometry.size()); 62 71354 : } 63 : 64 : Geometry DetectorDescriptor::getGeometryAt(const index_t index) const 65 10788 : { 66 10788 : return _geometry.at(asUnsigned(index)); 67 10788 : } 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 234525 : { 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 234525 : assert((detectorCoord.block(0, 0, getNumberOfDimensions() - 1, 0).array() 88 234525 : < getNumberOfCoefficientsPerDimension() 89 234525 : .block(0, 0, getNumberOfDimensions() - 1, 0) 90 234525 : .template cast<real_t>() 91 234525 : .array()) 92 234525 : .all() 93 234525 : && "PlanarDetectorDescriptor::computeRayToDetector: Assumption detectorCoord in " 94 234525 : "bounds, wrong"); 95 234525 : assert(asUnsigned(poseIndex) < _geometry.size() 96 234525 : && "PlanarDetectorDescriptor::computeRayToDetector: Assumption poseIndex smaller " 97 234525 : "than number of poses, wrong"); 98 : 99 234525 : auto dim = getNumberOfDimensions(); 100 : 101 : // get the pose of trajectory 102 234525 : auto geometry = _geometry[asUnsigned(poseIndex)]; 103 : 104 234525 : auto projInvMatrix = geometry.getInverseProjectionMatrix(); 105 : 106 : // homogeneous coordinates [p;1], with p in detector space 107 234525 : RealVector_t homogeneousPixelCoord(dim); 108 234525 : homogeneousPixelCoord << detectorCoord, 1; 109 : 110 : // Camera center is always the ray origin 111 234525 : auto ro = geometry.getCameraCenter(); 112 : 113 234525 : auto rd = (projInvMatrix * homogeneousPixelCoord) // Matrix-Vector multiplication 114 234525 : .head(dim) // Transform to non-homogeneous 115 234525 : .normalized(); // normalize vector 116 : 117 234525 : return RealRay_t(ro, rd); 118 234525 : } 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