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
17using namespace std;
18using namespace Isis;
19
20namespace Isis {
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
125 QList<double> roots = FunctionTools::realQuadraticRoots(A,B,C);
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}
Distort/undistort focal plane coordinates.
double p_focalPlaneX
Distorted focal plane x.
double p_undistortedFocalPlaneX
Undistorted focal plane x.
double p_undistortedFocalPlaneY
Undistorted focal plane y.
Camera * p_camera
The camera to distort/undistort.
double p_focalPlaneY
Distorted focal plane y.
double PixelPitch() const
Returns the pixel pitch.
Definition Camera.cpp:2772
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...
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...
KaguyaMiCameraDistortionMap(Camera *parent)
Camera distortion map constructor.
virtual bool SetUndistortedFocalPlane(const double ux, const double uy)
Compute distorted focal plane x/y.
virtual bool SetFocalPlane(const double dx, const double dy)
Compute undistorted focal plane x/y.
SpiceDouble getDouble(const QString &key, int index=0)
This returns a value from the NAIF text pool.
Definition Spice.cpp:1046
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
Namespace for the standard library.