23namespace xrt::auxiliary::tracking::camera_models {
25static constexpr double kSqrtEpsilon = 0.00316;
28#define CAST(x) static_cast<T>(x)
42 return {this->x - other.x, this->y - other.y};
48 return sqrt(this->x * this->x + this->y * this->y);
61 T determinant = v[0] * v[3] - v[1] * v[2];
62 invertedMatrix.v[0] = v[3] / determinant;
63 invertedMatrix.v[1] = -v[1] / determinant;
64 invertedMatrix.v[2] = -v[2] / determinant;
65 invertedMatrix.v[3] = v[0] / determinant;
71 result_out.x = v[0] * vec.x + v[1] * vec.y;
72 result_out.y = v[2] * vec.x + v[3] * vec.y;
86 T r_theta = CAST(dist.fisheye.k4) * theta2;
87 r_theta += CAST(dist.fisheye.k3);
89 r_theta += CAST(dist.fisheye.k2);
91 r_theta += CAST(dist.fisheye.k1);
108 const T r2 = x * x + y * y;
109 const T r = sqrt(r2);
111 if (r > kSqrtEpsilon) {
112 const T theta = atan2(r, z);
113 const T theta2 = theta * theta;
115 T r_theta = kb4_calc_r_theta(dist, theta, theta2);
117 const T mx = x * r_theta / r;
118 const T my = y * r_theta / r;
120 out_x = CAST(dist.fx) * mx + CAST(dist.cx);
121 out_y = CAST(dist.fy) * my + CAST(dist.cy);
125 out_x = CAST(dist.fx) * x / z + CAST(dist.cx);
126 out_y = CAST(dist.fy) * y / z + CAST(dist.cy);
129 return z >= kSqrtEpsilon;
132 assert(!
"Unreachable");
140 for (
int i = 4; i > 0; i--) {
141 T theta2 = theta * theta;
143 T func = CAST(dist.fisheye.k4) * theta2;
144 func += CAST(dist.fisheye.k3);
146 func += CAST(dist.fisheye.k2);
148 func += CAST(dist.fisheye.k1);
153 (*d_func_d_theta) = CAST(9.0 * dist.fisheye.k4) * theta2;
154 (*d_func_d_theta) += CAST(7.0 * dist.fisheye.k3);
155 (*d_func_d_theta) *= theta2;
156 (*d_func_d_theta) += CAST(5.0 * dist.fisheye.k2);
157 (*d_func_d_theta) *= theta2;
158 (*d_func_d_theta) += CAST(3.0 * dist.fisheye.k1);
159 (*d_func_d_theta) *= theta2;
160 (*d_func_d_theta) += CAST(1.0);
163 theta += (r_theta - func) / (*d_func_d_theta);
178 const T mx = (x - CAST(dist.cx)) / CAST(dist.fx);
179 const T my = (y - CAST(dist.cy)) / CAST(dist.fy);
182 T sin_theta = CAST(0.0);
183 T cos_theta = CAST(1.0);
184 T thetad = sqrt(mx * mx + my * my);
185 T scaling = CAST(1.0);
186 T d_func_d_theta = CAST(0.0);
188 if (thetad > kSqrtEpsilon) {
189 theta = kb4_solve_theta(dist, thetad, &d_func_d_theta);
191 sin_theta = sin(theta);
192 cos_theta = cos(theta);
193 scaling = sin_theta / thetad;
196 out_x = mx * scaling;
197 out_y = my * scaling;
211 kb4_unproject(dist, x, y, xp, yp, zp);
232 const T rp2 = xp * xp + yp * yp;
233 const T cdist = (CAST(1.0) + rp2 * (CAST(dist.rt8.k1) + rp2 * (CAST(dist.rt8.k2) + rp2 * CAST(dist.rt8.k3)))) /
234 (CAST(1.0) + rp2 * (CAST(dist.rt8.k4) + rp2 * (CAST(dist.rt8.k5) + rp2 * CAST(dist.rt8.k6))));
235 const T deltaX = CAST(2.0f * dist.rt8.p1) * xp * yp + CAST(dist.rt8.p2) * (rp2 + CAST(2.0) * xp * xp);
236 const T deltaY = CAST(2.0f * dist.rt8.p2) * xp * yp + CAST(dist.rt8.p1) * (rp2 + CAST(2.0) * yp * yp);
237 const T xpp = xp * cdist + deltaX;
238 const T ypp = yp * cdist + deltaY;
239 const T u = CAST(dist.fx) * xpp + CAST(dist.cx);
240 const T v = CAST(dist.fy) * ypp + CAST(dist.cy);
245 const float rpmax = dist.rt8.metric_radius;
247 bool positive_z = z >= kSqrtEpsilon;
248 bool in_injective_area = rpmax == 0.0 ? true : rp2 <= rpmax * rpmax;
249 bool is_valid = positive_z && in_injective_area;
259 Matrix2x2<T> &out_d_dist_d_undist)
261 const T k1 = CAST(params.rt8.k1);
262 const T k2 = CAST(params.rt8.k2);
263 const T p1 = CAST(params.rt8.p1);
264 const T p2 = CAST(params.rt8.p2);
265 const T k3 = CAST(params.rt8.k3);
266 const T k4 = CAST(params.rt8.k4);
267 const T k5 = CAST(params.rt8.k5);
268 const T k6 = CAST(params.rt8.k6);
270 const T xp = undist.x;
271 const T yp = undist.y;
272 const T rp2 = xp * xp + yp * yp;
273 const T cdist = (CAST(1.0) + rp2 * (k1 + rp2 * (k2 + rp2 * k3))) /
274 (CAST(1.0) + rp2 * (k4 + rp2 * (k5 + rp2 * k6)));
275 const T deltaX = CAST(2.0) * p1 * xp * yp + p2 * (rp2 + CAST(2.0) * xp * xp);
276 const T deltaY = CAST(2.0) * p2 * xp * yp + p1 * (rp2 + CAST(2.0) * yp * yp);
277 const T xpp = xp * cdist + deltaX;
278 const T ypp = yp * cdist + deltaY;
284 const T v0 = xp * xp;
285 const T v1 = yp * yp;
286 const T v2 = v0 + v1;
287 const T v3 = k6 * v2;
288 const T v4 = k4 + v2 * (k5 + v3);
289 const T v5 = v2 * v4 + CAST(1.0);
290 const T v6 = v5 * v5;
291 const T v7 = CAST(1.0) / v6;
292 const T v8 = p1 * yp;
293 const T v9 = p2 * xp;
294 const T v10 = CAST(2.0) * v6;
295 const T v11 = k3 * v2;
296 const T v12 = k1 + v2 * (k2 + v11);
297 const T v13 = v12 * v2 + CAST(1.0);
298 const T v14 = v13 * (v2 * (k5 + CAST(2.0) * v3) + v4);
299 const T v15 = CAST(2.0) * v14;
300 const T v16 = v12 + v2 * (k2 + CAST(2.0) * v11);
301 const T v17 = CAST(2.0) * v16;
302 const T v18 = xp * yp;
303 const T v19 = CAST(2.0) * v7 * (-v14 * v18 + v16 * v18 * v5 + v6 * (p1 * xp + p2 * yp));
305 const T dxpp_dxp = v7 * (-v0 * v15 + v10 * (v8 + CAST(3.0) * v9) + v5 * (v0 * v17 + v13));
306 const T dxpp_dyp = v19;
307 const T dypp_dxp = v19;
308 const T dypp_dyp = v7 * (-v1 * v15 + v10 * (CAST(3.0) * v8 + v9) + v5 * (v1 * v17 + v13));
310 out_d_dist_d_undist.v[0] = dxpp_dxp;
311 out_d_dist_d_undist.v[1] = dxpp_dyp;
312 out_d_dist_d_undist.v[2] = dypp_dxp;
313 out_d_dist_d_undist.v[3] = dypp_dyp;
320 const T x0 = (u - CAST(params.cx)) / CAST(params.fx);
321 const T y0 = (v - CAST(params.cy)) / CAST(params.fy);
332 for (
int i = 0; i < N; i++) {
336 rt8_distort(params, undist, fundist, J);
346 J_inverse.transformVector2(residual, undist_sub);
348 undist = undist.sub(undist_sub);
349 if (residual.length() < kSqrtEpsilon) {
360rt8_unproject(
const t_camera_model_params ¶ms,
const T &u,
const T &v, T &out_x, T &out_y, T &out_z)
363 rt8_undistort(params, u, v, xp, yp);
365 const T norm_inv = CAST(1.0) / sqrt(xp * xp + yp * yp + CAST(1.0));
366 out_x = xp * norm_inv;
367 out_y = yp * norm_inv;
370 const T rp2 = xp * xp + yp * yp;
371 bool in_injective_area =
372 params.rt8.metric_radius == 0.0f ? true : rp2 <= CAST(params.rt8.metric_radius * params.rt8.metric_radius);
373 bool is_valid = in_injective_area;
388 out_x = ((CAST(dist.fx) * x / z) + CAST(dist.cx));
389 out_y = ((CAST(dist.fy) * y / z) + CAST(dist.cy));
391 bool is_valid = z >= kSqrtEpsilon;
404 const T mx = (x - CAST(dist.cx)) / CAST(dist.fx);
405 const T my = (y - CAST(dist.cy)) / CAST(dist.fy);
407 const T r2 = mx * mx + my * my;
409 const T norm = sqrt(CAST(1.0) + r2);
411 const T norm_inv = CAST(1.0) / norm;
413 out_x = mx * norm_inv;
414 out_y = my * norm_inv;
438 switch (dist.model) {
440 return rt8_project(dist, x, y, z, out_x, out_y);
443 return kb4_project(dist, x, y, z, out_x, out_y);
446 default: assert(
false);
return false;
454 switch (dist.model) {
459 kb4_undistort(dist, x, y, out_x, out_y);
462 default: assert(
false);
Definition utility_northstar.h:270
@ T_DISTORTION_OPENCV_RADTAN_8
OpenCV's radial-tangential distortion model.
Definition t_tracking.h:82
@ T_DISTORTION_FISHEYE_KB4
Juho Kannalla and Sami Sebastian Brandt's fisheye distortion model.
Definition t_tracking.h:116
Wrapper header for <math.h> to ensure pi-related math constants are defined.
C matrix_2x2 math library.
Floating point calibration data for a single calibrated camera.
Definition t_camera_models.h:47
Definition t_camera_models.hpp:53
Definition t_camera_models.hpp:33
Camera (un)projection C API for various camera models.
static void rt8_undistort(const t_camera_model_params ¶ms, const T &u, const T &v, T &out_x, T &out_y)
Definition t_camera_models.hpp:318
static bool kb4_unproject(const t_camera_model_params &dist, const T &x, const T &y, T &out_x, T &out_y, T &out_z)
Definition t_camera_models.hpp:171