48 float k1, k2, p1, p2, k3, k4, k5, k6, metric_radius;
71static const float SQRT_EPSILON = 0.00316;
82 float r_theta = dist->fisheye.k4 * theta2;
83 r_theta += dist->fisheye.k3;
85 r_theta += dist->fisheye.k2;
87 r_theta += dist->fisheye.k1;
103 bool is_valid =
true;
104 const float r2 = x * x + y * y;
105 const float r = sqrtf(r2);
107 if (r > SQRT_EPSILON) {
110 const float theta = atan2(r, z);
111 const float theta2 = theta * theta;
113 float r_theta = kb4_calc_r_theta(dist, theta, theta2);
115 const float mx = x * r_theta / r;
116 const float my = y * r_theta / r;
118 *out_x = dist->fx * mx + dist->cx;
119 *out_y = dist->fy * my + dist->cy;
122 if (z < SQRT_EPSILON) {
125 *out_x = dist->fx * x / z + dist->cx;
126 *out_y = dist->fy * y / z + dist->cy;
133kb4_solve_theta(
const struct t_camera_model_params *dist,
const float *r_theta,
float *d_func_d_theta)
135 float theta = *r_theta;
136 for (
int i = 4; i > 0; i--) {
137 float theta2 = theta * theta;
139 float func = dist->fisheye.k4 * theta2;
140 func += dist->fisheye.k3;
142 func += dist->fisheye.k2;
144 func += dist->fisheye.k1;
149 *d_func_d_theta = 9.0f * dist->fisheye.k4 * theta2;
150 *d_func_d_theta += 7.0f * dist->fisheye.k3;
151 *d_func_d_theta *= theta2;
152 *d_func_d_theta += 5.0f * dist->fisheye.k2;
153 *d_func_d_theta *= theta2;
154 *d_func_d_theta += 3.0f * dist->fisheye.k1;
155 *d_func_d_theta *= theta2;
156 *d_func_d_theta += 1.0f;
159 theta += ((*r_theta) - func) / (*d_func_d_theta);
173 const float mx = (x - dist->cx) / dist->fx;
174 const float my = (y - dist->cy) / dist->fy;
177 float sin_theta = 0.0;
178 float cos_theta = 1.0;
179 float thetad = sqrt(mx * mx + my * my);
181 float d_func_d_theta = 0.0;
183 if (thetad > SQRT_EPSILON) {
184 theta = kb4_solve_theta(dist, &thetad, &d_func_d_theta);
186 sin_theta = sin(theta);
187 cos_theta = cos(theta);
188 scaling = sin_theta / thetad;
191 *out_x = mx * scaling;
192 *out_y = my * scaling;
201kb4_undistort(
const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y)
223 const float xp = x / z;
224 const float yp = y / z;
225 const float rp2 = xp * xp + yp * yp;
226 const float cdist = (1.0f + rp2 * (dist->rt8.k1 + rp2 * (dist->rt8.k2 + rp2 * dist->rt8.k3))) /
227 (1.0f + rp2 * (dist->rt8.k4 + rp2 * (dist->rt8.k5 + rp2 * dist->rt8.k6)));
228 const float deltaX = 2.0f * dist->rt8.p1 * xp * yp + dist->rt8.p2 * (rp2 + 2.0f * xp * xp);
229 const float deltaY = 2.0f * dist->rt8.p2 * xp * yp + dist->rt8.p1 * (rp2 + 2.0f * yp * yp);
230 const float xpp = xp * cdist + deltaX;
231 const float ypp = yp * cdist + deltaY;
232 const float u = dist->fx * xpp + dist->cx;
233 const float v = dist->fy * ypp + dist->cy;
238 const float rpmax = dist->rt8.metric_radius;
239 bool positive_z = z >= SQRT_EPSILON;
240 bool in_injective_area = rpmax == 0.0f ? true : rp2 <= rpmax * rpmax;
241 bool is_valid = positive_z && in_injective_area;
251 const float k1 = params->rt8.k1;
252 const float k2 = params->rt8.k2;
253 const float p1 = params->rt8.p1;
254 const float p2 = params->rt8.p2;
255 const float k3 = params->rt8.k3;
256 const float k4 = params->rt8.k4;
257 const float k5 = params->rt8.k5;
258 const float k6 = params->rt8.k6;
260 const float xp = undist->x;
261 const float yp = undist->y;
262 const float rp2 = xp * xp + yp * yp;
263 const float cdist = (1.0f + rp2 * (k1 + rp2 * (k2 + rp2 * k3))) / (1.0f + rp2 * (k4 + rp2 * (k5 + rp2 * k6)));
264 const float deltaX = 2.0f * p1 * xp * yp + p2 * (rp2 + 2.0f * xp * xp);
265 const float deltaY = 2.0f * p2 * xp * yp + p1 * (rp2 + 2.0f * yp * yp);
266 const float xpp = xp * cdist + deltaX;
267 const float ypp = yp * cdist + deltaY;
273 const float v0 = xp * xp;
274 const float v1 = yp * yp;
275 const float v2 = v0 + v1;
276 const float v3 = k6 * v2;
277 const float v4 = k4 + v2 * (k5 + v3);
278 const float v5 = v2 * v4 + 1.0f;
279 const float v6 = v5 * v5;
280 const float v7 = 1.0f / v6;
281 const float v8 = p1 * yp;
282 const float v9 = p2 * xp;
283 const float v10 = 2.0f * v6;
284 const float v11 = k3 * v2;
285 const float v12 = k1 + v2 * (k2 + v11);
286 const float v13 = v12 * v2 + 1.0f;
287 const float v14 = v13 * (v2 * (k5 + 2.0f * v3) + v4);
288 const float v15 = 2.0f * v14;
289 const float v16 = v12 + v2 * (k2 + 2.0f * v11);
290 const float v17 = 2.0f * v16;
291 const float v18 = xp * yp;
292 const float v19 = 2.0f * v7 * (-v14 * v18 + v16 * v18 * v5 + v6 * (p1 * xp + p2 * yp));
294 const float dxpp_dxp = v7 * (-v0 * v15 + v10 * (v8 + 3.0f * v9) + v5 * (v0 * v17 + v13));
295 const float dxpp_dyp = v19;
296 const float dypp_dxp = v19;
297 const float dypp_dyp = v7 * (-v1 * v15 + v10 * (3.0f * v8 + v9) + v5 * (v1 * v17 + v13));
299 d_dist_d_undist->v[0] = dxpp_dxp;
300 d_dist_d_undist->v[1] = dxpp_dyp;
301 d_dist_d_undist->v[2] = dypp_dxp;
302 d_dist_d_undist->v[3] = dypp_dyp;
308 const float x0 = (u - hg_dist->cx) / hg_dist->fx;
309 const float y0 = (v - hg_dist->cy) / hg_dist->fy;
320 for (
int i = 0; i < N; i++) {
324 rt8_distort(hg_dist, &undist, &fundist, &J);
325 struct xrt_vec2 residual = m_vec2_sub(fundist, dist);
330 m_mat2x2_invert(&J, &J_inverse);
334 m_mat2x2_transform_vec2(&J_inverse, &residual, &undist_sub);
336 undist = m_vec2_sub(undist, undist_sub);
337 if (m_vec2_len(residual) < SQRT_EPSILON) {
347 const struct t_camera_model_params *hg_dist,
const float u,
const float v,
float *out_x,
float *out_y,
float *out_z)
353 const float norm_inv = 1.0f / sqrt(xp * xp + yp * yp + 1.0f);
354 *out_x = xp * norm_inv;
355 *out_y = yp * norm_inv;
358 const float rp2 = xp * xp + yp * yp;
359 bool in_injective_area =
360 hg_dist->rt8.metric_radius == 0.0f ? true : rp2 <= hg_dist->rt8.metric_radius * hg_dist->rt8.metric_radius;
361 bool is_valid = in_injective_area;
375 *out_x = ((dist->fx * x / z) + dist->cx);
376 *out_y = ((dist->fy * y / z) + dist->cy);
378 bool is_valid = z >= SQRT_EPSILON;
389 const float mx = (x - dist->cx) / dist->fx;
390 const float my = (y - dist->cy) / dist->fy;
392 const float r2 = mx * mx + my * my;
394 const float norm = sqrtf(1.0f + r2);
396 const float norm_inv = 1.0f / norm;
398 *out_x = mx * norm_inv;
399 *out_y = my * norm_inv;
424 for (
size_t i = 0; i < dist_num; i++) {
427 distortion_tmp[i] = cc->distortion_parameters_as_array[i];
431 out_params->rt8.k1 = distortion_tmp[acc_idx++];
432 out_params->rt8.k2 = distortion_tmp[acc_idx++];
433 out_params->rt8.p1 = distortion_tmp[acc_idx++];
434 out_params->rt8.p2 = distortion_tmp[acc_idx++];
435 out_params->rt8.k3 = distortion_tmp[acc_idx++];
436 out_params->rt8.k4 = distortion_tmp[acc_idx++];
437 out_params->rt8.k5 = distortion_tmp[acc_idx++];
438 out_params->rt8.k6 = distortion_tmp[acc_idx++];
443 out_params->rt8.metric_radius = cc->wmr.rpmax;
445 out_params->rt8.metric_radius = 0;
480 out_params->fisheye.k1 = (float)cc->kb4.k1;
481 out_params->fisheye.k2 = (
float)cc->kb4.k2;
482 out_params->fisheye.k3 = (float)cc->kb4.k3;
483 out_params->fisheye.k4 = (
float)cc->kb4.k4;
490 U_LOG_E(
"t_camera_un_projections doesn't support camera model %s yet!",
502 const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y,
float *out_z)
504 switch (dist->model) {
506 return rt8_unproject(dist, x, y, out_x, out_y, out_z);
512 default: assert(
false);
return false;
523 const struct t_camera_model_params *dist,
const float x,
const float y,
float *out_x,
float *out_y,
float *out_z)
540 switch (dist->model) {
545 kb4_undistort(dist, x, y, out_x, out_y);
548 default: assert(
false);
565 switch (dist->model) {
567 return rt8_project(dist, x, y, z, out_x, out_y);
570 return kb4_project(dist, x, y, z, out_x, out_y);
573 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:301
#define U_LOG_W(...)
Log a message at U_LOGGING_WARN level, conditional on the global log level.
Definition: u_logging.h:298
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_RT8, also including metric_radius.
Definition: t_camera_models.h:47
Essential calibration data for a single camera, or single lens/sensor of a stereo camera.
Definition: t_tracking.h:223
double intrinsics[3][3]
Camera intrinsics matrix.
Definition: t_tracking.h:228
enum t_camera_distortion_model distortion_model
Distortion model that this camera uses.
Definition: t_tracking.h:241
Floating point calibration data for a single calibrated camera.
Definition: t_camera_models.h:58
A tightly packed 2x2 matrix of floats.
Definition: xrt_defines.h:513
A 2 element vector with single floats.
Definition: xrt_defines.h:250
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:583
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:558
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:501
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:537
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:306
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:459
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:522
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:166