206 const Mat3X& X_world,
209 CHECK(x_camera.cols() == X_world.cols());
210 CHECK(x_camera.cols() > 3);
212 int num_points = x_camera.cols();
216 Mat3X x_camera_unit(3, num_points);
217 x_camera_unit.block(0, 0, 2, num_points) = x_camera;
218 x_camera_unit.row(2).setOnes();
221 int num_m_rows = num_points * (num_points - 1) / 2;
222 int num_tt_variables = num_points * (num_points + 1) / 2;
223 int num_m_columns = num_tt_variables + 1;
224 Mat M(num_m_columns, num_m_columns);
226 Matu ij_index(num_tt_variables, 2);
231 for (
int i = 0; i < num_points; ++i) {
232 for (
int j = i + 1; j < num_points; ++j) {
233 M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j));
234 M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i));
235 M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j));
236 Vec3 Xdiff = X_world.col(i) - X_world.col(j);
237 double center_to_point_distance = Xdiff.norm();
238 M(row, num_m_columns - 1) =
239 -center_to_point_distance * center_to_point_distance;
240 ij_index(row, 0) = i;
241 ij_index(row, 1) = j;
244 ij_index(i + num_m_rows, 0) = i;
245 ij_index(i + num_m_rows, 1) = i;
248 int num_lambda = num_points + 1;
249 Mat V =
M.jacobiSvd(Eigen::ComputeFullV)
251 .block(0, num_m_rows, num_m_columns, num_lambda);
259 num_points * (num_points * (num_points - 1) / 2 - num_points + 1);
260 int num_k_columns = num_lambda * (num_lambda + 1) / 2;
261 Mat K(num_k_rows, num_k_columns);
266 int counter_k_row = 0;
267 for (
int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
268 for (
int idx2 = 0; idx2 < num_m_rows; ++idx2) {
269 unsigned int i = ij_index(idx1, 0);
270 unsigned int j = ij_index(idx2, 0);
271 unsigned int k = ij_index(idx2, 1);
273 if (i != j && i != k) {
277 K.row(counter_k_row) =
279 V.row(idx3).transpose() *
V.row(idx4),
289 for (
int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
290 for (
int idx2 = idx1 + 1; idx2 < num_tt_variables; ++idx2) {
291 unsigned int i = ij_index(idx1, 0);
292 unsigned int j = ij_index(idx2, 0);
293 unsigned int k = ij_index(idx2, 1);
298 K.row(counter_k_row) =
300 V.row(idx3).transpose() *
V.row(idx4),
306 Vec L_sq =
K.jacobiSvd(Eigen::ComputeFullV).matrixV().col(num_k_columns - 1);
310 double max_L_sq_value =
fabs(L_sq(
IJToIndex(0, 0, num_lambda)));
311 int max_L_sq_index = 1;
312 for (
int i = 1; i < num_lambda; ++i) {
313 double abs_sq_value =
fabs(L_sq(
IJToIndex(i, i, num_lambda)));
314 if (max_L_sq_value < abs_sq_value) {
315 max_L_sq_value = abs_sq_value;
321 L_sq *
Sign(L_sq(
IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda)));
325 sqrt(L_sq(
IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda)));
327 for (
int i = 0; i < num_lambda; ++i) {
328 if (i != max_L_sq_index) {
329 L(i) = L_sq(
IJToIndex(max_L_sq_index, i, num_lambda)) /
L(max_L_sq_index);
334 L =
L / (
V.row(num_m_columns - 1).dot(
L));
340 for (
int c_point = num_m_rows; c_point < num_tt_variables; ++c_point) {
341 d(c_point - num_m_rows) =
sqrt(
X(c_point));
345 Mat X_cam(3, num_points);
346 for (
int c_point = 0; c_point < num_points; ++c_point) {
347 X_cam.col(c_point) = d(c_point) * x_camera_unit.col(c_point);
439 const Mat3X& X_world,
442 CHECK(x_camera.cols() == X_world.cols());
443 CHECK(x_camera.cols() > 3);
444 size_t num_points = X_world.cols();
447 Mat34 X_control_points;
452 Mat4X alphas(4, num_points);
456 Mat M(2 * num_points, 12);
457 Eigen::Matrix<double, 2, 12> sub_M;
458 for (
size_t c = 0; c < num_points; c++) {
459 double a0 = alphas(0, c);
460 double a1 = alphas(1, c);
461 double a2 = alphas(2, c);
462 double a3 = alphas(3, c);
463 double ui = x_camera(0, c);
464 double vi = x_camera(1, c);
466 M.block(2*c, 0, 2, 12) << a0, 0,
479 Eigen::JacobiSVD<Mat> MtMsvd(
M.transpose() *
M, Eigen::ComputeFullU);
480 Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose();
483 Eigen::Matrix<double, 6, 3> dv1;
484 Eigen::Matrix<double, 6, 3> dv2;
485 Eigen::Matrix<double, 6, 3> dv3;
486 Eigen::Matrix<double, 6, 3> dv4;
488 dv1.row(0) = u2.block(11, 0, 1, 3) - u2.block(11, 3, 1, 3);
489 dv1.row(1) = u2.block(11, 0, 1, 3) - u2.block(11, 6, 1, 3);
490 dv1.row(2) = u2.block(11, 0, 1, 3) - u2.block(11, 9, 1, 3);
491 dv1.row(3) = u2.block(11, 3, 1, 3) - u2.block(11, 6, 1, 3);
492 dv1.row(4) = u2.block(11, 3, 1, 3) - u2.block(11, 9, 1, 3);
493 dv1.row(5) = u2.block(11, 6, 1, 3) - u2.block(11, 9, 1, 3);
494 dv2.row(0) = u2.block(10, 0, 1, 3) - u2.block(10, 3, 1, 3);
495 dv2.row(1) = u2.block(10, 0, 1, 3) - u2.block(10, 6, 1, 3);
496 dv2.row(2) = u2.block(10, 0, 1, 3) - u2.block(10, 9, 1, 3);
497 dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3);
498 dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3);
499 dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3);
500 dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3);
501 dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3);
502 dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3);
503 dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3);
504 dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3);
505 dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3);
506 dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3);
507 dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3);
508 dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3);
509 dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3);
510 dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3);
511 dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3);
513 Eigen::Matrix<double, 6, 10>
L;
514 for (
size_t r = 0; r < 6; r++) {
516 L.row(r) << dv1.row(r).dot(dv1.row(r)),
517 2.0 * dv1.row(r).dot(dv2.row(r)),
518 dv2.row(r).dot(dv2.row(r)),
519 2.0 * dv1.row(r).dot(dv3.row(r)),
520 2.0 * dv2.row(r).dot(dv3.row(r)),
521 dv3.row(r).dot(dv3.row(r)),
522 2.0 * dv1.row(r).dot(dv4.row(r)),
523 2.0 * dv2.row(r).dot(dv4.row(r)),
524 2.0 * dv3.row(r).dot(dv4.row(r)),
525 dv4.row(r).dot(dv4.row(r));
530 rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(),
531 (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(),
532 (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(),
533 (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(),
534 (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(),
535 (X_control_points.col(2) - X_control_points.col(3)).squaredNorm();
556 double kSuccessThreshold = std::numeric_limits<double>::max();
561 Vec4 betas = Vec4::Zero();
562 Eigen::Matrix<double, 6, 4> l_6x4;
563 for (
size_t r = 0; r < 6; r++) {
564 l_6x4.row(r) <<
L(r, 0),
L(r, 1),
L(r, 3),
L(r, 6);
566 Eigen::JacobiSVD<Mat> svd_of_l4(l_6x4,
567 Eigen::ComputeFullU | Eigen::ComputeFullV);
568 Vec4 b4 = svd_of_l4.solve(rho);
569 if ((l_6x4 * b4).isApprox(rho, kSuccessThreshold)) {
573 b4(0) = std::sqrt(b4(0));
574 betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0);
579 LOG(ERROR) <<
"First approximation of beta not good enough.";
581 rmse(0) = std::numeric_limits<double>::max();
588 Eigen::Matrix<double, 6, 3> l_6x3;
589 l_6x3 =
L.block(0, 0, 6, 3);
590 Eigen::JacobiSVD<Mat> svdOfL3(l_6x3,
591 Eigen::ComputeFullU | Eigen::ComputeFullV);
592 Vec3 b3 = svdOfL3.solve(rho);
593 VLOG(2) <<
" rho = " << rho;
594 VLOG(2) <<
" l_6x3 * b3 = " << l_6x3 * b3;
595 if ((l_6x3 * b3).isApprox(rho, kSuccessThreshold)) {
597 betas(0) = std::sqrt(-b3(0));
598 betas(1) = (b3(2) < 0) ? std::sqrt(-b3(2)) : 0;
600 betas(0) = std::sqrt(b3(0));
601 betas(1) = (b3(2) > 0) ? std::sqrt(b3(2)) : 0;
604 betas(0) = -betas(0);
612 LOG(ERROR) <<
"Second approximation of beta not good enough.";
614 rmse(1) = std::numeric_limits<double>::max();
621 Eigen::Matrix<double, 6, 5> l_6x5;
622 l_6x5 =
L.block(0, 0, 6, 5);
623 Eigen::JacobiSVD<Mat> svdOfL5(l_6x5,
624 Eigen::ComputeFullU | Eigen::ComputeFullV);
625 Vec5 b5 = svdOfL5.solve(rho);
626 if ((l_6x5 * b5).isApprox(rho, kSuccessThreshold)) {
628 betas(0) = std::sqrt(-b5(0));
630 betas(1) = std::sqrt(-b5(2));
635 betas(0) = std::sqrt(b5(0));
637 betas(1) = std::sqrt(b5(2));
643 betas(0) = -betas(0);
645 betas(2) = b5(3) / betas(0);
651 LOG(ERROR) <<
"Third approximation of beta not good enough.";
653 rmse(2) = std::numeric_limits<double>::max();
657 VLOG(2) <<
"RMSE for solution 0: " << rmse(0);
658 VLOG(2) <<
"RMSE for solution 1: " << rmse(1);
659 VLOG(2) <<
"RMSE for solution 2: " << rmse(2);
661 if (rmse(1) < rmse(0)) {
664 if (rmse(2) < rmse(n)) {
667 if (rmse(n) == std::numeric_limits<double>::max()) {
668 LOG(ERROR) <<
"All three possibilities failed. Reporting failure.";
672 VLOG(1) <<
"RMSE for best solution #" << n <<
": " << rmse(n);