28 #ifdef USE_NUMERIC_JACOBIANS
50 ASSERT_(
p.check_squares_length_X_meters > 0);
51 ASSERT_(
p.check_squares_length_Y_meters > 0);
52 const bool user_wants_use_robust =
p.use_robust_kernel;
54 if (images.size() < 1)
56 std::cout <<
"ERROR: No input images." << std::endl;
60 const unsigned CORNERS_COUNT =
p.check_size_x *
p.check_size_y;
70 vector<size_t> valid_image_pair_indices;
74 for (
size_t i = 0; i < images.size(); i++)
78 bool corners_found[2] = {
false,
false};
80 for (
int lr = 0; lr < 2; lr++)
91 imgSize[lr] = img_gray.
getSize();
105 if (imgSize[lr].
y != (
int)img_gray.
getHeight() ||
106 imgSize[lr].
x != (
int)img_gray.
getWidth())
108 std::cout <<
"ERROR: All the images in each left/right "
109 "channel must have the same size."
123 if (corners_found[lr] &&
125 corners_found[lr] =
false;
129 "%s img #%u: %s\n", lr == 0 ?
"LEFT" :
"RIGHT",
130 static_cast<unsigned int>(i),
131 corners_found[lr] ?
"DETECTED" :
"NOT DETECTED");
140 (*
p.callback)(cbPars,
p.callback_user_param);
143 if (corners_found[lr])
160 if (corners_found[0] && corners_found[1])
162 valid_image_pair_indices.push_back(i);
174 bool has_to_redraw_corners =
false;
176 const TPixelCoordf pt_l0 = images[i].left.detected_corners[0],
177 pt_l1 = images[i].left.detected_corners[1],
178 pt_r0 = images[i].right.detected_corners[0],
179 pt_r1 = images[i].right.detected_corners[1];
187 if (Al.x * Ar.x + Al.y * Ar.y < 0)
189 has_to_redraw_corners =
true;
192 images[i].right.detected_corners.begin(),
193 images[i].right.detected_corners.end());
196 if (has_to_redraw_corners)
199 images[i].right.img_original.colorImage(
200 images[i].right.img_checkboard);
201 images[i].right.img_checkboard.drawChessboardCorners(
202 images[i].right.detected_corners, check_size.
x,
210 std::cout << valid_image_pair_indices.size()
211 <<
" valid image pairs." << std::endl;
212 if (valid_image_pair_indices.empty())
214 std::cout <<
"ERROR: No valid images. Perhaps the checkerboard "
223 vector<TPoint3D> obj_points;
224 obj_points.reserve(CORNERS_COUNT);
225 for (
unsigned int y = 0;
y <
p.check_size_y;
y++)
226 for (
unsigned int x = 0;
x <
p.check_size_x;
x++)
227 obj_points.push_back(
229 p.check_squares_length_X_meters *
x,
230 p.check_squares_length_Y_meters *
y, 0));
241 const size_t N = valid_image_pair_indices.size();
242 const size_t nObs = 2 * N * CORNERS_COUNT;
247 const double tau = 0.3;
248 const double t1 = 1e-8;
249 const double t2 = 1e-8;
250 const double MAX_LAMBDA = 1e20;
255 lm_stat_t lm_stat(images, valid_image_pair_indices, obj_points);
279 size_t nUnknownsCamParams = 0;
282 std::vector<size_t> vars_to_optimize;
286 for (
int calibRound = 0; calibRound < 2; calibRound++)
291 << ((calibRound == 0) ?
"LM calibration round #0: WITHOUT "
292 "distortion ----------\n"
293 :
"LM calibration round #1: ALL "
294 "parameters --------------\n");
300 vars_to_optimize.clear();
301 vars_to_optimize.push_back(0);
302 vars_to_optimize.push_back(1);
303 vars_to_optimize.push_back(2);
304 vars_to_optimize.push_back(3);
307 if (
p.optimize_k1) vars_to_optimize.push_back(4);
308 if (
p.optimize_k2) vars_to_optimize.push_back(5);
309 if (
p.optimize_t1) vars_to_optimize.push_back(6);
310 if (
p.optimize_t2) vars_to_optimize.push_back(7);
311 if (
p.optimize_k3) vars_to_optimize.push_back(8);
314 nUnknownsCamParams = vars_to_optimize.size();
320 const size_t nUnknowns = N * 6 + 6 + 2 * nUnknownsCamParams;
325 lm_stat, res_jacob,
false ,
326 p.robust_kernel_param);
329 Eigen::VectorXd minus_g;
335 double lambda = tau * H.diagonal().array().maxCoeff();
336 bool done = (minus_g.array().abs().maxCoeff() < t1);
337 int numItersImproving = 0;
338 bool use_robust =
false;
342 while (iter <
p.maxIters && !done)
349 (*
p.callback)(cbPars,
p.callback_user_param);
353 Eigen::MatrixXd HH = H;
354 for (
size_t i = 0; i < nUnknowns; i++) HH(i, i) += lambda;
357 Eigen::LLT<Eigen::MatrixXd> llt(
358 HH.selfadjointView<Eigen::Lower>());
359 if (llt.info() != Eigen::Success)
363 done = (lambda > MAX_LAMBDA);
365 if (
p.verbose && !done)
366 cout <<
"LM iter#" << iter
367 <<
": Couldn't solve LLt, retrying with larger "
372 const Eigen::VectorXd
eps = llt.solve(minus_g);
374 const double eps_norm =
eps.norm();
375 if (eps_norm < t2 * (eps_norm + t2))
378 cout <<
"Termination criterion: eps_norm < "
380 << eps_norm <<
" < " << t2 * (eps_norm + t2)
395 new_lm_stat, new_res_jacob, use_robust,
396 p.robust_kernel_param);
403 if (numItersImproving++ > 5)
404 use_robust = user_wants_use_robust;
408 cout <<
"LM iter#" << iter
409 <<
": Avr.err(px):" << std::sqrt(err / nObs)
410 <<
"->" << std::sqrt(err_new / nObs)
411 <<
" lambda:" << lambda << endl;
414 lm_stat.
swap(new_lm_stat);
415 res_jacob.swap(new_res_jacob);
419 res_jacob, vars_to_optimize, minus_g, H);
422 done = (minus_g.array().abs().maxCoeff() < t1);
425 lambda = std::max(lambda, 1e-100);
434 cout <<
"LM iter#" << iter <<
": No update: err=" << err
435 <<
" -> err_new=" << err_new
436 <<
" retrying with larger lambda=" << lambda
439 done = (lambda > MAX_LAMBDA);
483 for (
size_t i = 0; i < valid_image_pair_indices.size(); i++)
494 const size_t base_idx_H_CPs = H.cols() - 2 * nUnknownsCamParams;
495 for (
size_t i = 0; i < nUnknownsCamParams; i++)
498 H(base_idx_H_CPs + i, base_idx_H_CPs + i);
500 H(base_idx_H_CPs + nUnknownsCamParams + i,
501 base_idx_H_CPs + nUnknownsCamParams + i);
505 for (
size_t i = 0; i < valid_image_pair_indices.size(); i++)
519 const size_t idx = valid_image_pair_indices[i];
552 catch (std::exception& e)
554 std::cout << e.what() << std::endl;
574 Eigen::Matrix<double, 2, 3>&
G)
576 const double pz_ = 1 /
p.z;
577 const double pz_2 = pz_ * pz_;
581 G(0, 2) = -
p.x * pz_2;
585 G(1, 2) = -
p.y * pz_2;
633 const Eigen::Matrix<double, 9, 1>&
c,
634 Eigen::Matrix<double, 2, 2>& Hb, Eigen::Matrix<double, 2, 9>& Hc)
636 const double x = nP.
x / nP.
z;
637 const double y = nP.
y / nP.
z;
639 const double r2 =
x *
x +
y *
y;
640 const double r = std::sqrt(r2);
641 const double r6 = r2 * r2 * r2;
644 const double fx =
c[0], fy =
c[1];
646 const double k1 =
c[4], k2 =
c[5], k3 =
c[6];
647 const double t1 =
c[7], t2 =
c[8];
651 fx * (k2 * r2 + k3 * r6 + 6 * t2 *
x + 2 * t1 *
y +
652 x * (2 * k1 *
x + 4 * k2 *
x *
r + 6 * k3 *
x * r2) + k1 *
r + 1);
653 Hb(0, 1) = fx * (2 * t1 *
x + 2 * t2 *
y +
654 x * (2 * k1 *
y + 4 * k2 *
y *
r + 6 * k3 *
y * r2));
656 Hb(1, 0) = fy * (2 * t1 *
x + 2 * t2 *
y +
657 y * (2 * k1 *
x + 4 * k2 *
x *
r + 6 * k3 *
x * r2));
659 fy * (k2 * r2 + k3 * r6 + 2 * t2 *
x + 6 * t1 *
y +
660 y * (2 * k1 *
y + 4 * k2 *
y *
r + 6 * k3 *
y * r2) + k1 *
r + 1);
663 Hc(0, 0) = t2 * (3 *
x *
x +
y *
y) +
x * (k2 * r2 + k3 * r6 + k1 *
r + 1) +
668 Hc(0, 4) = fx *
x *
r;
669 Hc(0, 5) = fx *
x * r2;
670 Hc(0, 6) = fx *
x * r6;
671 Hc(0, 7) = 2 * fx *
x *
y;
672 Hc(0, 8) = fx * (3 *
x *
x +
y *
y);
675 Hc(1, 1) = t1 * (
x *
x + 3 *
y *
y) +
y * (k2 * r2 + k3 * r6 + k1 *
r + 1) +
679 Hc(1, 4) = fy *
y *
r;
680 Hc(1, 5) = fy *
y * r2;
681 Hc(1, 6) = fy *
y * r6;
682 Hc(1, 7) = fy * (
x *
x + 3 *
y *
y);
683 Hc(1, 8) = 2 * fy *
x *
y;
688 Eigen::Matrix<double, 3, 6>& dpl_del)
692 dpl_del.block<3, 3>(0, 0).setIdentity();
698 Eigen::Matrix<double, 3, 6>& dp_deps)
702 const Eigen::Matrix<double, 1, 3> P(
p.x,
p.y,
p.z);
703 const Eigen::Matrix<double, 1, 3> dr1 =
705 const Eigen::Matrix<double, 1, 3> dr2 =
707 const Eigen::Matrix<double, 1, 3> dr3 =
710 const Eigen::Matrix<double, 1, 3>
v(
711 P.dot(dr1) + D.
x(), P.dot(dr2) + D.
y(), P.dot(dr3) + D.z());
713 Eigen::Matrix<double, 3, 6> H;
714 H.block<3, 3>(0, 0).setIdentity();
729 const double x = nP.
x / nP.
z;
730 const double y = nP.
y / nP.
z;
734 const double r4 =
square(r2);
735 const double r6 = r2 * r4;
738 const double B = 2 *
x *
y;
756 Eigen::VectorXd& minus_g, Eigen::MatrixXd& H)
758 const size_t N = res_jac.size();
759 const size_t nMaxUnknowns = N * 6 + 6 + 9 + 9;
762 Eigen::VectorXd minus_g_tot = Eigen::VectorXd::Zero(nMaxUnknowns);
763 Eigen::MatrixXd H_tot = Eigen::MatrixXd::Zero(nMaxUnknowns, nMaxUnknowns);
766 for (
size_t i = 0; i < N; i++)
768 const size_t nObs = res_jac[i].size();
769 for (
size_t j = 0; j < nObs; j++)
775 const Eigen::Matrix<double, 30, 30> Hij = rje.
J.transpose() * rje.
J;
776 const Eigen::Matrix<double, 30, 1> gij =
780 minus_g_tot.block<6, 1>(i * 6, 0) -= gij.block<6, 1>(0, 0);
781 minus_g_tot.block<6 + 9 + 9, 1>(N * 6, 0) -=
782 gij.block<6 + 9 + 9, 1>(6, 0);
784 H_tot.block<6, 6>(i * 6, i * 6) += Hij.block<6, 6>(0, 0);
786 H_tot.block<6 + 9 + 9, 6 + 9 + 9>(N * 6, N * 6) +=
787 Hij.block<6 + 9 + 9, 6 + 9 + 9>(6, 6);
788 H_tot.block<6, 6 + 9 + 9>(i * 6, N * 6) +=
789 Hij.block<6, 6 + 9 + 9>(0, 6);
790 H_tot.block<6 + 9 + 9, 6>(N * 6, i * 6) +=
791 Hij.block<6 + 9 + 9, 6>(6, 0);
799 const double cost_lr_angular = 1e10;
800 H_tot.block<3,3>(N*6+3,N*6+3) += Eigen::Matrix<double,3,3>::Identity() * cost_lr_angular;
806 const size_t N_Cs = var_indxs.size();
807 const size_t nUnknowns = N * 6 + 6 + 2 * N_Cs;
808 const size_t nUnkPoses = N * 6 + 6;
810 minus_g.setZero(nUnknowns);
811 H.setZero(nUnknowns, nUnknowns);
813 minus_g.block(0, 0, nUnkPoses, 1) = minus_g_tot.block(0, 0, nUnkPoses, 1);
814 H.block(0, 0, nUnkPoses, nUnkPoses) =
815 H_tot.block(0, 0, nUnkPoses, nUnkPoses);
818 for (
size_t i = 0; i < N_Cs; i++)
820 minus_g[nUnkPoses + i] = minus_g_tot[nUnkPoses + var_indxs[i]];
821 minus_g[nUnkPoses + N_Cs + i] =
822 minus_g_tot[nUnkPoses + 9 + var_indxs[i]];
825 for (
size_t k = 0; k < nUnkPoses; k++)
827 for (
size_t i = 0; i < N_Cs; i++)
829 H(nUnkPoses + i, k) = H(k, nUnkPoses + i) =
830 H_tot(k, nUnkPoses + var_indxs[i]);
831 H(nUnkPoses + i + N_Cs, k) = H(k, nUnkPoses + i + N_Cs) =
832 H_tot(k, nUnkPoses + 9 + var_indxs[i]);
836 for (
size_t i = 0; i < N_Cs; i++)
838 for (
size_t j = 0; j < N_Cs; j++)
840 H(nUnkPoses + i, nUnkPoses + j) =
841 H_tot(nUnkPoses + var_indxs[i], nUnkPoses + var_indxs[j]);
842 H(nUnkPoses + N_Cs + i, nUnkPoses + N_Cs + j) = H_tot(
843 nUnkPoses + 9 + var_indxs[i], nUnkPoses + 9 + var_indxs[j]);
851 M1.saveToTextFile(
"H1.txt");
852 g1.saveToTextFile(
"g1.txt");
856 M2.saveToTextFile(
"H2.txt");
857 g2.saveToTextFile(
"g2.txt");
869 const Eigen::VectorXd&
eps,
const std::vector<size_t>& var_indxs,
874 for (
size_t i = 0; i < N; i++)
881 const CPose3D incrPose = CPose3D::exp(incr);
892 const CPose3D incrPose = CPose3D::exp(incr);
900 const size_t idx = 6 * N + 6;
903 for (
size_t i = 0; i < nPC; i++)
911 #ifdef USE_NUMERIC_JACOBIANS
921 const Eigen::Matrix<double, 4, 1>& real_obs;
926 const Eigen::Matrix<double, 4, 1>& _real_obs)
928 obj_point(_obj_point),
930 right2left(_right2left),
936 void numeric_jacob_eval_function(
941 const CPose3D incrPose_l = CPose3D::exp(incr_l);
943 const CPose3D incrPose_rl = CPose3D::exp(incr_rl);
972 dat.obj_point, cam_params.
leftCamera, incrPose_l + dat.left_cam, px_l);
976 incrPose_rl + dat.right2left + incrPose_l + dat.left_cam, px_r);
978 const Eigen::Matrix<double, 4, 1> predicted_obs(
979 px_l.
x, px_l.
y, px_r.
x, px_r.
y);
989 const double x = X[0],
y = X[1];
991 const double r4 =
square(r2);
992 const double r6 = r2 * r4;
995 const double B = 2 *
x *
y;
1016 const CPose3D incrPose = CPose3D::exp(incr);
1019 for (
int i = 0; i < 3; i++) out[i] = D_p_out[i];
1022 struct TEvalData_A_eps_D_p
1028 void eval_dA_eps_D_p(
1033 const CPose3D incrPose = CPose3D::exp(incr);
1034 const CPose3D A_eps_D = dat.A + (incrPose + dat.D);
1037 for (
int i = 0; i < 3; i++) out[i] = pt[i];
1048 bool use_robust_kernel,
double kernel_param)
1050 double total_err = 0;
1078 for (
size_t k = 0; k < N; k++)
1081 const size_t nPts = lm_stat.
obj_points.size();
1082 res_jac[k].resize(nPts);
1084 for (
size_t i = 0; i < nPts; i++)
1088 lm_stat.
images[k_idx].left.detected_corners[i];
1090 lm_stat.
images[k_idx].right.detected_corners[i];
1091 const Eigen::Matrix<double, 4, 1> obs(
1092 px_obs_l.
x, px_obs_l.
y, px_obs_r.
x, px_obs_r.
y);
1106 Eigen::Matrix<double, 4, 1>(px_l.
x, px_l.
y, px_r.
x, px_r.
y);
1112 const double err_sqr_norm = rje.
residual.squaredNorm();
1113 if (use_robust_kernel)
1116 rk.param_sq = kernel_param;
1118 double kernel_1st_deriv, kernel_2nd_deriv;
1119 const double scaled_err =
1120 rk.eval(err_sqr_norm, kernel_1st_deriv, kernel_2nd_deriv);
1123 total_err += scaled_err;
1126 total_err += err_sqr_norm;
1133 #if !defined(USE_NUMERIC_JACOBIANS) || defined(COMPARE_NUMERIC_JACOBIANS)
1135 Eigen::Matrix<double, 2, 6> dhl_del, dhr_del, dhr_der;
1136 Eigen::Matrix<double, 2, 9> dhl_dcl, dhr_dcr;
1139 TPoint3D pt_wrt_left, pt_wrt_right;
1143 .composePoint(lm_stat.
obj_points[i], pt_wrt_right);
1146 Eigen::Matrix<double, 2, 2> dhl_dbl, dhr_dbr;
1161 x_incrs.setConstant(1e-6);
1163 Eigen::Matrix<double,2,2> num_dhl_dbl, num_dhr_dbr;
1171 cout <<
"num_dhl_dbl:\n" << num_dhl_dbl <<
"\ndiff dhl_dbl:\n" << dhl_dbl-num_dhl_dbl << endl << endl;
1172 cout <<
"num_dhr_dbr:\n" << num_dhr_dbr <<
"\ndiff dhr_dbr:\n" << dhr_dbr-num_dhr_dbr << endl << endl;
1177 Eigen::Matrix<double, 2, 3> dbl_dpl, dbr_dpr;
1185 x0[0]=pt_wrt_left.
x;
1186 x0[1]=pt_wrt_left.
y;
1187 x0[2]=pt_wrt_left.
z;
1190 x_incrs.setConstant(1e-8);
1192 Eigen::Matrix<double,2,3> num_dbl_dpl, num_dbr_dpr;
1196 x0[0]=pt_wrt_right.
x;
1197 x0[1]=pt_wrt_right.
y;
1198 x0[2]=pt_wrt_right.
z;
1201 cout <<
"num_dbl_dpl:\n" << num_dbl_dpl <<
"\ndbl_dpl:\n" << dbl_dpl << endl << endl;
1202 cout <<
"num_dbr_dpr:\n" << num_dbr_dpr <<
"\ndbr_dpr:\n" << dbr_dpr << endl << endl;
1210 Eigen::Matrix<double, 3, 6> dpl_del, dpr_del, dpr_der;
1225 x_incrs.setConstant(1e-8);
1227 Eigen::Matrix<double,3,6> num_dpl_del, num_dpr_der;
1231 cout <<
"num_dpl_del:\n" << num_dpl_del <<
"\ndiff dpl_del:\n" << dpl_del-num_dpl_del << endl << endl;
1232 cout <<
"num_dpr_der:\n" << num_dpr_der <<
"\ndiff dpr_der:\n" << dpr_der-num_dpr_der << endl << endl;
1244 x_incrs.setConstant(1e-8);
1246 TEvalData_A_eps_D_p dat;
1251 Eigen::Matrix<double,3,6> num_dpr_del;
1254 cout <<
"num_dpr_del:\n" << num_dpr_del <<
"\ndiff dpr_del:\n" << num_dpr_del-dpr_del << endl << endl;
1259 dhl_del = dhl_dbl * dbl_dpl * dpl_del;
1260 dhr_del = dhr_dbr * dbr_dpr * dpr_del;
1261 dhr_der = dhr_dbr * dbr_dpr * dpr_der;
1263 rje.
J.setZero(4, 30);
1264 rje.
J.block<2, 6>(0, 0) = dhl_del;
1265 rje.
J.block<2, 6>(2, 0) = dhr_del;
1266 rje.
J.block<2, 6>(2, 6) = dhr_der;
1267 rje.
J.block<2, 9>(0, 12) = dhl_dcl;
1268 rje.
J.block<2, 9>(2, 21) = dhr_dcr;
1270 #if defined(COMPARE_NUMERIC_JACOBIANS)
1271 const Eigen::Matrix<double, 4, 30> J_theor = rje.
J;
1276 #if defined(USE_NUMERIC_JACOBIANS) || defined(COMPARE_NUMERIC_JACOBIANS)
1285 const double x_incrs_val[30] = {
1286 1e-6, 1e-6, 1e-6, 1e-7, 1e-7, 1e-7,
1287 1e-6, 1e-6, 1e-6, 1e-7, 1e-7, 1e-7,
1288 1e-3, 1e-3, 1e-3, 1e-3, 1e-8, 1e-8, 1e-8, 1e-8, 1e-4,
1289 1e-3, 1e-3, 1e-3, 1e-3, 1e-8, 1e-8, 1e-8, 1e-8, 1e-4
1297 x0, &numeric_jacob_eval_function, x_incrs, dat, rje.
J);
1299 #if defined(COMPARE_NUMERIC_JACOBIANS)
1300 const Eigen::Matrix<double, 4, 30> J_num = rje.
J;
1305 #if defined(COMPARE_NUMERIC_JACOBIANS)
1309 f.open(
"dbg.txt", ios_base::out | ios_base::app);
1315 << J_num - J_theor << endl
1316 <<
"diff (ratio):\n"
1317 << (J_num - J_theor).cwiseQuotient(J_num) << endl
1331 check_squares_length_X_meters(0.02),
1332 check_squares_length_Y_meters(0.02),
1333 normalize_image(true),
1334 skipDrawDetectedImgs(false),
1342 use_robust_kernel(false),
1343 robust_kernel_param(10),
1345 callback_user_param(nullptr)
1350 : final_rmse(0), final_iters(0), final_number_good_image_pairs(0)
void jacob_deps_D_p_deps(const TPoint3D &p_D, Eigen::Matrix< double, 3, 6 > &dpl_del)
void jacob_db_dp(const TPoint3D &p, Eigen::Matrix< double, 2, 3 > &G)
void jacob_dA_eps_D_p_deps(const CPose3D &A, const CPose3D &D, const TPoint3D &p, Eigen::Matrix< double, 3, 6 > &dp_deps)
void project_point(const mrpt::math::TPoint3D &P, const mrpt::img::TCamera ¶ms, const CPose3D &cameraPose, mrpt::img::TPixelCoordf &px)
void jacob_dh_db_and_dh_dc(const TPoint3D &nP, const Eigen::Matrix< double, 9, 1 > &c, Eigen::Matrix< double, 2, 2 > &Hb, Eigen::Matrix< double, 2, 9 > &Hc)
A class for storing images as grayscale or RGB bitmaps.
bool drawChessboardCorners(std::vector< TPixelCoordf > &cornerCoords, unsigned int check_size_x, unsigned int check_size_y, unsigned int lines_width=1, unsigned int circles_radius=4)
Draw onto this image the detected corners of a chessboard.
bool isExternallyStored() const noexcept
See setExternalStorage().
size_t getHeight() const override
Returns the height of the image in pixels.
void getSize(TImageSize &s) const
Return the size of the image.
void colorImage(CImage &ret) const
Returns a RGB version of the grayscale image, or itself if it is already a RGB image.
size_t getWidth() const override
Returns the width of the image in pixels.
Structure to hold the parameters of a pinhole camera model.
double fx() const
Get the value of the focal length x-value (in pixels).
double fy() const
Get the value of the focal length y-value (in pixels).
double p1() const
Get the value of the p1 distortion parameter.
double cx() const
Get the value of the principal point x-coordinate (in pixels).
double k3() const
Get the value of the k3 distortion parameter.
double p2() const
Get the value of the p2 distortion parameter.
double k1() const
Get the value of the k1 distortion parameter.
double k2() const
Get the value of the k2 distortion parameter.
uint32_t ncols
Camera resolution.
double cy() const
Get the value of the principal point y-coordinate (in pixels).
Structure to hold the parameters of a pinhole stereo camera model.
TCamera leftCamera
Intrinsic and distortion parameters of the left and right cameras.
CArrayNumeric is an array for numeric types supporting several mathematical operations (actually,...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
void getRotationMatrix(mrpt::math::CMatrixDouble33 &ROT) const
Get the 3x3 rotation matrix.
void composePoint(double lx, double ly, double lz, double &gx, double &gy, double &gz, mrpt::math::CMatrixFixedNumeric< double, 3, 3 > *out_jacobian_df_dpoint=nullptr, mrpt::math::CMatrixFixedNumeric< double, 3, 6 > *out_jacobian_df_dpose=nullptr, mrpt::math::CMatrixFixedNumeric< double, 3, 6 > *out_jacobian_df_dse3=nullptr, bool use_small_rot_approx=false) const
An alternative, slightly more efficient way of doing with G and L being 3D points and P this 6D pose...
void composeFrom(const CPose3D &A, const CPose3D &B)
Makes "this = A (+) B"; this method is slightly more efficient than "this= A + B;" since it avoids th...
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,...
double x() const
Common members of all points & poses classes.
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
#define ASSERT_(f)
Defines an assertion mechanism.
GLdouble GLdouble GLdouble r
GLenum const GLfloat * params
bool findChessboardCorners(const mrpt::img::CImage &img, std::vector< mrpt::img::TPixelCoordf > &cornerCoords, unsigned int check_size_x, unsigned int check_size_y, bool normalize_image=true, bool useScaramuzzaMethod=false)
Look for the corners of a chessboard in the image using one of two different methods.
bool checkerBoardStereoCalibration(TCalibrationStereoImageList &images, const TStereoCalibParams ¶ms, TStereoCalibResults &out_results)
Optimize the calibration parameters of a stereo camera or a RGB+D (Kinect) camera.
std::vector< TImageStereoCalibData > TCalibrationStereoImageList
A list of images, used in checkerBoardStereoCalibration.
void skew_symmetric3_neg(const VECTOR &v, MATRIX &M)
Computes the negative version of a 3x3 skew symmetric matrix from a 3-vector or 3-array:
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
void pause(const std::string &msg=std::string("Press any key to continue...")) noexcept
Shows the message "Press any key to continue" (or other custom message) to the current standard outpu...
void projectPoints_with_distortion(const std::vector< mrpt::math::TPoint3D > &in_points_3D, const mrpt::poses::CPose3D &cameraPose, const mrpt::math::CMatrixDouble33 &intrinsicParams, const std::vector< double > &distortionParams, std::vector< mrpt::img::TPixelCoordf > &projectedPoints, bool accept_points_behind=false)
Project a set of 3D points into a camera at an arbitrary 6D pose using its calibration matrix and dis...
TPixelCoord TImageSize
A type for image sizes.
@ FAST_REF_OR_CONVERT_TO_GRAY
This base provides a set of functions for maths stuff.
void estimateJacobian(const VECTORLIKE &x, const std::function< void(const VECTORLIKE &x, const USERPARAM &y, VECTORLIKE3 &out)> &functor, const VECTORLIKE2 &increments, const USERPARAM &userParam, MATRIXLIKE &out_Jacobian)
Estimate the Jacobian of a multi-dimensional function around a point "x", using finite differences of...
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Classes for computer vision, detectors, features, etc.
double recompute_errors_and_Jacobians(const lm_stat_t &lm_stat, TResidualJacobianList &res_jac, bool use_robust_kernel, double kernel_param)
std::vector< mrpt::aligned_std_vector< TResidJacobElement > > TResidualJacobianList
void add_lm_increment(const Eigen::VectorXd &eps, const std::vector< size_t > &var_indxs, lm_stat_t &new_lm_stat)
void build_linear_system(const TResidualJacobianList &res_jac, const std::vector< size_t > &var_indxs, Eigen::VectorXd &minus_g, Eigen::MatrixXd &H)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
T square(const T x)
Inline function for the square of a number.
A pair (x,y) of pixel coordinates (integer resolution).
A pair (x,y) of pixel coordinates (subpixel resolution).
double x
X,Y,Z coordinates.
Data associated to each image in the calibration process mrpt::vision::checkerBoardCameraCalibration ...
mrpt::img::CImage img_checkboard
At output, this will contain the detected checkerboard overprinted to the image.
std::vector< mrpt::img::TPixelCoordf > detected_corners
At output, the detected corners (x,y) in pixel units.
mrpt::img::CImage img_original
This image will be automatically loaded from the file name passed to checkerBoardCameraCalibration.
mrpt::img::CImage img_rectified
At output, this will be the rectified image.
std::vector< mrpt::img::TPixelCoordf > projectedPoints_distorted
At output, only will have an empty vector if the checkerboard was not found in this image,...
mrpt::poses::CPose3D reconstructed_camera_pose
At output, the reconstructed pose of the camera.
Params of the optional callback provided by the user.
int calibRound
=-1:Processing images; =0: Initial calib without distortion, =1: Calib of all parameters
double current_rmse
Current root-mean square reprojection error (in pixels)
unsigned int nImgsProcessed
Info for calibRound==-1.
unsigned int nImgsToProcess
Data associated to each observation in the Lev-Marq.
Eigen::Matrix< double, 4, 1 > predicted_obs
[u_l v_l u_r v_r]: left/right camera pixels
Eigen::Matrix< double, 4, 30 > J
Jacobian.
Eigen::Matrix< double, 4, 1 > residual
= predicted_obs - observations
Input parameters for mrpt::vision::checkerBoardStereoCalibration.
Output results for mrpt::vision::checkerBoardStereoCalibration.
std::vector< bool > image_pair_was_used
true if a checkerboard was correctly detected in both left/right images.
Eigen::Array< double, 9, 1 > left_params_inv_variance
The inverse variance (information/precision) of each of the 9 left/right camera parameters [fx fy cx ...
size_t final_iters
Final number of optimization iterations executed.
mrpt::aligned_std_vector< mrpt::poses::CPose3D > left_cam_poses
Poses of the origin of coordinates of the pattern wrt the left camera (i.e.
mrpt::poses::CPose3D right2left_camera_pose
The pose of the left camera as seen from the right camera.
Eigen::Array< double, 9, 1 > right_params_inv_variance
double final_rmse
Final reprojection square Root Mean Square Error (in pixels).
size_t final_number_good_image_pairs
Number of image pairs in which valid checkerboards were correctly detected.
mrpt::img::TStereoCamera cam_params
Recovered parameters of the stereo camera.
const TCalibrationStereoImageList & images
mrpt::poses::CPose3D right2left_pose
mrpt::aligned_std_vector< mrpt::poses::CPose3D > left_cam_poses
mrpt::math::CArrayDouble< 9 > right_cam_params
const std::vector< size_t > & valid_image_pair_indices
mrpt::math::CArrayDouble< 9 > left_cam_params
const std::vector< mrpt::math::TPoint3D > & obj_points