farm-ng-core
kannala_brandt.h
Go to the documentation of this file.
1 // Copyright (c) 2011, Hauke Strasdat
2 // Copyright (c) 2012, Steven Lovegrove
3 // Copyright (c) 2021, farm-ng, inc.
4 //
5 // Use of this source code is governed by an MIT-style
6 // license that can be found in the LICENSE file or at
7 // https://opensource.org/licenses/MIT.
8 
9 #pragma once
10 
12 #include "sophus/common/common.h"
15 
16 #include <Eigen/Dense>
17 
18 namespace sophus {
19 
20 // https://github.com/facebookincubator/isometric_pattern_matcher/blob/main/IsometricPatternMatcher/CameraModels.h
21 //
22 // parameters = fx, fy, cx, cy, kb0, kb1, kb2, kb3
24  public:
25  static int constexpr kNumDistortionParams = 4;
26  static int constexpr kNumParams = kNumDistortionParams + 4;
27  static constexpr const std::string_view kProjectionModel =
28  "KannalaBrandtK3: fx, fy, cx, cy, kb0, kb1, kb2, kb3";
29 
30  template <class TScalar>
31  using ProjInCameraZ1Plane = Eigen::Matrix<TScalar, 2, 1>;
32  template <class TScalar>
33  using PixelImage = Eigen::Matrix<TScalar, 2, 1>;
34  template <class TScalar>
35  using Params = Eigen::Matrix<TScalar, kNumParams, 1>;
36  template <class TScalar>
37  using DistorationParams = Eigen::Matrix<TScalar, kNumDistortionParams, 1>;
38 
39  template <class TParamsTypeT, class TPointTypeT>
40  static auto distort(
41  Eigen::MatrixBase<TParamsTypeT> const& params,
42  Eigen::MatrixBase<TPointTypeT> const& proj_point_in_camera_z1_plane)
44  static_assert(
45  TParamsTypeT::ColsAtCompileTime == 1, "params must be a column-vector");
46  static_assert(
47  TParamsTypeT::RowsAtCompileTime == kNumParams,
48  "params must have exactly kNumParams rows");
49  static_assert(
50  TPointTypeT::ColsAtCompileTime == 1,
51  "point_camera must be a column-vector");
52  static_assert(
53  TPointTypeT::RowsAtCompileTime == 2,
54  "point_camera must have exactly 2 columns");
55 
56  auto const k0 = params[4];
57  auto const k1 = params[5];
58  auto const k2 = params[6];
59  auto const k3 = params[7];
60 
61  auto const radius_squared =
62  proj_point_in_camera_z1_plane[0] * proj_point_in_camera_z1_plane[0] +
63  proj_point_in_camera_z1_plane[1] * proj_point_in_camera_z1_plane[1];
64  using std::atan2;
65  using std::sqrt;
66 
67  if (radius_squared > sophus::kEpsilonF64) {
68  auto const radius = sqrt(radius_squared);
69  auto const radius_inverse = 1.0 / radius;
70  auto const theta = atan2(radius, typename TPointTypeT::Scalar(1.0));
71  auto const theta2 = theta * theta;
72  auto const theta4 = theta2 * theta2;
73  auto const theta6 = theta4 * theta2;
74  auto const theta8 = theta4 * theta4;
75  auto const r_distorted =
76  theta * (1.0 + k0 * theta2 + k1 * theta4 + k2 * theta6 + k3 * theta8);
77  auto const scaling = r_distorted * radius_inverse;
78 
79  return scaling * proj_point_in_camera_z1_plane.cwiseProduct(
80  params.template head<2>()) +
81  params.template segment<2>(2);
82  } // linearize r around radius=0
83 
85 
86  params.template head<4>(), proj_point_in_camera_z1_plane);
87  }
88 
89  template <class TScalar>
90  static auto undistort(
91  Params<TScalar> const& params, PixelImage<TScalar> const& pixel_image)
93  using std::abs;
94  using std::sqrt;
95  using std::tan;
96 
97  // Undistortion
98  const TScalar fu = params[0];
99  const TScalar fv = params[1];
100  const TScalar u0 = params[2];
101  const TScalar v0 = params[3];
102 
103  const TScalar k0 = params[4];
104  const TScalar k1 = params[5];
105  const TScalar k2 = params[6];
106  const TScalar k3 = params[7];
107 
108  const TScalar un = (pixel_image(0) - u0) / fu;
109  const TScalar vn = (pixel_image(1) - v0) / fv;
110  const TScalar rth2 = un * un + vn * vn;
111 
112  if (rth2 < sophus::kEpsilon<TScalar> * sophus::kEpsilon<TScalar>) {
113  return Eigen::Matrix<TScalar, 2, 1>(un, vn);
114  }
115 
116  const TScalar rth = sqrt(rth2);
117 
118  // Use Newtons method to solve for theta, 50 iterations max
119  TScalar th = sqrt(rth);
120  for (int i = 0; i < 500; ++i) {
121  const TScalar th2 = th * th;
122  const TScalar th4 = th2 * th2;
123  const TScalar th6 = th4 * th2;
124  const TScalar th8 = th4 * th4;
125 
126  const TScalar thd =
127  th * (TScalar(1.0) + k0 * th2 + k1 * th4 + k2 * th6 + k3 * th8);
128 
129  const TScalar d_thd_wtr_th =
130  TScalar(1.0) + TScalar(3.0) * k0 * th2 + TScalar(5.0) * k1 * th4 +
131  TScalar(7.0) * k2 * th6 + TScalar(9.0) * k3 * th8;
132 
133  const TScalar step = (thd - rth) / d_thd_wtr_th;
134  th -= step;
135  // has converged?
136  if (abs(jet_helpers::GetValue<TScalar>::impl(step)) <
137  sophus::kEpsilon<TScalar>) {
138  break;
139  }
140  }
141 
142  TScalar radius_undistorted = tan(th);
143 
144  if (radius_undistorted < TScalar(0.0)) {
145  return Eigen::Matrix<TScalar, 2, 1>(
146  -radius_undistorted * un / rth, -radius_undistorted * vn / rth);
147  }
148  return Eigen::Matrix<TScalar, 2, 1>(
149  radius_undistorted * un / rth, radius_undistorted * vn / rth);
150  }
151 
152  template <class TParamsTypeT, class TPointTypeT>
153  static auto dxDistort(
154  Eigen::MatrixBase<TParamsTypeT> const& params,
155  Eigen::MatrixBase<TPointTypeT> const& proj_point_in_camera_z1_plane)
156  -> Eigen::Matrix<typename TPointTypeT::Scalar, 2, 2> {
157  static_assert(
158  TParamsTypeT::ColsAtCompileTime == 1, "params must be a column-vector");
159  static_assert(
160  TParamsTypeT::RowsAtCompileTime == kNumParams,
161  "params must have exactly kNumParams rows");
162  static_assert(
163  TPointTypeT::ColsAtCompileTime == 1,
164  "point_camera must be a column-vector");
165  static_assert(
166  TPointTypeT::RowsAtCompileTime == 2,
167  "point_camera must have exactly 2 columns");
168  using Scalar = typename TPointTypeT::Scalar;
169 
170  Scalar a = proj_point_in_camera_z1_plane[0];
171  Scalar b = proj_point_in_camera_z1_plane[1];
172  Scalar const fx = params[0];
173  Scalar const fy = params[1];
174  Eigen::Matrix<Scalar, kNumDistortionParams, 1> k =
175  params.template tail<kNumDistortionParams>();
176 
177  auto const radius_squared = a * a + b * b;
178  using std::atan2;
179  using std::sqrt;
180 
181  Eigen::Matrix<typename TPointTypeT::Scalar, 2, 2> dx;
182 
183  if (radius_squared < sophus::kEpsilonSqrtF64) {
184  // clang-format off
185  dx << //
186  fx, 0,
187  0, fy;
188  // clang-format on
189  return dx;
190  }
191 
192  using std::atan2;
193  using std::pow;
194  using std::sqrt;
195 
196  Scalar const c0 = pow(a, 2);
197  Scalar const c1 = pow(b, 2);
198  Scalar const c2 = c0 + c1;
199  Scalar const c3 = pow(c2, 5.0 / 2.0);
200  Scalar const c4 = c2 + 1;
201  Scalar const c5 = atan(sqrt(c2));
202  Scalar const c6 = pow(c5, 2);
203  Scalar const c7 = c6 * k[0];
204  Scalar const c8 = pow(c5, 4);
205  Scalar const c9 = c8 * k[1];
206  Scalar const c10 = pow(c5, 6);
207  Scalar const c11 = c10 * k[2];
208  Scalar const c12 = pow(c5, 8) * k[3];
209  Scalar const c13 = 1.0 * c4 * c5 * (c11 + c12 + c7 + c9 + 1.0);
210  Scalar const c14 = c13 * c3;
211  Scalar const c15 = pow(c2, 3.0 / 2.0);
212  Scalar const c16 = c13 * c15;
213  Scalar const c17 =
214  1.0 * c11 + 1.0 * c12 +
215  2.0 * c6 * (4 * c10 * k[3] + 2 * c6 * k[1] + 3 * c8 * k[2] + k[0]) +
216  1.0 * c7 + 1.0 * c9 + 1.0;
217  Scalar const c18 = c17 * pow(c2, 2);
218  Scalar const c19 = 1.0 / c4;
219  Scalar const c20 = c19 / pow(c2, 3);
220  Scalar const c21 = a * b * c19 * (-c13 * c2 + c15 * c17) / c3;
221 
222  dx(0, 0) = c20 * fx * (-c0 * c16 + c0 * c18 + c14);
223  dx(0, 1) = c21 * fx;
224 
225  dx(1, 0) = c21 * fy;
226  dx(1, 1) = c20 * fy * (-c1 * c16 + c1 * c18 + c14);
227 
228  return dx;
229  }
230 };
231 
232 } // namespace sophus
sophus::KannalaBrandtK3Transform::dxDistort
static auto dxDistort(Eigen::MatrixBase< TParamsTypeT > const &params, Eigen::MatrixBase< TPointTypeT > const &proj_point_in_camera_z1_plane) -> Eigen::Matrix< typename TPointTypeT::Scalar, 2, 2 >
Definition: kannala_brandt.h:153
affine.h
sophus::KannalaBrandtK3Transform::ProjInCameraZ1Plane
Eigen::Matrix< TScalar, 2, 1 > ProjInCameraZ1Plane
Definition: kannala_brandt.h:31
sophus::KannalaBrandtK3Transform::kNumParams
static constexpr int kNumParams
Definition: kannala_brandt.h:26
sophus
Image MutImage, owning images types.
Definition: num_diff.h:20
sophus::KannalaBrandtK3Transform::PixelImage
Eigen::Matrix< TScalar, 2, 1 > PixelImage
Definition: kannala_brandt.h:33
sophus::jet_helpers::GetValue
Definition: jet_helpers.h:23
point_transform.h
sophus::KannalaBrandtK3Transform::kNumDistortionParams
static constexpr int kNumDistortionParams
Definition: kannala_brandt.h:25
sophus::KannalaBrandtK3Transform::DistorationParams
Eigen::Matrix< TScalar, kNumDistortionParams, 1 > DistorationParams
Definition: kannala_brandt.h:37
sophus::KannalaBrandtK3Transform
Definition: kannala_brandt.h:23
sophus::KannalaBrandtK3Transform::Params
Eigen::Matrix< TScalar, kNumParams, 1 > Params
Definition: kannala_brandt.h:35
common.h
sophus::KannalaBrandtK3Transform::undistort
static auto undistort(Params< TScalar > const &params, PixelImage< TScalar > const &pixel_image) -> ProjInCameraZ1Plane< TScalar >
Definition: kannala_brandt.h:90
sophus::KannalaBrandtK3Transform::kProjectionModel
static constexpr const std::string_view kProjectionModel
Definition: kannala_brandt.h:27
sophus::KannalaBrandtK3Transform::distort
static auto distort(Eigen::MatrixBase< TParamsTypeT > const &params, Eigen::MatrixBase< TPointTypeT > const &proj_point_in_camera_z1_plane) -> PixelImage< typename TPointTypeT::Scalar >
Definition: kannala_brandt.h:40
jet_helpers.h
sophus::AffineTransform::distort
static auto distort(Eigen::MatrixBase< TParamsTypeT > const &params, Eigen::MatrixBase< TPointTypeT > const &proj_point_in_camera_z1_plane) -> PixelImage< typename TPointTypeT::Scalar >
Definition: affine.h:32