Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
U
Usgscsm
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
aflab
astrogeology
Usgscsm
Commits
d5c49d98
Commit
d5c49d98
authored
1 year ago
by
Oleg Alexandrov
Browse files
Options
Downloads
Patches
Plain Diff
Implement radtan distortion and undistortion
parent
ce4d6a19
No related branches found
No related tags found
No related merge requests found
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
include/usgscsm/Distortion.h
+4
-4
4 additions, 4 deletions
include/usgscsm/Distortion.h
src/Distortion.cpp
+212
-10
212 additions, 10 deletions
src/Distortion.cpp
tests/DistortionTests.cpp
+29
-4
29 additions, 4 deletions
tests/DistortionTests.cpp
tests/Fixtures.h
+3
-0
3 additions, 0 deletions
tests/Fixtures.h
with
248 additions
and
18 deletions
include/usgscsm/Distortion.h
+
4
−
4
View file @
d5c49d98
...
@@ -6,10 +6,10 @@
...
@@ -6,10 +6,10 @@
#include
<tuple>
#include
<tuple>
#include
<vector>
#include
<vector>
enum
DistortionType
{
RADIAL
,
TRANSVERSE
,
KAGUYALISM
,
DAWNFC
,
LROLROCNAC
,
CAHVOR
};
enum
DistortionType
{
RADIAL
,
TRANSVERSE
,
KAGUYALISM
,
DAWNFC
,
LROLROCNAC
,
CAHVOR
,
RADTAN
};
// Transverse
D
istortion
// Transverse
d
istortion
Jacobian
void
d
istortionJacobian
(
double
x
,
double
y
,
double
*
jacobian
,
void
transverseD
istortionJacobian
(
double
x
,
double
y
,
double
*
jacobian
,
const
std
::
vector
<
double
>
opticalDistCoeffs
);
const
std
::
vector
<
double
>
opticalDistCoeffs
);
void
computeTransverseDistortion
(
double
ux
,
double
uy
,
double
&
dx
,
double
&
dy
,
void
computeTransverseDistortion
(
double
ux
,
double
uy
,
double
&
dx
,
double
&
dy
,
...
...
This diff is collapsed.
Click to expand it.
src/Distortion.cpp
+
212
−
10
View file @
d5c49d98
...
@@ -3,7 +3,8 @@
...
@@ -3,7 +3,8 @@
#include
<Error.h>
#include
<Error.h>
#include
<string>
#include
<string>
void
distortionJacobian
(
double
x
,
double
y
,
double
*
jacobian
,
// Jacobian for Transverse distortion
void
transverseDistortionJacobian
(
double
x
,
double
y
,
double
*
jacobian
,
const
std
::
vector
<
double
>
opticalDistCoeffs
)
{
const
std
::
vector
<
double
>
opticalDistCoeffs
)
{
double
d_dx
[
10
];
double
d_dx
[
10
];
d_dx
[
0
]
=
0
;
d_dx
[
0
]
=
0
;
...
@@ -82,6 +83,138 @@ void computeTransverseDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -82,6 +83,138 @@ 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].
void
computeRadTanDistortion
(
double
ux
,
double
uy
,
double
&
dx
,
double
&
dy
,
std
::
vector
<
double
>
const
&
opticalDistCoeffs
)
{
if
(
opticalDistCoeffs
.
size
()
!=
5
)
{
csm
::
Error
::
ErrorType
errorType
=
csm
::
Error
::
INDEX_OUT_OF_RANGE
;
std
::
string
message
=
"Distortion coefficients for the radtan distortion model must be of size 5. "
"Got: "
+
std
::
to_string
(
opticalDistCoeffs
.
size
());
std
::
string
function
=
"computeRadTanDistortion"
;
throw
csm
::
Error
(
errorType
,
message
,
function
);
}
// Shorten notation
double
x
=
ux
,
y
=
uy
;
double
k1
=
opticalDistCoeffs
[
0
];
double
k2
=
opticalDistCoeffs
[
1
];
double
p1
=
opticalDistCoeffs
[
2
];
double
p2
=
opticalDistCoeffs
[
3
];
double
k3
=
opticalDistCoeffs
[
4
];
double
r2
=
(
x
*
x
)
+
(
y
*
y
);
dx
=
x
*
(
1.0
+
k1
*
r2
+
k2
*
r2
*
r2
+
k3
*
r2
*
r2
*
r2
)
+
(
2.0
*
p1
*
x
*
y
+
p2
*
(
r2
+
2.0
*
x
*
x
));
dy
=
y
*
(
1.0
+
k1
*
r2
+
k2
*
r2
*
r2
+
k3
*
r2
*
r2
*
r2
)
+
(
p1
*
(
r2
+
2.0
*
y
*
y
)
+
2.0
*
p2
*
x
*
y
);
}
// Compute the jacobian for radtan distortion
void
radTanDistortionJacobian
(
double
x
,
double
y
,
double
*
jacobian
,
std
::
vector
<
double
>
const
&
opticalDistCoeffs
)
{
double
k1
=
opticalDistCoeffs
[
0
];
double
k2
=
opticalDistCoeffs
[
1
];
double
p1
=
opticalDistCoeffs
[
2
];
double
p2
=
opticalDistCoeffs
[
3
];
double
k3
=
opticalDistCoeffs
[
4
];
double
r2
=
x
*
x
+
y
*
y
;
double
dr2dx
=
2.0
*
x
;
double
dr2dy
=
2.0
*
y
;
// dfx / dx
jacobian
[
0
]
=
(
1.0
+
k1
*
r2
+
k2
*
r2
*
r2
+
k3
*
r2
*
r2
*
r2
)
+
x
*
(
k1
*
dr2dx
+
k2
*
dr2dx
*
2.0
*
r2
+
k3
*
dr2dx
*
3.0
*
r2
*
r2
)
+
2.0
*
p1
*
y
+
p2
*
(
dr2dx
+
4.0
*
x
);
// dfx / dy
jacobian
[
1
]
=
x
*
(
k1
*
dr2dy
+
k2
*
dr2dy
*
2.0
*
r2
+
k3
*
dr2dy
*
3.0
*
r2
*
r2
)
+
2.0
*
p1
*
x
+
p2
*
dr2dy
;
// dfy / dx
jacobian
[
2
]
=
y
*
(
k1
*
dr2dx
+
k2
*
dr2dx
*
2.0
*
r2
+
k3
*
dr2dx
*
3.0
*
r2
*
r2
)
+
(
p1
*
dr2dx
+
2.0
*
p2
*
y
);
// dfy / dy
jacobian
[
3
]
=
(
1.0
+
k1
*
r2
+
k2
*
r2
*
r2
+
k3
*
r2
*
r2
*
r2
)
+
y
*
(
k1
*
dr2dy
+
k2
*
dr2dy
*
2.0
*
r2
+
k3
*
dr2dy
*
3.0
*
r2
*
r2
)
+
p1
*
(
dr2dy
+
4.0
*
y
)
+
2.0
*
p2
*
x
;
#if 0
// Check the partial derivatives with numerical differentiation
{
double eps = 1e-4;
double y0 = y;
y = y0 + eps;
r2 = (x * x) + (y * y);
double dx1 = x * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (2.0 * p1 * x * y + p2 * (r2 + 2.0 * x * x));
double dy1 = y * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (p1 * (r2 + 2.0 * y * y) + 2.0 * p2 * x * y);
y = y0 - eps;
r2 = (x * x) + (y * y);
double dx2 = x * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (2.0 * p1 * x * y + p2 * (r2 + 2.0 * x * x));
double dy2 = y * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (p1 * (r2 + 2.0 * y * y) + 2.0 * p2 * x * y);
std::cout << "--numerical1 is " << (dx1-dx2)/(2*eps) << " " << jacobian[1] << std::endl;
std::cout << "diff1 is " << (dx1-dx2)/(2*eps) - jacobian[1] << std::endl;
std::cout << "--numerical3 is " << (dy1-dy2)/(2*eps) << " " << jacobian[3] << std::endl;
std::cout << "diff3 is " << (dy1-dy2)/(2*eps) - jacobian[3] << std::endl;
y = y0;
}
{
double eps = 1e-4;
double x0 = x;
x = x0 + eps;
r2 = (x * x) + (y * y);
double dx1 = x * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (2.0 * p1 * x * y + p2 * (r2 + 2.0 * x * x));
double dy1 = y * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (p1 * (r2 + 2.0 * y * y) + 2.0 * p2 * x * y);
x = x0 - eps;
r2 = (x * x) + (y * y);
double dx2 = x * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (2.0 * p1 * x * y + p2 * (r2 + 2.0 * x * x));
double dy2 = y * (1.0 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2)
+ (p1 * (r2 + 2.0 * y * y) + 2.0 * p2 * x * y);
std::cout << "--numerical0 is " << (dx1-dx2)/(2*eps) << " " << jacobian[0] << std::endl;
std::cout << "diff0 is " << (dx1-dx2)/(2*eps) - jacobian[0] << std::endl;
std::cout << "--numerical2 is " << (dy1-dy2)/(2*eps) << " " << jacobian[2] << std::endl;
std::cout << "diff2 is " << (dy1-dy2)/(2*eps) - jacobian[2] << std::endl;
x = x0;
}
#endif
}
void
removeDistortion
(
double
dx
,
double
dy
,
double
&
ux
,
double
&
uy
,
void
removeDistortion
(
double
dx
,
double
dy
,
double
&
ux
,
double
&
uy
,
const
std
::
vector
<
double
>
opticalDistCoeffs
,
const
std
::
vector
<
double
>
opticalDistCoeffs
,
DistortionType
distortionType
,
const
double
tolerance
)
{
DistortionType
distortionType
,
const
double
tolerance
)
{
...
@@ -132,7 +265,7 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
...
@@ -132,7 +265,7 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
fx
=
dx
-
fx
;
fx
=
dx
-
fx
;
fy
=
dy
-
fy
;
fy
=
dy
-
fy
;
d
istortionJacobian
(
x
,
y
,
jacobian
,
opticalDistCoeffs
);
transverseD
istortionJacobian
(
x
,
y
,
jacobian
,
opticalDistCoeffs
);
// Jxx * Jyy - Jxy * Jyx
// Jxx * Jyy - Jxy * Jyx
double
determinant
=
double
determinant
=
...
@@ -316,6 +449,66 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
...
@@ -316,6 +449,66 @@ void removeDistortion(double dx, double dy, double &ux, double &uy,
}
}
}
}
break
;
break
;
// Compute undistorted focal plane coordinate given distorted coordinates
// with the RADTAN model. See computeRadTanDistortion() for more details.
case
RADTAN
:
{
// Solve the distortion equation using the Newton-Raphson method.
// Set the error tolerance to about one millionth of a NAC pixel.
// The maximum number of iterations of the Newton-Raphson method.
const
int
maxTries
=
20
;
double
x
;
double
y
;
double
fx
;
double
fy
;
double
jacobian
[
4
];
// Initial guess at the root
x
=
dx
;
y
=
dy
;
computeRadTanDistortion
(
x
,
y
,
fx
,
fy
,
opticalDistCoeffs
);
for
(
int
count
=
1
;
((
fabs
(
fx
)
+
fabs
(
fy
))
>
tolerance
)
&&
(
count
<
maxTries
);
count
++
)
{
computeRadTanDistortion
(
x
,
y
,
fx
,
fy
,
opticalDistCoeffs
);
fx
=
dx
-
fx
;
fy
=
dy
-
fy
;
radTanDistortionJacobian
(
x
,
y
,
jacobian
,
opticalDistCoeffs
);
// Jxx * Jyy - Jxy * Jyx
double
determinant
=
jacobian
[
0
]
*
jacobian
[
3
]
-
jacobian
[
1
]
*
jacobian
[
2
];
if
(
fabs
(
determinant
)
<
1e-6
)
{
ux
=
x
;
uy
=
y
;
//
// Near-zero determinant. Add error handling here.
//
//-- Just break out and return with no convergence
return
;
}
x
=
x
+
(
jacobian
[
3
]
*
fx
-
jacobian
[
1
]
*
fy
)
/
determinant
;
y
=
y
+
(
jacobian
[
0
]
*
fy
-
jacobian
[
2
]
*
fx
)
/
determinant
;
}
if
((
fabs
(
fx
)
+
fabs
(
fy
))
<=
tolerance
)
{
// The method converged to a root.
ux
=
x
;
uy
=
y
;
return
;
}
// Otherwise method did not converge to a root within the maximum
// number of iterations
}
break
;
}
}
}
}
...
@@ -327,7 +520,7 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -327,7 +520,7 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
dy
=
uy
;
dy
=
uy
;
switch
(
distortionType
)
{
switch
(
distortionType
)
{
// Compute
un
distorted focal plane coordinate given
a
distorted
// Compute distorted focal plane coordinate given
un
distorted
// focal plane coordinate. This case works by iteratively adding distortion
// focal plane coordinate. This case works by iteratively adding distortion
// until the new distorted point, r, undistorts to within a tolerance of the
// until the new distorted point, r, undistorts to within a tolerance of the
// original point, rp.
// original point, rp.
...
@@ -454,9 +647,9 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -454,9 +647,9 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
}
}
}
break
;
}
break
;
// The dawn distortion model is "reversed" from other distortion models
so
// The dawn distortion model is "reversed" from other distortion models
.
//
t
he apply function computes distorted coordinates as a
//
T
he apply function computes distorted coordinates as a
// f
n(
undistorted coordinates
)
// f
unction of
undistorted coordinates
.
case
DAWNFC
:
{
case
DAWNFC
:
{
double
r2
;
double
r2
;
...
@@ -468,7 +661,7 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -468,7 +661,7 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
// The LRO LROC NAC distortion model uses an iterative approach to go from
// The LRO LROC NAC distortion model uses an iterative approach to go from
// undistorted x,y to distorted x,y
// undistorted x,y to distorted x,y
// Algorith
u
m adapted from ISIS3 LRONarrowAngleDistortionMap.cpp
// Algorithm adapted from ISIS3 LRONarrowAngleDistortionMap.cpp
case
LROLROCNAC
:
{
case
LROLROCNAC
:
{
double
yt
=
uy
;
double
yt
=
uy
;
...
@@ -491,9 +684,9 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -491,9 +684,9 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
double
dk1
=
opticalDistCoeffs
[
0
];
double
dk1
=
opticalDistCoeffs
[
0
];
// Owing to the odd distotion model employed in this sens
e
r if |y| is >
// Owing to the odd disto
r
tion model employed in this sens
o
r if |y| is >
// 116.881145553046 then there is no root to find. Further, the greatest
// 116.881145553046 then there is no root to find. Further, the greatest
// y that any measure on the sensor will ac
u
tally distort to is less
// y that any measure on the sensor will act
u
ally distort to is less
// than 20. Thus, if any distorted measure is greater that that skip the
// than 20. Thus, if any distorted measure is greater that that skip the
// iterations. The points isn't in the cube, and exactly how far outside
// iterations. The points isn't in the cube, and exactly how far outside
// the cube is irrelevant. Just let the camera model know its not in the
// the cube is irrelevant. Just let the camera model know its not in the
...
@@ -597,5 +790,14 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
...
@@ -597,5 +790,14 @@ void applyDistortion(double ux, double uy, double &dx, double &dy,
}
}
}
}
break
;
break
;
// Compute distorted focal plane coordinate given undistorted coordinates
// with the RADTAN model. See computeRadTanDistortion() for more details.
case
RADTAN
:
{
computeRadTanDistortion
(
ux
,
uy
,
dx
,
dy
,
opticalDistCoeffs
);
}
break
;
}
}
}
}
This diff is collapsed.
Click to expand it.
tests/DistortionTests.cpp
+
29
−
4
View file @
d5c49d98
...
@@ -19,7 +19,7 @@ TEST_P(ImageCoordParameterizedTest, JacobianTest) {
...
@@ -19,7 +19,7 @@ TEST_P(ImageCoordParameterizedTest, JacobianTest) {
csm
::
ImageCoord
imagePt
=
GetParam
();
csm
::
ImageCoord
imagePt
=
GetParam
();
double
jacobian
[
4
];
double
jacobian
[
4
];
d
istortionJacobian
(
imagePt
.
samp
,
imagePt
.
line
,
jacobian
,
transverseD
istortionJacobian
(
imagePt
.
samp
,
imagePt
.
line
,
jacobian
,
transverseDistortionCoeffs
);
transverseDistortionCoeffs
);
// Jxx * Jyy - Jxy * Jyx
// Jxx * Jyy - Jxy * Jyx
...
@@ -36,7 +36,7 @@ TEST(Transverse, Jacobian1) {
...
@@ -36,7 +36,7 @@ TEST(Transverse, Jacobian1) {
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
1.0
,
1.0
};
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
1.0
,
1.0
};
double
jacobian
[
4
];
double
jacobian
[
4
];
d
istortionJacobian
(
imagePt
.
samp
,
imagePt
.
line
,
jacobian
,
transverseD
istortionJacobian
(
imagePt
.
samp
,
imagePt
.
line
,
jacobian
,
transverseDistortionCoeffs
);
transverseDistortionCoeffs
);
EXPECT_NEAR
(
jacobian
[
0
],
56.25
,
1e-8
);
EXPECT_NEAR
(
jacobian
[
0
],
56.25
,
1e-8
);
...
@@ -380,3 +380,28 @@ TEST_P(CoeffOffsetParameterizedTest, InverseOnesCoeffsCahvorTest)
...
@@ -380,3 +380,28 @@ TEST_P(CoeffOffsetParameterizedTest, InverseOnesCoeffsCahvorTest)
EXPECT_NEAR
(
dx
,
4
,
1e-8
);
EXPECT_NEAR
(
dx
,
4
,
1e-8
);
EXPECT_NEAR
(
dy
,
0
,
1e-8
);
EXPECT_NEAR
(
dy
,
0
,
1e-8
);
}
}
INSTANTIATE_TEST_SUITE_P
(
RadTanInversionTest
,
RadTanTest
,
::
testing
::
Values
(
std
::
vector
<
double
>
(
0
,
0
)));
TEST_P
(
RadTanTest
,
RadTanInversionTest
)
{
// Initialize radtan distortion coefficients (k1, k2, p1, p2, k3)
std
::
vector
<
double
>
distCoeffs
=
{
0.000031
,
-
0.000056
,
1.3e-5
,
-
1.7e-6
,
2.9e-8
};
double
ux
=
5.0
,
uy
=
6.0
;
// Compute distortion
double
dx
,
dy
;
applyDistortion
(
ux
,
uy
,
dx
,
dy
,
distCoeffs
,
DistortionType
::
RADTAN
,
1e-8
,
1e-8
);
// Remove distortion (undistort)
double
ux2
,
uy2
;
removeDistortion
(
dx
,
dy
,
ux2
,
uy2
,
distCoeffs
,
DistortionType
::
RADTAN
,
1e-8
);
EXPECT_NEAR
(
dx
,
4.0010785450000004
,
1e-8
);
EXPECT_NEAR
(
dy
,
4.8022116940000013
,
1e-8
);
EXPECT_NEAR
(
ux2
,
ux
,
1e-8
);
EXPECT_NEAR
(
uy2
,
uy
,
1e-8
);
}
This diff is collapsed.
Click to expand it.
tests/Fixtures.h
+
3
−
0
View file @
d5c49d98
...
@@ -180,6 +180,9 @@ class ImageCoordParameterizedTest
...
@@ -180,6 +180,9 @@ class ImageCoordParameterizedTest
class
CoeffOffsetParameterizedTest
class
CoeffOffsetParameterizedTest
:
public
::
testing
::
TestWithParam
<
std
::
vector
<
double
>>
{};
:
public
::
testing
::
TestWithParam
<
std
::
vector
<
double
>>
{};
class
RadTanTest
:
public
::
testing
::
TestWithParam
<
std
::
vector
<
double
>>
{};
class
FramerParameterizedTest
class
FramerParameterizedTest
:
public
::
testing
::
TestWithParam
<
csm
::
ImageCoord
>
{
:
public
::
testing
::
TestWithParam
<
csm
::
ImageCoord
>
{
protected:
protected:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment