From 3a1bb8aa674f76ca53c9dcdc0b0544587e2154a5 Mon Sep 17 00:00:00 2001
From: Oleg Alexandrov <oleg.alexandrov@gmail.com>
Date: Mon, 29 Apr 2024 13:50:19 -0700
Subject: [PATCH] Hide normalizing of distorted coordiantes in the lens
 distortion model

---
 include/usgscsm/Distortion.h          |  2 ++
 src/Distortion.cpp                    | 23 +++++++++++++++--------
 src/UsgsAstroFrameSensorModel.cpp     | 20 +++-----------------
 src/UsgsAstroLsSensorModel.cpp        |  7 ++++---
 src/UsgsAstroPushFrameSensorModel.cpp |  6 +++---
 5 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/include/usgscsm/Distortion.h b/include/usgscsm/Distortion.h
index 10c5669..d5c3c51 100644
--- a/include/usgscsm/Distortion.h
+++ b/include/usgscsm/Distortion.h
@@ -19,11 +19,13 @@ void computeTransverseDistortion(double ux, double uy, double &dx, double &dy,
 
 void removeDistortion(double dx, double dy, double &ux, double &uy,
                       std::vector<double> const& opticalDistCoeffs,
+                      double focalLength,
                       DistortionType distortionType,
                       const double tolerance = 1.0E-6);
 
 void applyDistortion(double ux, double uy, double &dx, double &dy,
                      std::vector<double> const& opticalDistCoeffs,
+                     double focalLength,
                      DistortionType distortionType,
                      const double desiredPrecision = 1.0E-6,
                      const double tolerance = 1.0E-6);
diff --git a/src/Distortion.cpp b/src/Distortion.cpp
index 38f397a..e69a5cd 100644
--- a/src/Distortion.cpp
+++ b/src/Distortion.cpp
@@ -84,13 +84,14 @@ void computeTransverseDistortion(double ux, double uy, double &dx, double &dy,
   }
 }
 
