#include "upnp.h"
#include <limits>
-void printMat(cv::Mat &mat)
-{
- cout << mat.rows << "x" << mat.cols << endl;
- for (int i = 0; i < mat.rows; ++i) {
- cout << "[";
- for (int j = 0; j < mat.cols; ++j) {
- cout << mat.at<double>(i,j) << ",";
- }
- cout << "];" << endl;
- }
-}
upnp::upnp(const cv::Mat& cameraMatrix, const cv::Mat& opoints, const cv::Mat& ipoints)
{
if (cameraMatrix.depth() == CV_32F)
- init_camera_parameters<float>(cameraMatrix);
+ init_camera_parameters<float>(cameraMatrix);
else
init_camera_parameters<double>(cameraMatrix);
upnp::~upnp()
{
- if (A1)
- delete[] A1;
- if (A2)
- delete[] A2;
+ if (A1)
+ delete[] A1;
+ if (A2)
+ delete[] A2;
}
double upnp::compute_pose(cv::Mat& R, cv::Mat& t)
{
- choose_control_points();
- compute_alphas();
+ choose_control_points();
+ compute_alphas();
- CvMat * M = cvCreateMat(2 * number_of_correspondences, 12, CV_64F);
+ CvMat * M = cvCreateMat(2 * number_of_correspondences, 12, CV_64F);
- for(int i = 0; i < number_of_correspondences; i++)
- {
- fill_M(M, 2 * i, &alphas[0] + 4 * i, us[2 * i], us[2 * i + 1]);
- }
+ for(int i = 0; i < number_of_correspondences; i++)
+ {
+ fill_M(M, 2 * i, &alphas[0] + 4 * i, us[2 * i], us[2 * i + 1]);
+ }
- double mtm[12 * 12], d[12], ut[12 * 12];
- CvMat MtM = cvMat(12, 12, CV_64F, mtm);
- CvMat D = cvMat(12, 1, CV_64F, d);
- CvMat Ut = cvMat(12, 12, CV_64F, ut);
+ double mtm[12 * 12], d[12], ut[12 * 12];
+ CvMat MtM = cvMat(12, 12, CV_64F, mtm);
+ CvMat D = cvMat(12, 1, CV_64F, d);
+ CvMat Ut = cvMat(12, 12, CV_64F, ut);
- cvMulTransposed(M, &MtM, 1);
- cvSVD(&MtM, &D, &Ut, 0, CV_SVD_MODIFY_A | CV_SVD_U_T);
- cvReleaseMat(&M);
+ cvMulTransposed(M, &MtM, 1);
+ cvSVD(&MtM, &D, &Ut, 0, CV_SVD_MODIFY_A | CV_SVD_U_T);
+ cvReleaseMat(&M);
- double l_6x12[6 * 12], rho[6];
- CvMat L_6x12 = cvMat(6, 12, CV_64F, l_6x12);
- CvMat Rho = cvMat(6, 1, CV_64F, rho);
+ double l_6x12[6 * 12], rho[6];
+ CvMat L_6x12 = cvMat(6, 12, CV_64F, l_6x12);
+ CvMat Rho = cvMat(6, 1, CV_64F, rho);
- compute_L_6x12(ut, l_6x12);
- compute_rho(rho);
+ compute_L_6x12(ut, l_6x12);
+ compute_rho(rho);
- double Betas[4][4], Efs[4][1], rep_errors[4];
- double Rs[4][3][3], ts[4][3];
+ double Betas[3][4], Efs[3][1], rep_errors[3];
+ double Rs[3][3][3], ts[3][3];
- find_betas_and_focal_approx_1(&Ut, &Rho, Betas[1], Efs[1]);
- gauss_newton(&L_6x12, &Rho, Betas[1], Efs[1]);
- rep_errors[1] = compute_R_and_t(ut, Betas[1], Efs[1], Rs[1], ts[1]);
+ find_betas_and_focal_approx_1(&Ut, &Rho, Betas[1], Efs[1]);
+ gauss_newton(&L_6x12, &Rho, Betas[1], Efs[1]);
+ rep_errors[1] = compute_R_and_t(ut, Betas[1], Rs[1], ts[1]);
- find_betas_and_focal_approx_2(&Ut, &Rho, Betas[2], Efs[2]);
- //gauss_newton(&L_6x12, &Rho, Betas[2], Efs[2]);
- //rep_errors[2] = compute_R_and_t(ut, Betas[2], Efs[2], Rs[2], ts[2]);
+ find_betas_and_focal_approx_2(&Ut, &Rho, Betas[2], Efs[2]);
+ gauss_newton(&L_6x12, &Rho, Betas[2], Efs[2]);
+ rep_errors[2] = compute_R_and_t(ut, Betas[2], Rs[2], ts[2]);
- int N = 1;
- //if (rep_errors[2] < rep_errors[1]) N = 2;
- //if (rep_errors[3] < rep_errors[N]) N = 3;
+ int N = 1;
+ if (rep_errors[2] < rep_errors[1]) N = 2;
- cv::Mat(3, 1, CV_64F, ts[N]).copyTo(t);
- cv::Mat(3, 3, CV_64F, Rs[N]).copyTo(R);
+ cv::Mat(3, 1, CV_64F, ts[N]).copyTo(t);
+ cv::Mat(3, 3, CV_64F, Rs[N]).copyTo(R);
+ fu = fv = Efs[N][0];
- return Efs[N][0];
+ return fu;
}
void upnp::copy_R_and_t(const double R_src[3][3], const double t_src[3],
- double R_dst[3][3], double t_dst[3])
+ double R_dst[3][3], double t_dst[3])
{
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++)
- R_dst[i][j] = R_src[i][j];
+ R_dst[i][j] = R_src[i][j];
t_dst[i] = t_src[i];
}
}
if (pcs[2] < 0.0) {
for(int i = 0; i < 4; i++)
for(int j = 0; j < 3; j++)
- ccs[i][j] = -ccs[i][j];
+ ccs[i][j] = -ccs[i][j];
for(int i = 0; i < number_of_correspondences; i++) {
pcs[3 * i ] = -pcs[3 * i];
}
}
-double upnp::compute_R_and_t(const double * ut, const double * betas, const double * efs,
- double R[3][3], double t[3])
+double upnp::compute_R_and_t(const double * ut, const double * betas,
+ double R[3][3], double t[3])
{
- compute_ccs(betas, efs, ut);
+ compute_ccs(betas, ut);
compute_pcs();
solve_for_sign();
void upnp::choose_control_points()
{
- for (int i = 0; i < 4; ++i)
- cws[i][0] = cws[i][1] = cws[i][2] = 0;
+ for (int i = 0; i < 4; ++i)
+ cws[i][0] = cws[i][1] = cws[i][2] = 0;
cws[0][0] = cws[1][1] = cws[2][2] = 1.;
}
void upnp::compute_alphas()
{
- cv::Mat CC = cv::Mat(4, 3, CV_64F, &cws);
- cv::Mat PC = cv::Mat(number_of_correspondences, 3, CV_64F, &pws.front());
- cv::Mat ALPHAS = cv::Mat(number_of_correspondences, 4, CV_64F, &alphas.front());
+ cv::Mat CC = cv::Mat(4, 3, CV_64F, &cws);
+ cv::Mat PC = cv::Mat(number_of_correspondences, 3, CV_64F, &pws[0]);
+ cv::Mat ALPHAS = cv::Mat(number_of_correspondences, 4, CV_64F, &alphas[0]);
- cv::Mat CC_ = CC.clone().t();
- cv::Mat PC_ = PC.clone().t();
+ cv::Mat CC_ = CC.clone().t();
+ cv::Mat PC_ = PC.clone().t();
- cv::Mat row14 = cv::Mat::ones(1, 4, CV_64F);
- cv::Mat row1n = cv::Mat::ones(1, number_of_correspondences, CV_64F);
+ cv::Mat row14 = cv::Mat::ones(1, 4, CV_64F);
+ cv::Mat row1n = cv::Mat::ones(1, number_of_correspondences, CV_64F);
- CC_.push_back(row14);
- PC_.push_back(row1n);
+ CC_.push_back(row14);
+ PC_.push_back(row1n);
- ALPHAS = cv::Mat( CC_.inv() * PC_ ).t();
+ ALPHAS = cv::Mat( CC_.inv() * PC_ ).t();
}
void upnp::fill_M(CvMat * M, const int row, const double * as, const double u, const double v)
}
}
-void upnp::compute_ccs(const double * betas, const double * f, const double * ut)
+void upnp::compute_ccs(const double * betas, const double * ut)
{
- for(int i = 0; i < 4; ++i)
- ccs[i][0] = ccs[i][1] = ccs[i][2] = 0.0f;
-
- int N = 4;
- for(int i = 0; i < N; ++i) {
- const double * v = ut + 12 * (9 + i);
- for(int j = 0; j < 4; ++j)
- for(int k = 0; k < 3; ++k)
- ccs[j][k] += betas[i] * v[3 * j + k]; // be careful with that
- }
-
- for (int i = 0; i < 4; ++i) ccs[i][2] *= f[0];
+ for(int i = 0; i < 4; ++i)
+ ccs[i][0] = ccs[i][1] = ccs[i][2] = 0.0f;
+
+ int N = 4;
+ for(int i = 0; i < N; ++i) {
+ const double * v = ut + 12 * (9 + i);
+ for(int j = 0; j < 4; ++j)
+ for(int k = 0; k < 3; ++k)
+ ccs[j][k] += betas[i] * v[3 * j + k];
+ }
+
+ for (int i = 0; i < 4; ++i) ccs[i][2] *= fu;
}
void upnp::compute_pcs(void)
void upnp::find_betas_and_focal_approx_1(const CvMat * Ut, const CvMat * Rho, double * betas, double * efs)
{
- cv::Mat Kmf1 = cv::Mat(12, 1, CV_64F, Ut->data.db + 11 * 12);
- cv::Mat dsq = cv::Mat(6, 1, CV_64F, Rho->data.db);
+ cv::Mat Kmf1 = cv::Mat(12, 1, CV_64F, Ut->data.db + 11 * 12);
+ cv::Mat dsq = cv::Mat(6, 1, CV_64F, Rho->data.db);
- cv::Mat D = compute_constraint_distance_2param_6eq_2unk_f_unk( Kmf1 );
- cv::Mat Dt = D.t();
+ cv::Mat D = compute_constraint_distance_2param_6eq_2unk_f_unk( Kmf1 );
+ cv::Mat Dt = D.t();
- cv::Mat A = Dt * D;
- cv::Mat b = Dt * dsq;
+ cv::Mat A = Dt * D;
+ cv::Mat b = Dt * dsq;
- cv::Mat x = cv::Mat(2, 1, CV_64F);
- cv::solve(A, b, x);
+ cv::Mat x = cv::Mat(2, 1, CV_64F);
+ cv::solve(A, b, x);
- betas[0] = std::sqrt( std::abs( x.at<double>(0) ) );
- betas[1] = betas[2] = betas[3] = 0;
+ betas[0] = std::sqrt( std::abs( x.at<double>(0) ) );
+ betas[1] = betas[2] = betas[3] = 0;
- efs[0] = std::sqrt( std::abs( x.at<double>(1) ) ) / betas[0];
+ efs[0] = std::sqrt( std::abs( x.at<double>(1) ) ) / betas[0];
}
void upnp::find_betas_and_focal_approx_2(const CvMat * Ut, const CvMat * Rho, double * betas, double * efs)
{
- cv::Mat Kmf1 = cv::Mat(12, 1, CV_64F, Ut->data.db + 10 * 12);
- cv::Mat Kmf2 = cv::Mat(12, 1, CV_64F, Ut->data.db + 11 * 12);
- cv::Mat dsq = cv::Mat(6, 1, CV_64F, Rho->data.db);
+ cv::Mat Kmf1 = cv::Mat(12, 1, CV_64F, Ut->data.db + 10 * 12);
+ cv::Mat Kmf2 = cv::Mat(12, 1, CV_64F, Ut->data.db + 11 * 12);
+ cv::Mat dsq = cv::Mat(6, 1, CV_64F, Rho->data.db);
+
+ cv::Mat D = compute_constraint_distance_3param_6eq_6unk_f_unk( Kmf1, Kmf2 );
+
+ cv::Mat A = D;
+ cv::Mat b = dsq;
- cv::Mat D = compute_constraint_distance_3param_6eq_6unk_f_unk( Kmf1, Kmf2 ); // OKAY
+ double x[6];
+ cv::Mat X = cv::Mat(6, 1, CV_64F, x);
- cv::Mat A = D;
- cv::Mat b = dsq;
+ cv::solve(A, b, X, cv::DECOMP_QR);
- cv::Mat x = cv::Mat(6, 1, CV_64F);
+ double solutions[18][3];
+ generate_all_possible_solutions_for_f_unk(x, solutions);
+
+ // find solution with minimum reprojection error
+ double min_error = std::numeric_limits<double>::max();
+ int min_sol = 0;
+ for (int i = 0; i < 18; ++i) {
+
+ betas[3] = solutions[i][0];
+ betas[2] = solutions[i][1];
+ betas[1] = betas[0] = 0;
+ fu = fv = solutions[i][2];
+
+ double Rs[3][3], ts[3];
+ double error_i = compute_R_and_t( Ut->data.db, betas, Rs, ts);
+
+ if( error_i < min_error)
+ {
+ min_error = error_i;
+ min_sol = i;
+ }
+}
- cv::solve(A, b, x, cv::DECOMP_QR);
+ betas[0] = solutions[min_sol][0];
+ betas[1] = solutions[min_sol][1];
+ betas[2] = betas[3] = 0;
- betas[0] = std::sqrt( std::abs( x.at<double>(0) ) );
- betas[1] = std::sqrt( std::abs( x.at<double>(2) ) * ( x.at<double>(2) < 0 ) ? -1 : ( x.at<double>(2) > 0 ) ? 1 : 0 );
- betas[2] = betas[3] = 0;
+ efs[0] = solutions[min_sol][2];
}
cv::Mat upnp::compute_constraint_distance_2param_6eq_2unk_f_unk(const cv::Mat& M1)
{
- cv::Mat P = cv::Mat(6, 2, CV_64F);
-
- double m[13];
- for (int i = 1; i < 13; ++i) m[i] = M1.at<double>(i-1);
-
- double t1 = std::pow( m[4], 2 );
- double t4 = std::pow( m[1], 2 );
- double t5 = std::pow( m[5], 2 );
- double t8 = std::pow( m[2], 2 );
- double t10 = std::pow( m[6], 2 );
- double t13 = std::pow( m[3], 2 );
- double t15 = std::pow( m[7], 2 );
- double t18 = std::pow( m[8], 2 );
- double t22 = std::pow( m[9], 2 );
- double t26 = std::pow( m[10], 2 );
- double t29 = std::pow( m[11], 2 );
- double t33 = std::pow( m[12], 2 );
-
- P.at<double>(0,0) = t1 - 2 * m[4] * m[1] + t4 + t5 - 2 * m[5] * m[2] + t8;
- P.at<double>(0,1) = t10 - 2 * m[6] * m[3] + t13;
- P.at<double>(1,0) = t15 - 2 * m[7] * m[1] + t4 + t18 - 2 * m[8] * m[2] + t8;
- P.at<double>(1,1) = t22 - 2 * m[9] * m[3] + t13;
- P.at<double>(2,0) = t26 - 2 * m[10] * m[1] + t4 + t29 - 2 * m[11] * m[2] + t8;
- P.at<double>(2,1) = t33 - 2 * m[12] * m[3] + t13;
- P.at<double>(3,0) = t15 - 2 * m[7] * m[4] + t1 + t18 - 2 * m[8] * m[5] + t5;
- P.at<double>(3,1) = t22 - 2 * m[9] * m[6] + t10;
- P.at<double>(4,0) = t26 - 2 * m[10] * m[4] + t1 + t29 - 2 * m[11] * m[5] + t5;
- P.at<double>(4,1) = t33 - 2 * m[12] * m[6] + t10;
- P.at<double>(5,0) = t26 - 2 * m[10] * m[7] + t15 + t29 - 2 * m[11] * m[8] + t18;
- P.at<double>(5,1) = t33 - 2 * m[12] * m[9] + t22;
-
- return P;
+ cv::Mat P = cv::Mat(6, 2, CV_64F);
+
+ double m[13];
+ for (int i = 1; i < 13; ++i) m[i] = M1.at<double>(i-1);
+
+ double t1 = std::pow( m[4], 2 );
+ double t4 = std::pow( m[1], 2 );
+ double t5 = std::pow( m[5], 2 );
+ double t8 = std::pow( m[2], 2 );
+ double t10 = std::pow( m[6], 2 );
+ double t13 = std::pow( m[3], 2 );
+ double t15 = std::pow( m[7], 2 );
+ double t18 = std::pow( m[8], 2 );
+ double t22 = std::pow( m[9], 2 );
+ double t26 = std::pow( m[10], 2 );
+ double t29 = std::pow( m[11], 2 );
+ double t33 = std::pow( m[12], 2 );
+
+ P.at<double>(0,0) = t1 - 2 * m[4] * m[1] + t4 + t5 - 2 * m[5] * m[2] + t8;
+ P.at<double>(0,1) = t10 - 2 * m[6] * m[3] + t13;
+ P.at<double>(1,0) = t15 - 2 * m[7] * m[1] + t4 + t18 - 2 * m[8] * m[2] + t8;
+ P.at<double>(1,1) = t22 - 2 * m[9] * m[3] + t13;
+ P.at<double>(2,0) = t26 - 2 * m[10] * m[1] + t4 + t29 - 2 * m[11] * m[2] + t8;
+ P.at<double>(2,1) = t33 - 2 * m[12] * m[3] + t13;
+ P.at<double>(3,0) = t15 - 2 * m[7] * m[4] + t1 + t18 - 2 * m[8] * m[5] + t5;
+ P.at<double>(3,1) = t22 - 2 * m[9] * m[6] + t10;
+ P.at<double>(4,0) = t26 - 2 * m[10] * m[4] + t1 + t29 - 2 * m[11] * m[5] + t5;
+ P.at<double>(4,1) = t33 - 2 * m[12] * m[6] + t10;
+ P.at<double>(5,0) = t26 - 2 * m[10] * m[7] + t15 + t29 - 2 * m[11] * m[8] + t18;
+ P.at<double>(5,1) = t33 - 2 * m[12] * m[9] + t22;
+
+ return P;
}
cv::Mat upnp::compute_constraint_distance_3param_6eq_6unk_f_unk(const cv::Mat& M1, const cv::Mat& M2)
{
- cv::Mat P = cv::Mat(6, 6, CV_64F);
-
- double m[3][13];
- for (int i = 1; i < 13; ++i)
- {
- m[1][i] = M1.at<double>(i-1);
- m[2][i] = M2.at<double>(i-1);
- }
-
- double t1 = std::pow( m[1][4], 2 );
- double t2 = std::pow( m[1][1], 2 );
- double t7 = std::pow( m[1][5], 2 );
- double t8 = std::pow( m[1][2], 2 );
- double t11 = m[1][1] * m[2][1];
- double t12 = m[1][5] * m[2][5];
- double t15 = m[1][2] * m[2][2];
- double t16 = m[1][4] * m[2][4];
- double t19 = std::pow( m[2][4], 2 );
- double t22 = std::pow( m[2][2], 2 );
- double t23 = std::pow( m[2][1], 2 );
- double t24 = std::pow( m[2][5], 2 );
- double t28 = std::pow( m[1][6], 2 );
- double t29 = std::pow( m[1][3], 2 );
- double t34 = std::pow( m[1][3], 2 );
- double t36 = m[1][6] * m[2][6];
- double t40 = std::pow( m[2][6], 2 );
- double t41 = std::pow( m[2][3], 2 );
- double t47 = std::pow( m[1][7], 2 );
- double t48 = std::pow( m[1][8], 2 );
- double t52 = m[1][7] * m[2][7];
- double t55 = m[1][8] * m[2][8];
- double t59 = std::pow( m[2][8], 2 );
- double t62 = std::pow( m[2][7], 2 );
- double t64 = std::pow( m[1][9], 2 );
- double t68 = m[1][9] * m[2][9];
- double t74 = std::pow( m[2][9], 2 );
- double t78 = std::pow( m[1][10], 2 );
- double t79 = std::pow( m[1][11], 2 );
- double t84 = m[1][10] * m[2][10];
- double t87 = m[1][11] * m[2][11];
- double t90 = std::pow( m[2][10], 2 );
- double t95 = std::pow( m[2][11], 2 );
- double t99 = std::pow( m[1][12], 2 );
- double t101 = m[1][12] * m[2][12];
- double t105 = std::pow( m[2][12], 2 );
-
- P.at<double>(0,0) = t1 + t2 - 2 * m[1][4] * m[1][1] - 2 * m[1][5] * m[1][2] + t7 + t8;
- P.at<double>(0,1) = -2 * m[2][4] * m[1][1] + 2 * t11 + 2 * t12 - 2 * m[1][4] * m[2][1] - 2 * m[2][5] * m[1][2] + 2 * t15 + 2 * t16 - 2 * m[1][5] * m[2][2];
- P.at<double>(0,2) = t19 - 2 * m[2][4] * m[2][1] + t22 + t23 + t24 - 2 * m[2][5] * m[2][2];
- P.at<double>(0,3) = t28 + t29 - 2 * m[1][6] * m[1][3];
- P.at<double>(0,4) = -2 * m[2][6] * m[1][3] + 2 * t34 - 2 * m[1][6] * m[2][3] + 2 * t36;
- P.at<double>(0,5) = -2 * m[2][6] * m[2][3] + t40 + t41;
-
- P.at<double>(1,0) = t8 - 2 * m[1][8] * m[1][2] - 2 * m[1][7] * m[1][1] + t47 + t48 + t2;
- P.at<double>(1,1) = 2 * t15 - 2 * m[1][8] * m[2][2] - 2 * m[2][8] * m[1][2] + 2 * t52 - 2 * m[1][7] * m[2][1] - 2 * m[2][7] * m[1][1] + 2 * t55 + 2 * t11;
- P.at<double>(1,2) = -2 * m[2][8] * m[2][2] + t22 + t23 + t59 - 2 * m[2][7] * m[2][1] + t62;
- P.at<double>(1,3) = t29 + t64 - 2 * m[1][9] * m[1][3];
- P.at<double>(1,4) = 2 * t34 + 2 * t68 - 2 * m[2][9] * m[1][3] - 2 * m[1][9] * m[2][3];
- P.at<double>(1,5) = -2 * m[2][9] * m[2][3] + t74 + t41;
-
- P.at<double>(2,0) = -2 * m[1][11] * m[1][2] + t2 + t8 + t78 + t79 - 2 * m[1][10] * m[1][1];
- P.at<double>(2,1) = 2 * t15 - 2 * m[1][11] * m[2][2] + 2 * t84 - 2 * m[1][10] * m[2][1] - 2 * m[2][10] * m[1][1] + 2 * t87 - 2 * m[2][11] * m[1][2]+ 2 * t11;
- P.at<double>(2,2) = t90 + t22 - 2 * m[2][10] * m[2][1] + t23 - 2 * m[2][11] * m[2][2] + t95;
- P.at<double>(2,3) = -2 * m[1][12] * m[1][3] + t99 + t29;
- P.at<double>(2,4) = 2 * t34 + 2 * t101 - 2 * m[2][12] * m[1][3] - 2 * m[1][12] * m[2][3];
- P.at<double>(2,5) = t41 + t105 - 2 * m[2][12] * m[2][3];
-
- P.at<double>(3,0) = t48 + t1 - 2 * m[1][8] * m[1][5] + t7 - 2 * m[1][7] * m[1][4] + t47;
- P.at<double>(3,1) = 2 * t16 - 2 * m[1][7] * m[2][4] + 2 * t55 + 2 * t52 - 2 * m[1][8] * m[2][5] - 2 * m[2][8] * m[1][5] - 2 * m[2][7] * m[1][4] + 2 * t12;
- P.at<double>(3,2) = t24 - 2 * m[2][8] * m[2][5] + t19 - 2 * m[2][7] * m[2][4] + t62 + t59;
- P.at<double>(3,3) = -2 * m[1][9] * m[1][6] + t64 + t28;
- P.at<double>(3,4) = 2 * t68 + 2 * t36 - 2 * m[2][9] * m[1][6] - 2 * m[1][9] * m[2][6];
- P.at<double>(3,5) = t40 + t74 - 2 * m[2][9] * m[2][6];
-
- P.at<double>(4,0) = t1 - 2 * m[1][10] * m[1][4] + t7 + t78 + t79 - 2 * m[1][11] * m[1][5];
- P.at<double>(4,1) = 2 * t84 - 2 * m[1][11] * m[2][5] - 2 * m[1][10] * m[2][4] + 2 * t16 - 2 * m[2][11] * m[1][5] + 2 * t87 - 2 * m[2][10] * m[1][4] + 2 * t12;
- P.at<double>(4,2) = t19 + t24 - 2 * m[2][10] * m[2][4] - 2 * m[2][11] * m[2][5] + t95 + t90;
- P.at<double>(4,3) = t28 - 2 * m[1][12] * m[1][6] + t99;
- P.at<double>(4,4) = 2 * t101 + 2 * t36 - 2 * m[2][12] * m[1][6] - 2 * m[1][12] * m[2][6];
- P.at<double>(4,5) = t105 - 2 * m[2][12] * m[2][6] + t40;
-
- P.at<double>(5,0) = -2 * m[1][10] * m[1][7] + t47 + t48 + t78 + t79 - 2 * m[1][11] * m[1][8];
- P.at<double>(5,1) = 2 * t84 + 2 * t87 - 2 * m[2][11] * m[1][8] - 2 * m[1][10] * m[2][7] - 2 * m[2][10] * m[1][7] + 2 * t55 + 2 * t52 - 2 * m[1][11] * m[2][8];
- P.at<double>(5,2) = -2 * m[2][10] * m[2][7] - 2 * m[2][11] * m[2][8] + t62 + t59 + t90 + t95;
- P.at<double>(5,3) = t64 - 2 * m[1][12] * m[1][9] + t99;
- P.at<double>(5,4) = 2 * t68 - 2 * m[2][12] * m[1][9] - 2 * m[1][12] * m[2][9] + 2 * t101;
- P.at<double>(5,5) = t105 - 2 * m[2][12] * m[2][9] + t74;
-
- return P;
+ cv::Mat P = cv::Mat(6, 6, CV_64F);
+
+ double m[3][13];
+ for (int i = 1; i < 13; ++i)
+ {
+ m[1][i] = M1.at<double>(i-1);
+ m[2][i] = M2.at<double>(i-1);
+ }
+
+ double t1 = std::pow( m[1][4], 2 );
+ double t2 = std::pow( m[1][1], 2 );
+ double t7 = std::pow( m[1][5], 2 );
+ double t8 = std::pow( m[1][2], 2 );
+ double t11 = m[1][1] * m[2][1];
+ double t12 = m[1][5] * m[2][5];
+ double t15 = m[1][2] * m[2][2];
+ double t16 = m[1][4] * m[2][4];
+ double t19 = std::pow( m[2][4], 2 );
+ double t22 = std::pow( m[2][2], 2 );
+ double t23 = std::pow( m[2][1], 2 );
+ double t24 = std::pow( m[2][5], 2 );
+ double t28 = std::pow( m[1][6], 2 );
+ double t29 = std::pow( m[1][3], 2 );
+ double t34 = std::pow( m[1][3], 2 );
+ double t36 = m[1][6] * m[2][6];
+ double t40 = std::pow( m[2][6], 2 );
+ double t41 = std::pow( m[2][3], 2 );
+ double t47 = std::pow( m[1][7], 2 );
+ double t48 = std::pow( m[1][8], 2 );
+ double t52 = m[1][7] * m[2][7];
+ double t55 = m[1][8] * m[2][8];
+ double t59 = std::pow( m[2][8], 2 );
+ double t62 = std::pow( m[2][7], 2 );
+ double t64 = std::pow( m[1][9], 2 );
+ double t68 = m[1][9] * m[2][9];
+ double t74 = std::pow( m[2][9], 2 );
+ double t78 = std::pow( m[1][10], 2 );
+ double t79 = std::pow( m[1][11], 2 );
+ double t84 = m[1][10] * m[2][10];
+ double t87 = m[1][11] * m[2][11];
+ double t90 = std::pow( m[2][10], 2 );
+ double t95 = std::pow( m[2][11], 2 );
+ double t99 = std::pow( m[1][12], 2 );
+ double t101 = m[1][12] * m[2][12];
+ double t105 = std::pow( m[2][12], 2 );
+
+ P.at<double>(0,0) = t1 + t2 - 2 * m[1][4] * m[1][1] - 2 * m[1][5] * m[1][2] + t7 + t8;
+ P.at<double>(0,1) = -2 * m[2][4] * m[1][1] + 2 * t11 + 2 * t12 - 2 * m[1][4] * m[2][1] - 2 * m[2][5] * m[1][2] + 2 * t15 + 2 * t16 - 2 * m[1][5] * m[2][2];
+ P.at<double>(0,2) = t19 - 2 * m[2][4] * m[2][1] + t22 + t23 + t24 - 2 * m[2][5] * m[2][2];
+ P.at<double>(0,3) = t28 + t29 - 2 * m[1][6] * m[1][3];
+ P.at<double>(0,4) = -2 * m[2][6] * m[1][3] + 2 * t34 - 2 * m[1][6] * m[2][3] + 2 * t36;
+ P.at<double>(0,5) = -2 * m[2][6] * m[2][3] + t40 + t41;
+
+ P.at<double>(1,0) = t8 - 2 * m[1][8] * m[1][2] - 2 * m[1][7] * m[1][1] + t47 + t48 + t2;
+ P.at<double>(1,1) = 2 * t15 - 2 * m[1][8] * m[2][2] - 2 * m[2][8] * m[1][2] + 2 * t52 - 2 * m[1][7] * m[2][1] - 2 * m[2][7] * m[1][1] + 2 * t55 + 2 * t11;
+ P.at<double>(1,2) = -2 * m[2][8] * m[2][2] + t22 + t23 + t59 - 2 * m[2][7] * m[2][1] + t62;
+ P.at<double>(1,3) = t29 + t64 - 2 * m[1][9] * m[1][3];
+ P.at<double>(1,4) = 2 * t34 + 2 * t68 - 2 * m[2][9] * m[1][3] - 2 * m[1][9] * m[2][3];
+ P.at<double>(1,5) = -2 * m[2][9] * m[2][3] + t74 + t41;
+
+ P.at<double>(2,0) = -2 * m[1][11] * m[1][2] + t2 + t8 + t78 + t79 - 2 * m[1][10] * m[1][1];
+ P.at<double>(2,1) = 2 * t15 - 2 * m[1][11] * m[2][2] + 2 * t84 - 2 * m[1][10] * m[2][1] - 2 * m[2][10] * m[1][1] + 2 * t87 - 2 * m[2][11] * m[1][2]+ 2 * t11;
+ P.at<double>(2,2) = t90 + t22 - 2 * m[2][10] * m[2][1] + t23 - 2 * m[2][11] * m[2][2] + t95;
+ P.at<double>(2,3) = -2 * m[1][12] * m[1][3] + t99 + t29;
+ P.at<double>(2,4) = 2 * t34 + 2 * t101 - 2 * m[2][12] * m[1][3] - 2 * m[1][12] * m[2][3];
+ P.at<double>(2,5) = t41 + t105 - 2 * m[2][12] * m[2][3];
+
+ P.at<double>(3,0) = t48 + t1 - 2 * m[1][8] * m[1][5] + t7 - 2 * m[1][7] * m[1][4] + t47;
+ P.at<double>(3,1) = 2 * t16 - 2 * m[1][7] * m[2][4] + 2 * t55 + 2 * t52 - 2 * m[1][8] * m[2][5] - 2 * m[2][8] * m[1][5] - 2 * m[2][7] * m[1][4] + 2 * t12;
+ P.at<double>(3,2) = t24 - 2 * m[2][8] * m[2][5] + t19 - 2 * m[2][7] * m[2][4] + t62 + t59;
+ P.at<double>(3,3) = -2 * m[1][9] * m[1][6] + t64 + t28;
+ P.at<double>(3,4) = 2 * t68 + 2 * t36 - 2 * m[2][9] * m[1][6] - 2 * m[1][9] * m[2][6];
+ P.at<double>(3,5) = t40 + t74 - 2 * m[2][9] * m[2][6];
+
+ P.at<double>(4,0) = t1 - 2 * m[1][10] * m[1][4] + t7 + t78 + t79 - 2 * m[1][11] * m[1][5];
+ P.at<double>(4,1) = 2 * t84 - 2 * m[1][11] * m[2][5] - 2 * m[1][10] * m[2][4] + 2 * t16 - 2 * m[2][11] * m[1][5] + 2 * t87 - 2 * m[2][10] * m[1][4] + 2 * t12;
+ P.at<double>(4,2) = t19 + t24 - 2 * m[2][10] * m[2][4] - 2 * m[2][11] * m[2][5] + t95 + t90;
+ P.at<double>(4,3) = t28 - 2 * m[1][12] * m[1][6] + t99;
+ P.at<double>(4,4) = 2 * t101 + 2 * t36 - 2 * m[2][12] * m[1][6] - 2 * m[1][12] * m[2][6];
+ P.at<double>(4,5) = t105 - 2 * m[2][12] * m[2][6] + t40;
+
+ P.at<double>(5,0) = -2 * m[1][10] * m[1][7] + t47 + t48 + t78 + t79 - 2 * m[1][11] * m[1][8];
+ P.at<double>(5,1) = 2 * t84 + 2 * t87 - 2 * m[2][11] * m[1][8] - 2 * m[1][10] * m[2][7] - 2 * m[2][10] * m[1][7] + 2 * t55 + 2 * t52 - 2 * m[1][11] * m[2][8];
+ P.at<double>(5,2) = -2 * m[2][10] * m[2][7] - 2 * m[2][11] * m[2][8] + t62 + t59 + t90 + t95;
+ P.at<double>(5,3) = t64 - 2 * m[1][12] * m[1][9] + t99;
+ P.at<double>(5,4) = 2 * t68 - 2 * m[2][12] * m[1][9] - 2 * m[1][12] * m[2][9] + 2 * t101;
+ P.at<double>(5,5) = t105 - 2 * m[2][12] * m[2][9] + t74;
+
+ return P;
+}
+
+void upnp::generate_all_possible_solutions_for_f_unk(const double betas[5], double solutions[18][3])
+{
+ int matrix_to_resolve[18][9] = {
+ { 2, 0, 0, 1, 1, 0, 2, 0, 2 }, { 2, 0, 0, 1, 1, 0, 1, 1, 2 },
+ { 2, 0, 0, 1, 1, 0, 0, 2, 2 }, { 2, 0, 0, 0, 2, 0, 2, 0, 2 },
+ { 2, 0, 0, 0, 2, 0, 1, 1, 2 }, { 2, 0, 0, 0, 2, 0, 0, 2, 2 },
+ { 2, 0, 0, 2, 0, 2, 1, 1, 2 }, { 2, 0, 0, 2, 0, 2, 0, 2, 2 },
+ { 2, 0, 0, 1, 1, 2, 0, 2, 2 }, { 1, 1, 0, 0, 2, 0, 2, 0, 2 },
+ { 1, 1, 0, 0, 2, 0, 1, 1, 2 }, { 1, 1, 0, 2, 0, 2, 0, 2, 2 },
+ { 1, 1, 0, 2, 0, 2, 1, 1, 2 }, { 1, 1, 0, 2, 0, 2, 0, 2, 2 },
+ { 1, 1, 0, 1, 1, 2, 0, 2, 2 }, { 0, 2, 0, 2, 0, 2, 1, 1, 2 },
+ { 0, 2, 0, 2, 0, 2, 0, 2, 2 }, { 0, 2, 0, 1, 1, 2, 0, 2, 2 }
+ };
+
+ int combination[18][3] = {
+ { 1, 2, 4 }, { 1, 2, 5 }, { 1, 2, 6 }, { 1, 3, 4 },
+ { 1, 3, 5 }, { 1, 3, 6 }, { 1, 4, 5 }, { 1, 4, 6 },
+ { 1, 5, 6 }, { 2, 3, 4 }, { 2, 3, 5 }, { 2, 3, 6 },
+ { 2, 4, 5 }, { 2, 4, 6 }, { 2, 5, 6 }, { 3, 4, 5 },
+ { 3, 4, 6 }, { 3, 5, 6 }
+ };
+
+ for (int i = 0; i < 18; ++i) {
+ double matrix[9], independent_term[3];
+ cv::Mat M = cv::Mat(3, 3, CV_64F, matrix);
+ cv::Mat I = cv::Mat(3, 1, CV_64F, independent_term);
+ cv::Mat S = cv::Mat(1, 3, CV_64F);
+
+ for (int j = 0; j < 9; ++j) matrix[j] = (double)matrix_to_resolve[i][j];
+
+ independent_term[0] = std::log( std::abs( betas[ combination[i][0]-1 ] ) );
+ independent_term[1] = std::log( std::abs( betas[ combination[i][1]-1 ] ) );
+ independent_term[2] = std::log( std::abs( betas[ combination[i][2]-1 ] ) );
+
+ cv::exp( cv::Mat(M.inv() * I), S);
+
+ solutions[i][0] = S.at<double>(0);
+ solutions[i][1] = S.at<double>(1) * sign( betas[1] );
+ solutions[i][2] = std::abs( S.at<double>(2) );
+ }
}
void upnp::gauss_newton(const CvMat * L_6x12, const CvMat * Rho, double betas[4], double * f)
{
- const int iterations_number = 100;
+ const int iterations_number = 50;
double a[6*4], b[6], x[4];
CvMat A = cvMat(6, 4, CV_64F, a);
compute_A_and_b_gauss_newton(L_6x12->data.db, Rho->data.db, betas, &A, &B, f[0]);
qr_solve(&A, &B, &X);
for(int i = 0; i < 3; i++)
- betas[i] += x[i];
+ betas[i] += x[i];
f[0] += x[3];
}
if (f[0] < 0) f[0] = -f[0];
+ fu = fv = f[0];
+
}
void upnp::compute_A_and_b_gauss_newton(const double * l_6x12, const double * rho,
- const double betas[4], CvMat * A, CvMat * b, double const f)
+ const double betas[4], CvMat * A, CvMat * b, double const f)
{
for(int i = 0; i < 6; i++) {
const double * rowL = l_6x12 + i * 12;
double * rowA = A->data.db + i * 4;
- rowA[0] = 2 * rowL[0] * betas[0] + rowL[1] * betas[1] + rowL[2] * betas[2] + f*f * ( 2 * rowL[6]*betas[0] + rowL[7]*betas[1] + rowL[8]*betas[2] );
- rowA[1] = rowL[1] * betas[0] + 2 * rowL[3] * betas[1] + rowL[4] * betas[2] + f*f * ( rowL[7]*betas[0] + 2 * rowL[9]*betas[1] + rowL[10]*betas[2] );
- rowA[2] = rowL[2] * betas[0] + rowL[4] * betas[1] + 2 * rowL[5] * betas[2] + f*f * ( rowL[8]*betas[0] + rowL[10]*betas[1] + 2 * rowL[11]*betas[2] );
+ rowA[0] = 2 * rowL[0] * betas[0] + rowL[1] * betas[1] + rowL[2] * betas[2] + f*f * ( 2 * rowL[6]*betas[0] + rowL[7]*betas[1] + rowL[8]*betas[2] );
+ rowA[1] = rowL[1] * betas[0] + 2 * rowL[3] * betas[1] + rowL[4] * betas[2] + f*f * ( rowL[7]*betas[0] + 2 * rowL[9]*betas[1] + rowL[10]*betas[2] );
+ rowA[2] = rowL[2] * betas[0] + rowL[4] * betas[1] + 2 * rowL[5] * betas[2] + f*f * ( rowL[8]*betas[0] + rowL[10]*betas[1] + 2 * rowL[11]*betas[2] );
rowA[3] = 2*f * ( rowL[6]*betas[0]*betas[0] + rowL[7]*betas[0]*betas[1] + rowL[8]*betas[0]*betas[2] + rowL[9]*betas[1]*betas[1] + rowL[10]*betas[1]*betas[2] + rowL[11]*betas[2]*betas[2] ) ;
cvmSet(b, i, 0, rho[i] -
- (
- rowL[0] * betas[0] * betas[0] +
- rowL[1] * betas[0] * betas[1] +
- rowL[2] * betas[0] * betas[2] +
- rowL[3] * betas[1] * betas[1] +
- rowL[4] * betas[1] * betas[2] +
- rowL[5] * betas[2] * betas[2] +
- f*f * rowL[6] * betas[0] * betas[0] +
- f*f * rowL[7] * betas[0] * betas[1] +
- f*f * rowL[8] * betas[0] * betas[2] +
- f*f * rowL[9] * betas[1] * betas[1] +
- f*f * rowL[10] * betas[1] * betas[2] +
- f*f * rowL[11] * betas[2] * betas[2]
- ));
+ (
+ rowL[0] * betas[0] * betas[0] +
+ rowL[1] * betas[0] * betas[1] +
+ rowL[2] * betas[0] * betas[2] +
+ rowL[3] * betas[1] * betas[1] +
+ rowL[4] * betas[1] * betas[2] +
+ rowL[5] * betas[2] * betas[2] +
+ f*f * rowL[6] * betas[0] * betas[0] +
+ f*f * rowL[7] * betas[0] * betas[1] +
+ f*f * rowL[8] * betas[0] * betas[2] +
+ f*f * rowL[9] * betas[1] * betas[1] +
+ f*f * rowL[10] * betas[1] * betas[2] +
+ f*f * rowL[11] * betas[2] * betas[2]
+ ));
}
}
b++;
if (b > 3) {
- a++;
- b = a + 1;
+ a++;
+ b = a + 1;
}
}
}
double * row = l_6x12 + 12 * i;
row[0] = dotXY(dv[0][i], dv[0][i]);
- row[1] = 2.0f * dotXY(dv[0][i], dv[1][i]);
- row[2] = dotXY(dv[1][i], dv[1][i]);
- row[3] = 2.0f * dotXY(dv[0][i], dv[2][i]);
- row[4] = 2.0f * dotXY(dv[1][i], dv[2][i]);
- row[5] = dotXY(dv[2][i], dv[2][i]);
-
- row[6] = dotZ(dv[0][i], dv[0][i]);
- row[7] = 2.0f * dotZ(dv[0][i], dv[1][i]);
- row[8] = 2.0f * dotZ(dv[0][i], dv[2][i]);
- row[9] = dotZ(dv[1][i], dv[1][i]);
- row[10] = 2.0f * dotZ(dv[1][i], dv[2][i]);
- row[11] = dotZ(dv[2][i], dv[2][i]);
+ row[1] = 2.0f * dotXY(dv[0][i], dv[1][i]);
+ row[2] = dotXY(dv[1][i], dv[1][i]);
+ row[3] = 2.0f * dotXY(dv[0][i], dv[2][i]);
+ row[4] = 2.0f * dotXY(dv[1][i], dv[2][i]);
+ row[5] = dotXY(dv[2][i], dv[2][i]);
+
+ row[6] = dotZ(dv[0][i], dv[0][i]);
+ row[7] = 2.0f * dotZ(dv[0][i], dv[1][i]);
+ row[8] = 2.0f * dotZ(dv[0][i], dv[2][i]);
+ row[9] = dotZ(dv[1][i], dv[1][i]);
+ row[10] = 2.0f * dotZ(dv[1][i], dv[2][i]);
+ row[11] = dotZ(dv[2][i], dv[2][i]);
}
}
void upnp::compute_rho(double * rho)
{
- rho[0] = dist2(cws[0], cws[1]);
- rho[1] = dist2(cws[0], cws[2]);
- rho[2] = dist2(cws[0], cws[3]);
- rho[3] = dist2(cws[1], cws[2]);
- rho[4] = dist2(cws[1], cws[3]);
- rho[5] = dist2(cws[2], cws[3]);
+ rho[0] = dist2(cws[0], cws[1]);
+ rho[1] = dist2(cws[0], cws[2]);
+ rho[2] = dist2(cws[0], cws[3]);
+ rho[3] = dist2(cws[1], cws[2]);
+ rho[4] = dist2(cws[1], cws[3]);
+ rho[5] = dist2(cws[2], cws[3]);
}
double upnp::dist2(const double * p1, const double * p2)
return v1[2] * v2[2];
}
+double upnp::sign(const double v)
+{
+ return ( v < 0 ) ? -1. : ( v > 0 ) ? 1. : 0.;
+}
+
void upnp::qr_solve(CvMat * A, CvMat * b, CvMat * X)
{
const int nr = A->rows;
}
else
{
- double * ppAik2 = ppAkk, sum2 = 0.0, inv_eta = 1. / eta;
- for(int i = k; i < nr; i++)
- {
- *ppAik2 *= inv_eta;
- sum2 += *ppAik2 * *ppAik2;
- ppAik2 += nc;
- }
- double sigma = sqrt(sum2);
- if (*ppAkk < 0)
- sigma = -sigma;
- *ppAkk += sigma;
- A1[k] = sigma * *ppAkk;
- A2[k] = -eta * sigma;
- for(int j = k + 1; j < nc; j++)
- {
- double * ppAik = ppAkk, sum = 0;
- for(int i = k; i < nr; i++)
- {
- sum += *ppAik * ppAik[j - k];
- ppAik += nc;
- }
- double tau = sum / A1[k];
- ppAik = ppAkk;
- for(int i = k; i < nr; i++)
- {
- ppAik[j - k] -= tau * *ppAik;
- ppAik += nc;
- }
- }
+ double * ppAik2 = ppAkk, sum2 = 0.0, inv_eta = 1. / eta;
+ for(int i = k; i < nr; i++)
+ {
+ *ppAik2 *= inv_eta;
+ sum2 += *ppAik2 * *ppAik2;
+ ppAik2 += nc;
+ }
+ double sigma = sqrt(sum2);
+ if (*ppAkk < 0)
+ sigma = -sigma;
+ *ppAkk += sigma;
+ A1[k] = sigma * *ppAkk;
+ A2[k] = -eta * sigma;
+ for(int j = k + 1; j < nc; j++)
+ {
+ double * ppAik = ppAkk, sum = 0;
+ for(int i = k; i < nr; i++)
+ {
+ sum += *ppAik * ppAik[j - k];
+ ppAik += nc;
+ }
+ double tau = sum / A1[k];
+ ppAik = ppAkk;
+ for(int i = k; i < nr; i++)
+ {
+ ppAik[j - k] -= tau * *ppAik;
+ ppAik += nc;
+ }
+ }
}
ppAkk += nc + 1;
}
double * ppAij = ppAjj, tau = 0;
for(int i = j; i < nr; i++)
{
- tau += *ppAij * pb[i];
- ppAij += nc;
+ tau += *ppAij * pb[i];
+ ppAij += nc;
}
tau /= A1[j];
ppAij = ppAjj;
for(int i = j; i < nr; i++)
{
- pb[i] -= tau * *ppAij;
- ppAij += nc;
+ pb[i] -= tau * *ppAij;
+ ppAij += nc;
}
ppAjj += nc + 1;
}
for(int j = i + 1; j < nc; j++)
{
- sum += *ppAij * pX[j];
- ppAij++;
+ sum += *ppAij * pX[j];
+ ppAij++;
}
pX[i] = (pb[i] - sum) / A2[i];
}