Isis 3 Programmer Reference
KaguyaMiCameraDistortionMap.cpp
1 
7 /* SPDX-License-Identifier: CC0-1.0 */
8 
9 #include <cmath>
10 #include <iostream>
11 
12 #include "IString.h"
13 #include "Constants.h"
14 #include "FunctionTools.h"
15 #include "KaguyaMiCameraDistortionMap.h"
16 
17 using namespace std;
18 using namespace Isis;
19 
20 namespace Isis {
33  KaguyaMiCameraDistortionMap::KaguyaMiCameraDistortionMap(Camera *parent) : CameraDistortionMap(parent, 1) {
34  }
35 
39  void KaguyaMiCameraDistortionMap::SetDistortion(const int naifIkCode) {
40  //determine if this is the VIS or the NIR sensor, by loooking at the pixel pitch
41  if (p_camera->PixelPitch() == 0.013) m_numDistCoef = 3; //VIS camera has 3 distortion coefs
42  else m_numDistCoef = 4; //NIR camera has 4 distortion coefs
43 
44  //read the distortion coefs from the NAIF Kernels
45  QString naifXKey = "INS" + toString(naifIkCode) + "_DISTORTION_COEF_X";
46  QString naifYKey = "INS" + toString(naifIkCode) + "_DISTORTION_COEF_Y";
47  for (int i=0; i < m_numDistCoef; i++) {
48  m_distCoefX[i] = p_camera->getDouble(naifXKey,i);
49  m_distCoefY[i] = p_camera->getDouble(naifYKey,i);
50  }
51 
52  //now read the boresights, or what I would typicall call the principal point offsets
53  naifXKey = "INS" + toString(naifIkCode) + "_BORESIGHT";
54  m_boreX = p_camera->getDouble(naifXKey, 0);
55  m_boreY = p_camera->getDouble(naifXKey, 1);
56  }
57 
68  bool KaguyaMiCameraDistortionMap::SetFocalPlane(const double dx, const double dy) {
69  p_focalPlaneX = dx;
70  p_focalPlaneY = dy;
71  //cout << "focal plane: " << dx << " " << dy << "\n";
72  //NOTE: the IK/FK kernel does not include the " + dx" as I do below. They also define the
73  // radial distance only in terms of Y. Erroneously (I believe) they use only the
74  // DISTORTION_COEF_X's in their model definition. Finally, they provide different distortion
75  // coefficients for each line of the CCD--despite them going throught the same optical path.
76  // From this I conclude that this distorion model is only valid if x is very near zero. Which
77  // is exactly the situation we are shooting for when modeling a line scanner (x is the along
78  // path direction for this sensor). However, we can not just arbitarily zero, or almost zero,
79  // any along path offset calculated by the back projections. Those offsets are exactly the cost
80  // being zeroed in the iterative LineScanCameraGroundMap routines to find the time that a point
81  // on the ground was imaged. Therefore it must be maintained--with the knowledge that the
82  // small adjustmenst being provided by the distortion model are only relevant as the offsets (x)
83  // approach zero.
84  if (m_numDistCoef == 3) { //VIS camera
86  m_boreX + m_distCoefX[0] + dy*(m_distCoefX[1] + dy*m_distCoefX[2]) + dx;
88  m_boreY + m_distCoefY[0] + dy*(m_distCoefY[1] + dy*m_distCoefY[2]) + dy;
89  }
90  else { //NIR camera
91  p_undistortedFocalPlaneX = m_boreX +
92  m_distCoefX[0] + dy*(m_distCoefX[1] + dy*(m_distCoefX[2] + dy*m_distCoefX[3])) + dx;
93  p_undistortedFocalPlaneY = m_boreY +
94  m_distCoefY[0] + dy*(m_distCoefY[1] + dy*(m_distCoefY[2] + dy*m_distCoefY[3])) + dy;
95  }
96  //cout << "undistorted: " << p_undistortedFocalPlaneX << " " << p_undistortedFocalPlaneY << "\n";
97  return true;
98  }
99 
110  bool KaguyaMiCameraDistortionMap::SetUndistortedFocalPlane(const double ux, const double uy) {\
111  // image coordinates prior to introducing distortion
114 
115  //std::cout << "Distortionless : " << p_undistortedFocalPlaneX << " " << p_undistortedFocalPlaneY << "\n";
116 
117  if (m_numDistCoef == 3) { //quadratic distortion model
118  //use the quadratic equation to find the distorted Y value
119  double A,B,C; //coefficients of the quadric equation
120 
121  A = m_distCoefY[2];
122  B = 1.0 + m_distCoefY[1];
123  C = m_distCoefY[0] +m_boreY - uy;
124 
126 
127  if (roots.size() == 0) return false;
128  else if (roots.size() == 1)
129  p_focalPlaneY = roots[0];
130  else //two roots to choose between--choose the one closest to uy
131  p_focalPlaneY = fabs(uy - roots[0]) < fabs(uy - roots[1]) ? roots[0] : roots[1];
132 
133  //now that we know the distortedY we can directly calculate the X
134  p_focalPlaneX = ux -
135  (m_boreX + m_distCoefX[0] + p_focalPlaneY*(m_distCoefX[1] + p_focalPlaneY*m_distCoefX[2]));
136 
137  return true;
138  }
139  else { //cubic distortion model
140  //use the cubic equation to find the distorted Y value
141  double a,b,c; //coefficients of the cubic (coef x^3 ==1)
142 
143  a = m_distCoefY[2] / m_distCoefY[3];
144  b = (1.0 + m_distCoefY[1]) / m_distCoefY[3];
145  c = (m_distCoefY[0] + m_boreY - uy) / m_distCoefY[3];
146 
147  QList<double> roots = FunctionTools::realCubicRoots(1.0,a,b,c);
148 
149  if (roots.size() == 1) { //one root
150  p_focalPlaneY = roots[0];
151  }
152  else { //pick the root closest to the orginal value
153  QList<double> delta;
154 
155  //store all the distance from undistored to focal plane
156  for (int i=0;i<roots.size();i++)
157  delta << fabs(roots[i]-uy);
158 
159  if ( roots.size() == 3) //three roots to choose among
160  p_focalPlaneY = delta[0] < delta[1] ?
161  (delta[0] < delta[2] ? roots[0]:roots[2]) :
162  (delta[1] < delta[2] ? roots[1]:roots[2]) ;
163  else //two roots to choose between
164  p_focalPlaneY = delta[0] < delta[1] ? roots[0]:roots[1] ;
165  }
166 
167  //now that we know the distortedY we can directly calculate the X
168  p_focalPlaneX = ux - (m_boreX +m_distCoefX[0] +
169  p_focalPlaneY*(m_distCoefX[1] +
170  p_focalPlaneY*(m_distCoefX[2] +
171  p_focalPlaneY* m_distCoefX[3])));
172  return true;
173  }
174  }
175 }
Isis::CameraDistortionMap::p_focalPlaneX
double p_focalPlaneX
Distorted focal plane x.
Definition: CameraDistortionMap.h:65
QList< double >
Isis::KaguyaMiCameraDistortionMap::SetUndistortedFocalPlane
virtual bool SetUndistortedFocalPlane(const double ux, const double uy)
Compute distorted focal plane x/y.
Definition: KaguyaMiCameraDistortionMap.cpp:110
Isis::CameraDistortionMap::p_undistortedFocalPlaneY
double p_undistortedFocalPlaneY
Undistorted focal plane y.
Definition: CameraDistortionMap.h:68
Isis::CameraDistortionMap::p_undistortedFocalPlaneX
double p_undistortedFocalPlaneX
Undistorted focal plane x.
Definition: CameraDistortionMap.h:67
Isis::Camera
Definition: Camera.h:236
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::FunctionTools::realCubicRoots
static QList< double > realCubicRoots(double coeffCubicTerm, double coeffQuadTerm, double coeffLinearTerm, double coeffConstTerm)
Find the real roots of a cubic (1, 2, or 3) (see numerical recipies 3rd edtion page 227) Form: coeffC...
Definition: FunctionTools.h:106
Isis::KaguyaMiCameraDistortionMap::SetFocalPlane
virtual bool SetFocalPlane(const double dx, const double dy)
Compute undistorted focal plane x/y.
Definition: KaguyaMiCameraDistortionMap.cpp:68
Isis::FunctionTools::realQuadraticRoots
static QList< double > realQuadraticRoots(double coeffQuadTerm, double coeffLinearTerm, double coeffConstTerm)
The correct way to find the real roots of a quadratic (0, 1, or 2) (according to numerical recipies 3...
Definition: FunctionTools.h:71
Isis::CameraDistortionMap::p_camera
Camera * p_camera
The camera to distort/undistort.
Definition: CameraDistortionMap.h:63
Isis::CameraDistortionMap
Distort/undistort focal plane coordinates.
Definition: CameraDistortionMap.h:41
Isis::KaguyaMiCameraDistortionMap::SetDistortion
void SetDistortion(const int naifIkCode)
Definition: KaguyaMiCameraDistortionMap.cpp:39
std
Namespace for the standard library.
Isis::Camera::PixelPitch
double PixelPitch() const
Returns the pixel pitch.
Definition: Camera.cpp:2742
Isis::Spice::getDouble
SpiceDouble getDouble(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition: Spice.cpp:1039
Isis::CameraDistortionMap::p_focalPlaneY
double p_focalPlaneY
Distorted focal plane y.
Definition: CameraDistortionMap.h:66
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16