From 56bbb366461fec54462951a0c2da5b4ae3da04a5 Mon Sep 17 00:00:00 2001 From: Oleg Alexandrov <oleg.alexandrov@gmail.com> Date: Mon, 9 Aug 2021 18:47:21 +0300 Subject: [PATCH] Add fix for ground to image calculation for LRO NAC cameras (#341) * Add fix for ground to image calculation for LRO NAC cameras * Make the choice of the sign of m_iTransL only once at model loading * Reword a comment * Robustness fix, must always ensure fractional part is 0.5 * Remove the abs, cannot assume those values are positive * Added opposite flight and detector test Co-authored-by: Jesse Mapel <jmapel@usgs.gov> --- src/UsgsAstroLsSensorModel.cpp | 32 +++- tests/Fixtures.h | 26 +++ tests/LineScanCameraTests.cpp | 8 + tests/data/flippedOrbitalLineScan.json | 241 +++++++++++++++++++++++++ 4 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 tests/data/flippedOrbitalLineScan.json diff --git a/src/UsgsAstroLsSensorModel.cpp b/src/UsgsAstroLsSensorModel.cpp index b329d34..1fe6bed 100644 --- a/src/UsgsAstroLsSensorModel.cpp +++ b/src/UsgsAstroLsSensorModel.cpp @@ -648,6 +648,36 @@ void UsgsAstroLsSensorModel::updateState() { // Set focal length variance m_covariance[15 * num_params + 15] = positionVariance; + + // Test if a pixel projected to the ground and projected back + // returns to the original location. If not, flip the sign of + // m_iTransL. It is very important here to pick a pixel which is not + // an integer, as this test may succeed for integer pixels and fail + // for non-integer ones. Also, need to pick the answer with the + // smallest achieved precision, even when neither of them is smaller + // than the desired precision. + + lineCtr = round(m_nLines / 2.0) + 0.5; + sampCtr = round(m_nSamples / 2.0) + 0.5; + + double desiredPrecision = 0.001; + ip = csm::ImageCoord(lineCtr, sampCtr); + csm::EcefCoord xyz = imageToGround(ip, refHeight); + + double achievedPrecision1 = 1.0; + // Will use m_iTransL on the next line + ip = groundToImage(xyz, desiredPrecision, &achievedPrecision1); + + double achievedPrecision2 = 1.0; + for (int it = 0; it < sizeof(m_iTransL)/sizeof(double); it++) + m_iTransL[it] = -m_iTransL[it]; // use a flipped m_iTransL + ip = groundToImage(xyz, desiredPrecision, &achievedPrecision2); + + if (std::abs(achievedPrecision1) <= std::abs(achievedPrecision2)) { + // Flip back m_iTransL as the original was better + for (int it = 0; it < sizeof(m_iTransL)/sizeof(double); it++) + m_iTransL[it] = -m_iTransL[it]; + } } //--------------------------------------------------------------------------- @@ -2045,7 +2075,7 @@ std::vector<double> UsgsAstroLsSensorModel::computeDetectorView( bodyToCamera[5] * bodyLookY + bodyToCamera[8] * bodyLookZ; MESSAGE_LOG( - "computeDetectorView: look vector (camrea ref frame)" + "computeDetectorView: look vector (camera ref frame)" "{} {} {}", cameraLookX, cameraLookY, cameraLookZ) diff --git a/tests/Fixtures.h b/tests/Fixtures.h index a6c8848..d606fb0 100644 --- a/tests/Fixtures.h +++ b/tests/Fixtures.h @@ -261,6 +261,32 @@ class OrbitalLineScanSensorModel : public ::testing::Test { } }; +class FlippedOrbitalLineScanSensorModel : public ::testing::Test { + protected: + csm::Isd isd; + UsgsAstroLsSensorModel *sensorModel; + + void SetUp() override { + sensorModel = NULL; + + isd.setFilename("data/flippedOrbitalLineScan.img"); + UsgsAstroPlugin cameraPlugin; + + csm::Model *model = cameraPlugin.constructModelFromISD( + isd, "USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL"); + sensorModel = dynamic_cast<UsgsAstroLsSensorModel *>(model); + + ASSERT_NE(sensorModel, nullptr); + } + + void TearDown() override { + if (sensorModel) { + delete sensorModel; + sensorModel = NULL; + } + } +}; + class TwoLineScanSensorModels : public ::testing::Test { protected: csm::Isd isd; diff --git a/tests/LineScanCameraTests.cpp b/tests/LineScanCameraTests.cpp index 8ae9bd8..f08abb7 100644 --- a/tests/LineScanCameraTests.cpp +++ b/tests/LineScanCameraTests.cpp @@ -276,6 +276,14 @@ TEST_F(OrbitalLineScanSensorModel, ReferenceDateTime) { EXPECT_EQ(date, "2000-01-01T00:16:39Z"); } +TEST_F(FlippedOrbitalLineScanSensorModel, OppositeFlightDetector) { + csm::ImageCoord imagePt(8.7, 8.0); + csm::EcefCoord groundPt = sensorModel->imageToGround(imagePt, 0.0); + csm::ImageCoord backProjImagePt = sensorModel->groundToImage(groundPt); + EXPECT_NEAR(imagePt.line, backProjImagePt.line, 0.001); + EXPECT_NEAR(imagePt.samp, backProjImagePt.samp, 0.001); +} + TEST_F(TwoLineScanSensorModels, CrossCovariance) { std::vector<double> crossCovars = sensorModel1->getCrossCovarianceMatrix(*sensorModel2); diff --git a/tests/data/flippedOrbitalLineScan.json b/tests/data/flippedOrbitalLineScan.json new file mode 100644 index 0000000..3059d9d --- /dev/null +++ b/tests/data/flippedOrbitalLineScan.json @@ -0,0 +1,241 @@ +{ + "name_model" : "USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL", + "name_platform" : "TEST_PLATFORM", + "name_sensor" : "TEST_SENSOR", + "center_ephemeris_time": 1000.0, + "starting_ephemeris_time": 999.2, + "line_scan_rate": [ + [0.5, -0.85, 0.1] + ], + "detector_sample_summing": 1, + "detector_line_summing": 1, + "t0_ephemeris": -0.8, + "dt_ephemeris": 0.1, + "t0_quaternion": -0.8, + "dt_quaternion": 0.1, + "focal2pixel_lines": [0.0, 10.0, 0.0], + "focal2pixel_samples": [0.0, 0.0, 10.0], + "focal_length_model": { + "focal_length": 50 + }, + "image_lines": 16, + "image_samples": 16, + "detector_center" : { + "line" : 0.5, + "sample" : 8.0 + }, + "interpolation_method": "lagrange", + "optical_distortion": { + "radial": { + "coefficients": [0.0, 0.0, 0.0] + } + }, + "radii": { + "semimajor": 1000, + "semiminor": 1000, + "unit":"km" + }, + "reference_height": { + "maxheight": 1000, + "minheight": -1000, + "unit": "m" + }, + "instrument_position": { + "unit": "km", + "positions": [ + [1050.0, 0.0, -0.0], + [1049.99999524, 0.0, -0.1], + [1049.99998095, 0.0, -0.2], + [1049.99995714, 0.0, -0.3], + [1049.99992381, 0.0, -0.39999999], + [1049.99988095, 0.0, -0.49999998], + [1049.99982857, 0.0, -0.59999997], + [1049.99976667, 0.0, -0.69999995], + [1049.99969524, 0.0, -0.79999992], + [1049.99961429, 0.0, -0.89999989], + [1049.99952381, 0.0, -0.99999985], + [1049.99942381, 0.0, -1.0999998], + [1049.99931429, 0.0, -1.19999974], + [1049.99919524, 0.0, -1.29999967], + [1049.99906667, 0.0, -1.39999959], + [1049.99892857, 0.0, -1.49999949] + ], + "velocities": [ + [-0.0, 0.0, -1.0500], + [-0.1, 0.0, -1.04999999524], + [-0.2, 0.0, -1.04999998095], + [-0.3, 0.0, -1.04999995714], + [-0.39999999, 0.0 ,-1.04999992381], + [-0.49999998, 0.0 ,-1.04999988095], + [-0.59999997, 0.0 ,-1.04999982857], + [-0.69999995, 0.0 ,-1.04999976667], + [-0.79999992, 0.0 ,-1.04999969524], + [-0.89999989, 0.0 ,-1.04999961429], + [-0.99999985, 0.0 ,-1.04999952381], + [-1.0999998, 0.0 ,-1.04999942381], + [-1.19999974, 0.0 ,-1.04999931429], + [-1.29999967, 0.0 ,-1.04999919524], + [-1.39999959, 0.0 ,-1.04999906667], + [-1.49999949, 0.0, -1.04999892857] + ], + "ephemeris_times": [ + 999.2, + 999.3, + 999.4, + 999.5, + 999.6, + 999.7, + 999.8, + 999.9, + 1000.0, + 1000.1, + 1000.2, + 1000.3, + 1000.4, + 1000.5, + 1000.6, + 1000.7 + ], + "reference_frame": 1 + }, + "instrument_pointing": { + "quaternions": [ + [0.70710678, 0.0, -0.70710678, 0.0], + [0.70707311, 0.0, -0.70714045, 0.0], + [0.70703943, 0.0, -0.70717412, 0.0], + [0.70700576, 0.0, -0.70720779, 0.0], + [0.70697208, 0.0, -0.70724146, 0.0], + [0.7069384, 0.0, -0.70727512, 0.0], + [0.70690472, 0.0, -0.70730878, 0.0], + [0.70687104, 0.0, -0.70734244, 0.0], + [0.70683736, 0.0, -0.7073761 , 0.0], + [0.70680367, 0.0, -0.70740976, 0.0], + [0.70676998, 0.0, -0.70744342, 0.0], + [0.70673629, 0.0, -0.70747707, 0.0], + [0.7067026, 0.0, -0.70751073, 0.0], + [0.70666891, 0.0, -0.70754438, 0.0], + [0.70663522, 0.0, -0.70757803, 0.0], + [0.70660152, 0.0, -0.70761168, 0.0] + ], + "ephemeris_times": [ + 999.2, + 999.3, + 999.4, + 999.5, + 999.6, + 999.7, + 999.8, + 999.9, + 1000.0, + 1000.1, + 1000.2, + 1000.3, + 1000.4, + 1000.5, + 1000.6, + 1000.7 + ], + "angular_velocities": [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ], + "reference_frame": 1 + }, + "body_rotation": { + "quaternions": [ + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0] + ], + "ephemeris_times": [ + 999.2, + 999.3, + 999.4, + 999.5, + 999.6, + 999.7, + 999.8, + 999.9, + 1000.0, + 1000.1, + 1000.2, + 1000.3, + 1000.4, + 1000.5, + 1000.6, + 1000.7 + ], + "angular_velocities": [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ], + "reference_frame": 1, + "constant_frames": [1, 2, 3], + "time_dependent_frames": [4, 5, 6] + }, + "starting_detector_line": 1, + "starting_detector_sample": 0, + "sun_position": { + "positions": [ + [0.100, 0.100, 0.100], + [0.150, 0.150, 0.150], + [0.200, 0.200, 0.200], + [0.250, 0.250, 0.250] + ], + "velocities": [ + [0.125, 0.125, 0.125], + [0.125, 0.125, 0.125], + [0.125, 0.125, 0.125], + [0.125, 0.125, 0.125] + ], + "ephemeris_times": [ + 999.2, + 999.6, + 1000.0, + 1000.4 + ], + "reference_frame": 1, + "unit": "km" + } +} -- GitLab