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;
89 out_x = ((CAST(dist.fx) * x / z) + CAST(dist.cx));
90 out_y = ((CAST(dist.fy) * y / z) + CAST(dist.cy));
92 bool is_valid = z >= kSqrtEpsilon;
105 const T mx = (x - CAST(dist.cx)) / CAST(dist.fx);
106 const T my = (y - CAST(dist.cy)) / CAST(dist.fy);
108 const T r2 = mx * mx + my * my;
110 const T norm = sqrt(CAST(1.0) + r2);
112 const T norm_inv = CAST(1.0) / norm;
114 out_x = mx * norm_inv;
115 out_y = my * norm_inv;
132 T r_theta = CAST(dist.fisheye.k4) * theta2;
133 r_theta += CAST(dist.fisheye.k3);
135 r_theta += CAST(dist.fisheye.k2);
137 r_theta += CAST(dist.fisheye.k1);
139 r_theta += CAST(1.0);
154 const T r2 = x * x + y * y;
155 const T r = sqrt(r2);
157 if (r > kSqrtEpsilon) {
158 const T theta = atan2(r, z);
159 const T theta2 = theta * theta;
161 T r_theta = kb4_calc_r_theta(dist, theta, theta2);
163 const T mx = x * r_theta / r;
164 const T my = y * r_theta / r;
166 out_x = CAST(dist.fx) * mx + CAST(dist.cx);
167 out_y = CAST(dist.fy) * my + CAST(dist.cy);
171 out_x = CAST(dist.fx) * x / z + CAST(dist.cx);
172 out_y = CAST(dist.fy) * y / z + CAST(dist.cy);
175 return z >= kSqrtEpsilon;
178 assert(!
"Unreachable");
186 for (
int i = 4; i > 0; i--) {
187 T theta2 = theta * theta;
189 T func = CAST(dist.fisheye.k4) * theta2;
190 func += CAST(dist.fisheye.k3);
192 func += CAST(dist.fisheye.k2);
194 func += CAST(dist.fisheye.k1);
199 (*d_func_d_theta) = CAST(9.0 * dist.fisheye.k4) * theta2;
200 (*d_func_d_theta) += CAST(7.0 * dist.fisheye.k3);
201 (*d_func_d_theta) *= theta2;
202 (*d_func_d_theta) += CAST(5.0 * dist.fisheye.k2);
203 (*d_func_d_theta) *= theta2;
204 (*d_func_d_theta) += CAST(3.0 * dist.fisheye.k1);
205 (*d_func_d_theta) *= theta2;
206 (*d_func_d_theta) += CAST(1.0);
209 theta += (r_theta - func) / (*d_func_d_theta);
224 const T mx = (x - CAST(dist.cx)) / CAST(dist.fx);
225 const T my = (y - CAST(dist.cy)) / CAST(dist.fy);
228 T sin_theta = CAST(0.0);
229 T cos_theta = CAST(1.0);
230 T thetad = sqrt(mx * mx + my * my);
231 T scaling = CAST(1.0);
232 T d_func_d_theta = CAST(0.0);
234 if (thetad > kSqrtEpsilon) {
235 theta = kb4_solve_theta(dist, thetad, &d_func_d_theta);
237 sin_theta = sin(theta);
238 cos_theta = cos(theta);
239 scaling = sin_theta / thetad;
242 out_x = mx * scaling;
243 out_y = my * scaling;
257 kb4_unproject(dist, x, y, xp, yp, zp);
278 const T rp2 = xp * xp + yp * yp;
279 const T cdist = (CAST(1.0) + rp2 * (CAST(dist.rt8.k1) + rp2 * (CAST(dist.rt8.k2) + rp2 * CAST(dist.rt8.k3)))) /
280 (CAST(1.0) + rp2 * (CAST(dist.rt8.k4) + rp2 * (CAST(dist.rt8.k5) + rp2 * CAST(dist.rt8.k6))));
281 const T deltaX = CAST(2.0f * dist.rt8.p1) * xp * yp + CAST(dist.rt8.p2) * (rp2 + CAST(2.0) * xp * xp);
282 const T deltaY = CAST(2.0f * dist.rt8.p2) * xp * yp + CAST(dist.rt8.p1) * (rp2 + CAST(2.0) * yp * yp);
283 const T xpp = xp * cdist + deltaX;
284 const T ypp = yp * cdist + deltaY;
285 const T u = CAST(dist.fx) * xpp + CAST(dist.cx);
286 const T v = CAST(dist.fy) * ypp + CAST(dist.cy);
291 const float rpmax = dist.rt8.metric_radius;
293 bool positive_z = z >= kSqrtEpsilon;
294 bool in_injective_area = rpmax == 0.0 ? true : rp2 <= rpmax * rpmax;
295 bool is_valid = positive_z && in_injective_area;
305 Matrix2x2<T> &out_d_dist_d_undist)
307 const T k1 = CAST(params.rt8.k1);
308 const T k2 = CAST(params.rt8.k2);
309 const T p1 = CAST(params.rt8.p1);
310 const T p2 = CAST(params.rt8.p2);
311 const T k3 = CAST(params.rt8.k3);
312 const T k4 = CAST(params.rt8.k4);
313 const T k5 = CAST(params.rt8.k5);
314 const T k6 = CAST(params.rt8.k6);
316 const T xp = undist.x;
317 const T yp = undist.y;
318 const T rp2 = xp * xp + yp * yp;
319 const T cdist = (CAST(1.0) + rp2 * (k1 + rp2 * (k2 + rp2 * k3))) /
320 (CAST(1.0) + rp2 * (k4 + rp2 * (k5 + rp2 * k6)));
321 const T deltaX = CAST(2.0) * p1 * xp * yp + p2 * (rp2 + CAST(2.0) * xp * xp);
322 const T deltaY = CAST(2.0) * p2 * xp * yp + p1 * (rp2 + CAST(2.0) * yp * yp);
323 const T xpp = xp * cdist + deltaX;
324 const T ypp = yp * cdist + deltaY;
330 const T v0 = xp * xp;
331 const T v1 = yp * yp;
332 const T v2 = v0 + v1;
333 const T v3 = k6 * v2;
334 const T v4 = k4 + v2 * (k5 + v3);
335 const T v5 = v2 * v4 + CAST(1.0);
336 const T v6 = v5 * v5;
337 const T v7 = CAST(1.0) / v6;
338 const T v8 = p1 * yp;
339 const T v9 = p2 * xp;
340 const T v10 = CAST(2.0) * v6;
341 const T v11 = k3 * v2;
342 const T v12 = k1 + v2 * (k2 + v11);
343 const T v13 = v12 * v2 + CAST(1.0);
344 const T v14 = v13 * (v2 * (k5 + CAST(2.0) * v3) + v4);
345 const T v15 = CAST(2.0) * v14;
346 const T v16 = v12 + v2 * (k2 + CAST(2.0) * v11);
347 const T v17 = CAST(2.0) * v16;
348 const T v18 = xp * yp;
349 const T v19 = CAST(2.0) * v7 * (-v14 * v18 + v16 * v18 * v5 + v6 * (p1 * xp + p2 * yp));
351 const T dxpp_dxp = v7 * (-v0 * v15 + v10 * (v8 + CAST(3.0) * v9) + v5 * (v0 * v17 + v13));
352 const T dxpp_dyp = v19;
353 const T dypp_dxp = v19;
354 const T dypp_dyp = v7 * (-v1 * v15 + v10 * (CAST(3.0) * v8 + v9) + v5 * (v1 * v17 + v13));
356 out_d_dist_d_undist.v[0] = dxpp_dxp;
357 out_d_dist_d_undist.v[1] = dxpp_dyp;
358 out_d_dist_d_undist.v[2] = dypp_dxp;
359 out_d_dist_d_undist.v[3] = dypp_dyp;
366 const T x0 = (u - CAST(params.cx)) / CAST(params.fx);
367 const T y0 = (v - CAST(params.cy)) / CAST(params.fy);
378 for (
int i = 0; i < N; i++) {
382 rt8_distort(params, undist, fundist, J);
392 J_inverse.transformVector2(residual, undist_sub);
394 undist = undist.sub(undist_sub);
395 if (residual.length() < kSqrtEpsilon) {
406rt8_unproject(
const t_camera_model_params ¶ms,
const T &u,
const T &v, T &out_x, T &out_y, T &out_z)
409 rt8_undistort(params, u, v, xp, yp);
411 const T norm_inv = CAST(1.0) / sqrt(xp * xp + yp * yp + CAST(1.0));
412 out_x = xp * norm_inv;
413 out_y = yp * norm_inv;
416 const T rp2 = xp * xp + yp * yp;
417 bool in_injective_area =
418 params.rt8.metric_radius == 0.0f ? true : rp2 <= CAST(params.rt8.metric_radius * params.rt8.metric_radius);
419 bool is_valid = in_injective_area;
433 if (r == CAST(0.0)) {
442 T poly = CAST(dist.cv1.k4) * t2;
443 poly += CAST(dist.cv1.k3);
445 poly += CAST(dist.cv1.k2);
447 poly += CAST(dist.cv1.k1);
451 return (t / r) / poly;
459 const T p1 = CAST(dist.cv1.p1);
460 const T p2 = CAST(dist.cv1.p2);
461 const T rq2 = qx * qx + qy * qy;
463 T dx = (CAST(2.0) * qx * qx + rq2) * p1 + CAST(2.0) * p2 * qx * qy;
464 T dy = (CAST(2.0) * qy * qy + rq2) * p2 + CAST(2.0) * p1 * qx * qy;
467 const T
gain = CAST(1.0) + rq2 * (CAST(dist.cv1.g3) + rq2 * CAST(dist.cv1.g4));
480 const T px = (x - CAST(dist.cx)) / CAST(dist.fx);
481 const T py = (y - CAST(dist.cy)) / CAST(dist.fy);
483 const T r = sqrt(px * px + py * py);
486 const T qx = scale * px;
487 const T qy = scale * py;
512 switch (dist.model) {
514 return pinhole_project(dist, x, y, z, out_x, out_y);
517 return rt8_project(dist, x, y, z, out_x, out_y);
520 return kb4_project(dist, x, y, z, out_x, out_y);
524 out_x = T(dist.fx) * x / z + T(dist.cx);
525 out_y = T(dist.fy) * y / z + T(dist.cy);
531 default: assert(
false);
return false;
539 switch (dist.model) {
548 kb4_undistort(dist, x, y, out_x, out_y);
554 default: assert(
false);
Definition utility_northstar.h:270
@ T_DISTORTION_OPENCV_RADTAN_8
OpenCV's radial-tangential distortion model.
Definition t_tracking.h:87
@ T_DISTORTION_FISHEYE_KB4
Juho Kannalla and Sami Sebastian Brandt's fisheye distortion model.
Definition t_tracking.h:121
@ T_DISTORTION_RIFT_CV1
The Oculus Rift CV1 constellation sensor's lens model (LensModel "type 6" in Oculus' runtime).
Definition t_tracking.h:149
@ T_DISTORTION_PINHOLE
A perfect pinhole camera with no distortion.
Definition t_tracking.h:67
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:62
Definition t_camera_models.hpp:53
Definition t_camera_models.hpp:33
Camera (un)projection C API for various camera models.
static T cv1_radial_undistort_scale(const t_camera_model_params &dist, const T &r)
Radial undistortion scale s = |ray| / |p| for a distorted normalized image point of radius r.
Definition t_camera_models.hpp:431
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:364
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:217
static void cv1_undistort(const t_camera_model_params &dist, const T &x, const T &y, T &out_x, T &out_y)
Maps a distorted image-space point (x, y) to a pinhole ray tangent (x/z, y/z).
Definition t_camera_models.hpp:476
static void cv1_decentering_delta(const t_camera_model_params &dist, const T &qx, const T &qy, T &out_dx, T &out_dy)
Tangential ("decentering") delta with the CV1 4th-order affine gain (p1, p2, g3, g4),...
Definition t_camera_models.hpp:457
__le16 gain
observed 16 to 255
Definition wmr_camera.c:5