LCOV - code coverage report
Current view: top level - core/tests - test_PlanarDetectorDescriptor.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 148 148 100.0 %
Date: 2022-02-28 03:37:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_PlanarDetectorDescriptor.cpp
       3             :  *
       4             :  * @brief Test for PlanarDetectorDescriptor
       5             :  *
       6             :  * @author David Frank - initial code
       7             :  */
       8             : 
       9             : #include "doctest/doctest.h"
      10             : 
      11             : #include "PlanarDetectorDescriptor.h"
      12             : #include "VolumeDescriptor.h"
      13             : 
      14             : using namespace elsa;
      15             : using namespace elsa::geometry;
      16             : using namespace doctest;
      17             : 
      18             : using Ray = DetectorDescriptor::Ray;
      19             : 
      20             : TEST_SUITE_BEGIN("core");
      21             : 
      22          10 : TEST_CASE("PlanarDetectorDescriptor: Testing 2D PlanarDetectorDescriptor")
      23             : {
      24          20 :     GIVEN("Given a 5x5 Volume and a single 5 wide detector pose")
      25             :     {
      26          20 :         IndexVector_t volSize(2);
      27          10 :         volSize << 5, 5;
      28          20 :         VolumeDescriptor ddVol(volSize);
      29             : 
      30          20 :         IndexVector_t sinoSize(2);
      31          10 :         sinoSize << 5, 1;
      32             : 
      33          10 :         real_t s2c = 10;
      34          10 :         real_t c2d = 4;
      35             : 
      36             :         Geometry g(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d}, Radian{0},
      37          20 :                    VolumeData2D{Size2D{volSize}}, SinogramData2D{Size2D{sinoSize}});
      38             : 
      39          40 :         PlanarDetectorDescriptor desc(sinoSize, {g});
      40             : 
      41          11 :         WHEN("Retreiving the single geometry pose")
      42             :         {
      43           2 :             auto geom = desc.getGeometryAt(0);
      44           2 :             auto geomList = desc.getGeometry();
      45             : 
      46           1 :             CHECK_EQ(desc.getNumberOfGeometryPoses(), 1);
      47           1 :             CHECK_EQ(geomList.size(), 1);
      48             : 
      49           2 :             THEN("Geometry is equal")
      50             :             {
      51           1 :                 CHECK_EQ((geom), g);
      52           1 :                 CHECK_EQ(geomList[0], g);
      53             :             }
      54             :         }
      55             : 
      56          11 :         WHEN("Generating rays for detecor pixels 0, 2 and 4")
      57             :         {
      58           4 :             for (real_t detPixel : std::initializer_list<real_t>{0, 2, 4}) {
      59           6 :                 RealVector_t pixel(1);
      60           3 :                 pixel << detPixel + 0.5f;
      61             : 
      62             :                 // Check that ray for IndexVector_t is equal to previous one
      63           6 :                 auto ray = desc.computeRayFromDetectorCoord(pixel, 0);
      64             : 
      65             :                 // Create variables, which make typing quicker
      66           6 :                 auto ro = ray.origin();
      67           6 :                 auto rd = ray.direction();
      68             : 
      69             :                 // Check that ray origin is camera center
      70           3 :                 auto c = g.getCameraCenter();
      71           3 :                 CHECK_EQ((ro - c).sum(), Approx(0));
      72             : 
      73             :                 // compute intersection manually
      74           3 :                 real_t t = Approx(rd[0]) == 0 ? (s2c + c2d) : ((pixel[0] - ro[0]) / rd[0]);
      75             : 
      76           3 :                 auto detCoordY = ro[1] + t * rd[1];
      77             : 
      78           3 :                 CHECK_EQ(detCoordY, Approx(ddVol.getLocationOfOrigin()[1] + c2d));
      79             :             }
      80             :         }
      81          13 :         WHEN("Computing detector coord from ray")
      82             :         {
      83           6 :             auto ro = g.getCameraCenter();
      84           6 :             auto rd = RealVector_t(2);
      85             : 
      86           4 :             THEN("The detector coord is correct")
      87             :             {
      88           1 :                 rd << -0.141421f, 0.989949f;
      89           1 :                 rd.normalize();
      90             : 
      91           1 :                 auto detCoord = desc.computeDetectorCoordFromRay(Ray(ro, rd), 0);
      92           1 :                 CHECK_EQ(detCoord[0], Approx(0.5).epsilon(0.05));
      93             :             }
      94           4 :             THEN("The detector coord is correct asd")
      95             :             {
      96           1 :                 rd << 0.f, 1.f;
      97           1 :                 rd.normalize();
      98             : 
      99           1 :                 auto detCoord = desc.computeDetectorCoordFromRay(Ray(ro, rd), 0);
     100           1 :                 CHECK_EQ(detCoord[0], Approx(2.5));
     101             :             }
     102             : 
     103           4 :             THEN("The detector coord is correct asd")
     104             :             {
     105           1 :                 rd << 0.141421f, 0.989949f;
     106           1 :                 rd.normalize();
     107             : 
     108           1 :                 auto detCoord = desc.computeDetectorCoordFromRay(Ray(ro, rd), 0);
     109           1 :                 CHECK_EQ(detCoord[0], Approx(4.5).epsilon(0.05));
     110             :             }
     111             :         }
     112             : 
     113          15 :         GIVEN("Given a 5x5 Volume and a multiple 5 wide detector pose")
     114             :         {
     115          10 :             IndexVector_t volSize(2);
     116           5 :             volSize << 5, 5;
     117          10 :             VolumeDescriptor ddVol(volSize);
     118             : 
     119          10 :             IndexVector_t sinoSize(2);
     120           5 :             sinoSize << 5, 4;
     121             : 
     122           5 :             real_t s2c = 10;
     123           5 :             real_t c2d = 4;
     124             : 
     125             :             Geometry g1(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d}, Degree{0},
     126          10 :                         VolumeData2D{Size2D{volSize}}, SinogramData2D{Size2D{sinoSize}});
     127             :             Geometry g2(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d}, Degree{90},
     128          10 :                         VolumeData2D{Size2D{volSize}}, SinogramData2D{Size2D{sinoSize}});
     129             :             Geometry g3(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d}, Degree{180},
     130          10 :                         VolumeData2D{Size2D{volSize}}, SinogramData2D{Size2D{sinoSize}});
     131             :             Geometry g4(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d}, Degree{270},
     132          10 :                         VolumeData2D{Size2D{volSize}}, SinogramData2D{Size2D{sinoSize}});
     133             : 
     134          35 :             PlanarDetectorDescriptor desc(sinoSize, {g1, g2, g3, g4});
     135             : 
     136           9 :             WHEN("Retreiving geometry poses")
     137             :             {
     138           8 :                 auto geom = desc.getGeometryAt(0);
     139           8 :                 auto geomList = desc.getGeometry();
     140             : 
     141           4 :                 CHECK_EQ(desc.getNumberOfGeometryPoses(), 4);
     142           4 :                 CHECK_EQ(geomList.size(), 4);
     143             : 
     144           5 :                 THEN("Geometry is equal")
     145             :                 {
     146           1 :                     CHECK_EQ((desc.getGeometryAt(0)), g1);
     147           1 :                     CHECK_EQ(geomList[0], g1);
     148             :                 }
     149           5 :                 THEN("Geometry is equal")
     150             :                 {
     151           1 :                     CHECK_EQ((desc.getGeometryAt(1)), g2);
     152           1 :                     CHECK_EQ(geomList[1], g2);
     153             :                 }
     154           5 :                 THEN("Geometry is equal")
     155             :                 {
     156           1 :                     CHECK_EQ((desc.getGeometryAt(2)), g3);
     157           1 :                     CHECK_EQ(geomList[2], g3);
     158             :                 }
     159           5 :                 THEN("Geometry is equal")
     160             :                 {
     161           1 :                     CHECK_EQ((desc.getGeometryAt(3)), g4);
     162           1 :                     CHECK_EQ(geomList[3], g4);
     163             :                 }
     164             :             }
     165             : 
     166           6 :             WHEN("Check for multiple poses, that all the overloads compute the same rays")
     167             :             {
     168           5 :                 for (index_t pose : {0, 1, 2, 3}) {
     169             : 
     170          16 :                     for (index_t detPixel : {0, 2, 4}) {
     171          24 :                         IndexVector_t pixel(2);
     172          12 :                         pixel << detPixel, pose;
     173             : 
     174          24 :                         RealVector_t pixelReal(1);
     175          12 :                         pixelReal << static_cast<real_t>(detPixel) + 0.5f;
     176             : 
     177             :                         auto ray1 =
     178          24 :                             desc.computeRayFromDetectorCoord(desc.getIndexFromCoordinate(pixel));
     179          24 :                         auto ray2 = desc.computeRayFromDetectorCoord(pixel);
     180          24 :                         auto ray3 = desc.computeRayFromDetectorCoord(pixelReal, pose);
     181             : 
     182          24 :                         auto ro1 = ray1.origin();
     183          24 :                         auto rd1 = ray1.direction();
     184             : 
     185          24 :                         auto ro2 = ray2.origin();
     186          24 :                         auto rd2 = ray2.direction();
     187             : 
     188          24 :                         auto ro3 = ray3.origin();
     189          24 :                         auto rd3 = ray3.direction();
     190             : 
     191          12 :                         CHECK_EQ(ro1, ro2);
     192          12 :                         CHECK_EQ(ro1, ro3);
     193             : 
     194          12 :                         CHECK_EQ(rd1, rd2);
     195          12 :                         CHECK_EQ(rd1, rd3);
     196             : 
     197             :                         // Shouldn't be necessary, but whatever
     198          12 :                         CHECK_EQ(ro2, ro3);
     199          12 :                         CHECK_EQ(rd2, rd3);
     200             :                     }
     201             :                 }
     202             :             }
     203             :         }
     204             :     }
     205          10 : }
     206             : 
     207           2 : TEST_CASE("PlanarDetectorDescriptor: Testing 3D PlanarDetectorDescriptor")
     208             : {
     209           4 :     GIVEN("Given a 5x5x5 Volume and a single 5x5 wide detector pose")
     210             :     {
     211           4 :         IndexVector_t volSize(3);
     212           2 :         volSize << 5, 5, 5;
     213           4 :         VolumeDescriptor ddVol(volSize);
     214             : 
     215           4 :         IndexVector_t sinoSize(3);
     216           2 :         sinoSize << 5, 5, 1;
     217             : 
     218           2 :         real_t s2c = 10;
     219           2 :         real_t c2d = 4;
     220             : 
     221             :         Geometry g(SourceToCenterOfRotation{s2c}, CenterOfRotationToDetector{c2d},
     222           4 :                    VolumeData3D{Size3D{volSize}}, SinogramData3D{Size3D{sinoSize}},
     223           8 :                    RotationAngles3D{Gamma{0}});
     224             : 
     225           8 :         PlanarDetectorDescriptor desc(sinoSize, {g});
     226             : 
     227           3 :         WHEN("Retreiving the single geometry pose")
     228             :         {
     229           2 :             auto geom = desc.getGeometryAt(0);
     230           2 :             auto geomList = desc.getGeometry();
     231             : 
     232           1 :             CHECK_EQ(desc.getNumberOfGeometryPoses(), 1);
     233           1 :             CHECK_EQ(geomList.size(), 1);
     234             : 
     235           2 :             THEN("Geometry is equal")
     236             :             {
     237           1 :                 CHECK_EQ((geom), g);
     238           1 :                 CHECK_EQ(geomList[0], g);
     239             :             }
     240             :         }
     241             : 
     242           3 :         WHEN("Generating rays for detecor pixels 0, 2 and 4 for each dim")
     243             :         {
     244           4 :             for (index_t detPixel1 : {0, 2, 4}) {
     245          12 :                 for (index_t detPixel2 : {0, 2, 4}) {
     246          18 :                     RealVector_t pixel(2);
     247           9 :                     pixel << static_cast<real_t>(detPixel1) + 0.5f,
     248           9 :                         static_cast<real_t>(detPixel2) + 0.5f;
     249             : 
     250             :                     // Check that ray for IndexVector_t is equal to previous one
     251          18 :                     auto ray = desc.computeRayFromDetectorCoord(pixel, 0);
     252             : 
     253             :                     // Create variables, which make typing quicker
     254          18 :                     auto ro = ray.origin();
     255          18 :                     auto rd = ray.direction();
     256             : 
     257             :                     // Check that ray origin is camera center
     258          18 :                     auto c = g.getCameraCenter();
     259           9 :                     CHECK_EQ((ro - c).sum(), Approx(0));
     260             : 
     261          18 :                     auto o = ddVol.getLocationOfOrigin();
     262          18 :                     RealVector_t detCoordWorld(3);
     263           9 :                     detCoordWorld << pixel[0] - o[0], pixel[1] - o[1], c2d;
     264           9 :                     RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld + o;
     265             : 
     266           9 :                     real_t factor = 0;
     267           9 :                     if (std::abs(rd[0]) > 0)
     268           6 :                         factor = (rotD[0] - ro[0]) / rd[0];
     269           3 :                     else if (std::abs(rd[1]) > 0)
     270           2 :                         factor = (rotD[1] - ro[1]) / rd[1];
     271           1 :                     else if (std::abs(rd[2]) > 0)
     272           1 :                         factor = (rotD[2] - ro[2] / rd[2]);
     273             : 
     274           9 :                     CHECK_EQ((ro[0] + factor * rd[0]), Approx(rotD[0]));
     275           9 :                     CHECK_EQ((ro[1] + factor * rd[1]), Approx(rotD[1]));
     276           9 :                     CHECK_EQ((ro[2] + factor * rd[2]), Approx(rotD[2]));
     277             :                 }
     278             :             }
     279             :         }
     280             :     }
     281           2 : }
     282             : 
     283             : TEST_SUITE_END();

Generated by: LCOV version 1.15