-// Compute distorted focal plane coordinates given undistorted coordinates. Use
-// the radial-tangential distortion model with 5 coefficients (k1, k2, k3 for
-// radial distortion, and p1, p2 for tangential distortion). This was tested to
-// give the same results as the OpenCV distortion model, by invoking the
-// function cv::projectPoints() (with zero rotation, zero translation, and
-// identity camera matrix). The parameters are stored in opticalDistCoeffs 
-// in the order: [k1, k2, p1, p2, k3]. 
+// Compute distorted normalized focal plane coordinates given undistorted
+// normalized coordinates. Use the radial-tangential distortion model with 5
+// coefficients (k1, k2, k3 for radial distortion, and p1, p2 for tangential
+// distortion). This was tested to give the same results as the OpenCV
+// distortion model, by invoking the function cv::projectPoints() (with zero
+// rotation, zero translation, and identity camera matrix). The parameters are
+// stored in opticalDistCoeffs in the order: [k1, k2, p1, p2, k3]. 
+// Reference: https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html
 void computeRadTanDistortion(double ux, double uy, double &dx, double &dy,
                              std::vector<double> const& opticalDistCoeffs) {
 
@@ -120,7 +121,7 @@ void computeRadTanDistortion(double ux, double uy, double &dx, double &dy,
      + (p1 * (r2 + 2.0 * y * y) + 2.0 * p2 * x * y);
 }
 
-// Compute the jacobian for radtan distortion
+// Compute the jacobian for radtan distortion at given normalized coordinates
 void radTanDistortionJacobian(double x, double y, double *jacobian,
                               std::vector<double> const& opticalDistCoeffs) {
 
@@ -155,6 +156,7 @@ void radTanDistortionJacobian(double x, double y, double *jacobian,
 
 void removeDistortion(double dx, double dy, double &ux, double &uy,
                       std::vector<double> const& opticalDistCoeffs,
+                      double focalLength,
                       DistortionType distortionType, const double tolerance) {
   ux = dx;
   uy = dy;
@@ -343,8 +345,10 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
     // with the radtan model. See computeRadTanDistortion() for more details.
     case RADTAN:
     {
+      dx /= focalLength; dy /= focalLength; // Find normalized coordinates
       newtonRaphson(dx, dy, ux, uy, opticalDistCoeffs, distortionType, tolerance, 
                     computeRadTanDistortion, radTanDistortionJacobian);
+      ux *= focalLength; uy *= focalLength; // Convert back to pixel coordinates
       
     }
     break;
@@ -354,6 +358,7 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
 
 void applyDistortion(double ux, double uy, double &dx, double &dy,
                      std::vector<double> const& opticalDistCoeffs,
+                     double focalLength,
                      DistortionType distortionType,
                      const double desiredPrecision, const double tolerance) {
   dx = ux;
@@ -634,7 +639,9 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
     // with the RADTAN model. See computeRadTanDistortion() for more details.
     case RADTAN:
     {
+      ux /= focalLength; uy /= focalLength; // Find normalized coordinates
       computeRadTanDistortion(ux, uy, dx, dy, opticalDistCoeffs);  
+      dx *= focalLength; dy *= focalLength; // Convert back to pixel coordinates
     }  
     break;
     
diff --git a/src/UsgsAstroFrameSensorModel.cpp b/src/UsgsAstroFrameSensorModel.cpp
index 222e4ca..d702253 100644
--- a/src/UsgsAstroFrameSensorModel.cpp
+++ b/src/UsgsAstroFrameSensorModel.cpp
@@ -172,12 +172,8 @@ csm::ImageCoord UsgsAstroFrameSensorModel::groundToImage(
   // Apply the distortion to the line/sample location and then convert back to
   // line/sample
   double distortedX, distortedY;
-  // Divide by focal length
-  undistortedx /= f; undistortedy /= f;
   applyDistortion(undistortedx, undistortedy, distortedX, distortedY,
-                  m_opticalDistCoeffs, m_distortionType);
-  // Apply multiplication by focal length
-  distortedX *= f; distortedY *= f;
+                  m_opticalDistCoeffs, m_focalLength, m_distortionType);
   
   MESSAGE_LOG(
       spdlog::level::trace,
@@ -272,16 +268,10 @@ csm::EcefCoord UsgsAstroFrameSensorModel::imageToGround(
       m_detectorLineSumming, m_startingDetectorSample, m_startingDetectorLine,
       &m_iTransS[0], &m_iTransL[0], x_camera, y_camera);
 
-  // divide x_camera and y_camera by focal length
-  x_camera /= m_focalLength; y_camera /= m_focalLength;
-  
   // Apply the distortion model (remove distortion)
   double undistortedX, undistortedY;
   removeDistortion(x_camera, y_camera, undistortedX, undistortedY,
-                   m_opticalDistCoeffs, m_distortionType);
-  
-  // Multiply by focal length
-  undistortedX *= m_focalLength; undistortedY *= m_focalLength;
+                   m_opticalDistCoeffs, m_focalLength, m_distortionType);
   
   MESSAGE_LOG(
       spdlog::level::trace,
@@ -405,13 +395,9 @@ csm::EcefLocus UsgsAstroFrameSensorModel::imageToRemoteImagingLocus(
       
   // Distort
   double undistortedFocalPlaneX, undistortedFocalPlaneY;
-  // divide by focal length
-  focalPlaneX /= m_focalLength; focalPlaneY /= m_focalLength;
   removeDistortion(focalPlaneX, focalPlaneY, undistortedFocalPlaneX,
                    undistortedFocalPlaneY, m_opticalDistCoeffs,
-                   m_distortionType);
-  // Multiply by focal length
-  undistortedFocalPlaneX *= m_focalLength; undistortedFocalPlaneY *= m_focalLength;
+                   m_focalLength, m_distortionType);
 
   MESSAGE_LOG(
       spdlog::level::trace,
diff --git a/src/UsgsAstroLsSensorModel.cpp b/src/UsgsAstroLsSensorModel.cpp
index 8d1d985..d59e78b 100644
--- a/src/UsgsAstroLsSensorModel.cpp
+++ b/src/UsgsAstroLsSensorModel.cpp
@@ -774,7 +774,8 @@ csm::ImageCoord UsgsAstroLsSensorModel::groundToImage(
   // Invert distortion
   double distortedFocalX, distortedFocalY;
   applyDistortion(detectorView[0], detectorView[1], distortedFocalX,
-                  distortedFocalY, m_opticalDistCoeffs, m_distortionType,
+                  distortedFocalY, m_opticalDistCoeffs, m_focalLength,
+                  m_distortionType,
                   desiredPrecision);
   MESSAGE_LOG(
       spdlog::level::trace,
@@ -1876,7 +1877,7 @@ void UsgsAstroLsSensorModel::losToEcf(
   double undistortedFocalPlaneX, undistortedFocalPlaneY;
   removeDistortion(distortedFocalPlaneX, distortedFocalPlaneY,
                    undistortedFocalPlaneX, undistortedFocalPlaneY,
-                   m_opticalDistCoeffs, m_distortionType);
+                   m_opticalDistCoeffs, m_focalLength, m_distortionType);
   MESSAGE_LOG(
       spdlog::level::trace,
       "losToEcf: undistorted focal plane coordinate {} {}",
@@ -2800,7 +2801,7 @@ double UsgsAstroLsSensorModel::calcDetectorLineErr(double t, csm::ImageCoord con
   // Invert distortion
   double distortedFocalX, distortedFocalY;
   applyDistortion(detectorView[0], detectorView[1], distortedFocalX,
-                  distortedFocalY, m_opticalDistCoeffs, m_distortionType);
+                  distortedFocalY, m_opticalDistCoeffs, m_focalLength, m_distortionType);
 
   // Convert to detector line
   double detectorLine = m_iTransL[0] + m_iTransL[1] * distortedFocalX +
diff --git a/src/UsgsAstroPushFrameSensorModel.cpp b/src/UsgsAstroPushFrameSensorModel.cpp
index 1054200..a919487 100644
--- a/src/UsgsAstroPushFrameSensorModel.cpp
+++ b/src/UsgsAstroPushFrameSensorModel.cpp
@@ -762,8 +762,8 @@ csm::ImageCoord UsgsAstroPushFrameSensorModel::groundToImage(
   // Invert distortion
   double distortedFocalX, distortedFocalY;
   applyDistortion(focalCoord[0], focalCoord[1], distortedFocalX,
-                  distortedFocalY, m_opticalDistCoeffs, m_distortionType,
-                  desiredPrecision);
+                  distortedFocalY, m_opticalDistCoeffs, m_focalLength, 
+                  m_distortionType, desiredPrecision);
 
   // Convert to detector line and sample
   double detectorLine = m_iTransL[0] + m_iTransL[1] * distortedFocalX +
@@ -1793,7 +1793,7 @@ void UsgsAstroPushFrameSensorModel::losToEcf(
   double undistortedFocalPlaneX, undistortedFocalPlaneY;
   removeDistortion(distortedFocalPlaneX, distortedFocalPlaneY,
                    undistortedFocalPlaneX, undistortedFocalPlaneY,
-                   m_opticalDistCoeffs, m_distortionType);
+                   m_opticalDistCoeffs, m_focalLength, m_distortionType);
   MESSAGE_LOG("losToEcf: undistorted focal plane coordinate {} {}",
               undistortedFocalPlaneX, undistortedFocalPlaneY)
 
-- 
GitLab