49 float k1, k2, p1, p2, k3, k4, k5, k6, metric_radius;
72static const float SQRT_EPSILON = 0.00316;
83 float r_theta = dist->fisheye.k4 * theta2;
84 r_theta += dist->fisheye.k3;
86 r_theta += dist->fisheye.k2;
88 r_theta += dist->fisheye.k1;
104 bool is_valid =
true;
105 const float r2 = x * x + y * y;
106 const float r = sqrtf(r2);
108 if (r > SQRT_EPSILON) {
111 const float theta = atan2(r, z);
112 const float theta2 = theta * theta;
114 float r_theta = kb4_calc_r_theta(dist, theta, theta2);
116 const float mx = x * r_theta / r;
117 const float my = y * r_theta / r;
119 *out_x = dist->fx * mx + dist->cx;
120 *out_y = dist->fy * my + dist->cy;
123 if (z < SQRT_EPSILON) {
126 *out_x = dist->fx * x / z + dist->cx;
127 *out_y = dist->fy * y / z + dist->cy;
134kb4_solve_theta(
const struct t_camera_model_params *dist,
const float *r_theta,
float *d_func_d_theta)
136 float theta = *r_theta;
137 for (
int i = 4; i > 0; i--) {
138 float theta2 = theta * theta;
140 float func = dist->fisheye.k4 * theta2;
141 func += dist->fisheye.k3;
143 func += dist->fisheye.k2;
145 func += dist->fisheye.k1;
150 *d_func_d_theta = 9.0f * dist->fisheye.k4 * theta2;
151 *d_func_d_theta += 7.0f * dist->fisheye.k3;
152 *d_func_d_theta *= theta2;
153 *d_func_d_theta += 5.0f * dist->fisheye.k2;
154 *d_func_d_theta *= theta2;
155 *d_func_d_theta += 3.0f * dist->fisheye.k1;
156 *d_func_d_theta *= theta2;
157 *d_func_d_theta += 1.0f;
160 theta += ((*r_theta) - func) / (*d_func_d_theta);
174 const float mx = (x - dist->cx) / dist->fx;
175 const float my = (y - dist->cy) / dist->fy;
178 float sin_theta = 0.0;
179 float cos_theta = 1.0;
180 float thetad = sqrt(mx * mx + my * my);
182 float d_func_d_theta = 0.0;
184 if (thetad > SQRT_EPSILON) {
185 theta = kb4_solve_theta(dist, &thetad, &d_func_d_theta);
187 sin_theta = sin(theta);
188 cos_theta = cos(theta);
189 scaling = sin_theta / thetad;
192 *out_x = mx * scaling;
193 *out_y = my * scaling;
202kb4_undistort(
const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y)
224 const float xp = x / z;
225 const float yp = y / z;
226 const float rp2 = xp * xp + yp * yp;
227 const float cdist = (1.0f + rp2 * (dist->rt8.k1 + rp2 * (dist->rt8.k2 + rp2 * dist->rt8.k3))) /
228 (1.0f + rp2 * (dist->rt8.k4 + rp2 * (dist->rt8.k5 + rp2 * dist->rt8.k6)));
229 const float deltaX = 2.0f * dist->rt8.p1 * xp * yp + dist->rt8.p2 * (rp2 + 2.0f * xp * xp);
230 const float deltaY = 2.0f * dist->rt8.p2 * xp * yp + dist->rt8.p1 * (rp2 + 2.0f * yp * yp);
231 const float xpp = xp * cdist + deltaX;
232 const float ypp = yp * cdist + deltaY;
233 const float u = dist->fx * xpp + dist->cx;
234 const float v = dist->fy * ypp + dist->cy;
239 const float rpmax = dist->rt8.metric_radius;
240 bool positive_z = z >= SQRT_EPSILON;
241 bool in_injective_area = rpmax == 0.0f ? true : rp2 <= rpmax * rpmax;
242 bool is_valid = positive_z && in_injective_area;
252 const float k1 = params->rt8.k1;
253 const float k2 = params->rt8.k2;
254 const float p1 = params->rt8.p1;
255 const float p2 = params->rt8.p2;
256 const float k3 = params->rt8.k3;
257 const float k4 = params->rt8.k4;
258 const float k5 = params->rt8.k5;
259 const float k6 = params->rt8.k6;
261 const float xp = undist->x;
262 const float yp = undist->y;
263 const float rp2 = xp * xp + yp * yp;
264 const float cdist = (1.0f + rp2 * (k1 + rp2 * (k2 + rp2 * k3))) / (1.0f + rp2 * (k4 + rp2 * (k5 + rp2 * k6)));
265 const float deltaX = 2.0f * p1 * xp * yp + p2 * (rp2 + 2.0f * xp * xp);
266 const float deltaY = 2.0f * p2 * xp * yp + p1 * (rp2 + 2.0f * yp * yp);
267 const float xpp = xp * cdist + deltaX;
268 const float ypp = yp * cdist + deltaY;
274 const float v0 = xp * xp;
275 const float v1 = yp * yp;
276 const float v2 = v0 + v1;
277 const float v3 = k6 * v2;
278 const float v4 = k4 + v2 * (k5 + v3);
279 const float v5 = v2 * v4 + 1.0f;
280 const float v6 = v5 * v5;
281 const float v7 = 1.0f / v6;
282 const float v8 = p1 * yp;
283 const float v9 = p2 * xp;
284 const float v10 = 2.0f * v6;
285 const float v11 = k3 * v2;
286 const float v12 = k1 + v2 * (k2 + v11);
287 const float v13 = v12 * v2 + 1.0f;
288 const float v14 = v13 * (v2 * (k5 + 2.0f * v3) + v4);
289 const float v15 = 2.0f * v14;
290 const float v16 = v12 + v2 * (k2 + 2.0f * v11);
291 const float v17 = 2.0f * v16;
292 const float v18 = xp * yp;
293 const float v19 = 2.0f * v7 * (-v14 * v18 + v16 * v18 * v5 + v6 * (p1 * xp + p2 * yp));
295 const float dxpp_dxp = v7 * (-v0 * v15 + v10 * (v8 + 3.0f * v9) + v5 * (v0 * v17 + v13));
296 const float dxpp_dyp = v19;
297 const float dypp_dxp = v19;
298 const float dypp_dyp = v7 * (-v1 * v15 + v10 * (3.0f * v8 + v9) + v5 * (v1 * v17 + v13));
300 d_dist_d_undist->v[0] = dxpp_dxp;
301 d_dist_d_undist->v[1] = dxpp_dyp;
302 d_dist_d_undist->v[2] = dypp_dxp;
303 d_dist_d_undist->v[3] = dypp_dyp;
309 const float x0 = (u - hg_dist->cx) / hg_dist->fx;
310 const float y0 = (v - hg_dist->cy) / hg_dist->fy;
321 for (
int i = 0; i < N; i++) {
325 rt8_distort(hg_dist, &undist, &fundist, &J);
326 struct xrt_vec2 residual = m_vec2_sub(fundist, dist);
331 m_mat2x2_invert(&J, &J_inverse);
335 m_mat2x2_transform_vec2(&J_inverse, &residual, &undist_sub);
337 undist = m_vec2_sub(undist, undist_sub);
338 if (m_vec2_len(residual) < SQRT_EPSILON) {
348 const struct t_camera_model_params *hg_dist,
const float u,
const float v,
float *out_x,
float *out_y,
float *out_z)
354 const float norm_inv = 1.0f / sqrt(xp * xp + yp * yp + 1.0f);
355 *out_x = xp * norm_inv;
356 *out_y = yp * norm_inv;
359 const float rp2 = xp * xp + yp * yp;
360 bool in_injective_area =
361 hg_dist->rt8.metric_radius == 0.0f ? true : rp2 <= hg_dist->rt8.metric_radius * hg_dist->rt8.metric_radius;
362 bool is_valid = in_injective_area;
376 *out_x = ((dist->fx * x / z) + dist->cx);
377 *out_y = ((dist->fy * y / z) + dist->cy);
379 bool is_valid = z >= SQRT_EPSILON;
390 const float mx = (x - dist->cx) / dist->fx;
391 const float my = (y - dist->cy) / dist->fy;
393 const float r2 = mx * mx + my * my;
395 const float norm = sqrtf(1.0f + r2);
397 const float norm_inv = 1.0f / norm;
399 *out_x = mx * norm_inv;
400 *out_y = my * norm_inv;
425 for (
size_t i = 0; i < dist_num; i++) {
428 distortion_tmp[i] = cc->distortion_parameters_as_array[i];
432 out_params->rt8.k1 = distortion_tmp[acc_idx++];
433 out_params->rt8.k2 = distortion_tmp[acc_idx++];
434 out_params->rt8.p1 = distortion_tmp[acc_idx++];
435 out_params->rt8.p2 = distortion_tmp[acc_idx++];
436 out_params->rt8.k3 = distortion_tmp[acc_idx++];
437 out_params->rt8.k4 = distortion_tmp[acc_idx++];
438 out_params->rt8.k5 = distortion_tmp[acc_idx++];
439 out_params->rt8.k6 = distortion_tmp[acc_idx++];
444 out_params->rt8.metric_radius = cc->wmr.rpmax;
446 out_params->rt8.metric_radius = 0;
481 out_params->fisheye.k1 = (float)cc->kb4.k1;
482 out_params->fisheye.k2 = (
float)cc->kb4.k2;
483 out_params->fisheye.k3 = (float)cc->kb4.k3;
484 out_params->fisheye.k4 = (
float)cc->kb4.k4;
491 U_LOG_E(
"t_camera_un_projections doesn't support camera model %s yet!",
503 const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y,
float *out_z)
505 switch (dist->model) {
507 return rt8_unproject(dist, x, y, out_x, out_y, out_z);
513 default: assert(
false);
return false;
524 const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y,
float *out_z)
541 switch (dist->model) {
546 kb4_undistort(dist, x, y, out_x, out_y);
549 default: assert(
false);
566 switch (dist->model) {
568 return rt8_project(dist, x, y, z, out_x, out_y);
571 return kb4_project(dist, x, y, z, out_x, out_y);
574 default: assert(
false);
return false;
#define U_LOG_E(...)
Log a message at U_LOGGING_ERROR level, conditional on the global log level.
Definition: u_logging.h:442
#define U_LOG_W(...)
Log a message at U_LOGGING_WARN level, conditional on the global log level.
Definition: u_logging.h:439
static const char * t_stringify_camera_distortion_model(const enum t_camera_distortion_model model)
Stringifies a t_camera_distortion_model.
Definition: t_tracking.h:141
#define XRT_DISTORTION_MAX_DIM
Maximum size of rectilinear distortion coefficient array.
Definition: t_tracking.h:54
static size_t t_num_params_from_distortion_model(const enum t_camera_distortion_model model)
Returns the number of parameters needed for this t_camera_distortion_model to be held by an OpenCV Ma...
Definition: t_tracking.h:161
t_camera_distortion_model
The distortion model this camera calibration falls under.
Definition: t_tracking.h:63
@ T_DISTORTION_OPENCV_RADTAN_8
OpenCV's radial-tangential distortion model.
Definition: t_tracking.h:82
@ T_DISTORTION_OPENCV_RADTAN_5
OpenCV's radial-tangential distortion model.
Definition: t_tracking.h:73
@ T_DISTORTION_FISHEYE_KB4
Juho Kannalla and Sami Sebastian Brandt's fisheye distortion model.
Definition: t_tracking.h:116
@ T_DISTORTION_WMR
Windows Mixed Reality headsets' camera model.
Definition: t_tracking.h:131
@ T_DISTORTION_OPENCV_RADTAN_14
OpenCV's radial-tangential distortion model.
Definition: t_tracking.h:101
#define U_ZERO(PTR)
Zeroes the correct amount of memory based on the type pointed-to by the argument.
Definition: u_misc.h:68
Wrapper header for <math.h> to ensure pi-related math constants are defined.
C matrix_2x2 math library.
Floating point parameters for T_DISTORTION_FISHEYE_KB4.
Definition: t_camera_models.h:38
Floating point parameters for T_DISTORTION_OPENCV_RADTAN_8, also including metric_radius.
Definition: t_camera_models.h:48
Essential calibration data for a single camera, or single lens/sensor of a stereo camera.
Definition: t_tracking.h:236
double intrinsics[3][3]
Camera intrinsics matrix.
Definition: t_tracking.h:241
enum t_camera_distortion_model distortion_model
Distortion model that this camera uses.
Definition: t_tracking.h:254
Floating point calibration data for a single calibrated camera.
Definition: t_camera_models.h:59
A tightly packed 2x2 matrix of floats.
Definition: xrt_defines.h:526
A 2 element vector with single floats.
Definition: xrt_defines.h:268
static bool t_camera_models_flip_and_project(const struct t_camera_model_params *dist, const float x, const float y, const float z, float *out_x, float *out_y)
Takes a 3D point through x, y, and z, flips its Y and Z values (performing a coordinate space transfo...
Definition: t_camera_models.h:584
static bool t_camera_models_project(const struct t_camera_model_params *dist, const float x, const float y, const float z, float *out_x, float *out_y)
Takes a 3D point through x, y, and z, projects it into image space, and returns the result through ou...
Definition: t_camera_models.h:559
static bool t_camera_models_unproject(const struct t_camera_model_params *dist, const float x, const float y, float *out_x, float *out_y, float *out_z)
Takes a 2D image-space point through x and y, unprojects it to a normalized 3D direction,...
Definition: t_camera_models.h:502
static void t_camera_models_undistort(const struct t_camera_model_params *dist, const float x, const float y, float *out_x, float *out_y)
Takes a distorted 2D point through x and y and computes the undistorted point into out_x and out_y.
Definition: t_camera_models.h:538
static void rt8_undistort(const struct t_camera_model_params *hg_dist, const float u, const float v, float *out_x, float *out_y)
Definition: t_camera_models.h:307
static void t_camera_model_params_from_t_camera_calibration(const struct t_camera_calibration *cc, struct t_camera_model_params *out_params)
Takes a t_camera_calibration through cc, and returns a t_camera_model_params that shadows cc 's param...
Definition: t_camera_models.h:460
static bool t_camera_models_unproject_and_flip(const struct t_camera_model_params *dist, const float x, const float y, float *out_x, float *out_y, float *out_z)
Takes a 2D image-space point through x and y, unprojects it to a normalized 3D direction,...
Definition: t_camera_models.h:523
static bool kb4_unproject(const struct t_camera_model_params *dist, const float x, const float y, float *out_x, float *out_y, float *out_z)
Definition: t_camera_models.h:167