1 #include <cstring> 2 #include <cmath> 3 #include <iostream> 4 5 #include "polynom_solver.h" 6 #include "p3p.h" 7 8 void p3p::init_inverse_parameters() 9 { 10 inv_fx = 1. / fx; 11 inv_fy = 1. / fy; 12 cx_fx = cx / fx; 13 cy_fy = cy / fy; 14 } 15 16 p3p::p3p(cv::Mat cameraMatrix) 17 { 18 if (cameraMatrix.depth() == CV_32F) 19 init_camera_parameters<float>(cameraMatrix); 20 else 21 init_camera_parameters<double>(cameraMatrix); 22 init_inverse_parameters(); 23 } 24 25 p3p::p3p(double _fx, double _fy, double _cx, double _cy) 26 { 27 fx = _fx; 28 fy = _fy; 29 cx = _cx; 30 cy = _cy; 31 init_inverse_parameters(); 32 } 33 34 bool p3p::solve(cv::Mat& R, cv::Mat& tvec, const cv::Mat& opoints, const cv::Mat& ipoints) 35 { 36 double rotation_matrix[3][3], translation[3]; 37 std::vector<double> points; 38 if (opoints.depth() == ipoints.depth()) 39 { 40 if (opoints.depth() == CV_32F) 41 extract_points<cv::Point3f,cv::Point2f>(opoints, ipoints, points); 42 else 43 extract_points<cv::Point3d,cv::Point2d>(opoints, ipoints, points); 44 } 45 else if (opoints.depth() == CV_32F) 46 extract_points<cv::Point3f,cv::Point2d>(opoints, ipoints, points); 47 else 48 extract_points<cv::Point3d,cv::Point2f>(opoints, ipoints, points); 49 50 bool result = solve(rotation_matrix, translation, points[0], points[1], points[2], points[3], points[4], points[5], 51 points[6], points[7], points[8], points[9], points[10], points[11], points[12], points[13], points[14], 52 points[15], points[16], points[17], points[18], points[19]); 53 cv::Mat(3, 1, CV_64F, translation).copyTo(tvec); 54 cv::Mat(3, 3, CV_64F, rotation_matrix).copyTo(R); 55 return result; 56 } 57 58 bool p3p::solve(double R[3][3], double t[3], 59 double mu0, double mv0, double X0, double Y0, double Z0, 60 double mu1, double mv1, double X1, double Y1, double Z1, 61 double mu2, double mv2, double X2, double Y2, double Z2, 62 double mu3, double mv3, double X3, double Y3, double Z3) 63 { 64 double Rs[4][3][3], ts[4][3]; 65 66 int n = solve(Rs, ts, mu0, mv0, X0, Y0, Z0, mu1, mv1, X1, Y1, Z1, mu2, mv2, X2, Y2, Z2); 67 68 if (n == 0) 69 return false; 70 71 int ns = 0; 72 double min_reproj = 0; 73 for(int i = 0; i < n; i++) { 74 double X3p = Rs[i][0][0] * X3 + Rs[i][0][1] * Y3 + Rs[i][0][2] * Z3 + ts[i][0]; 75 double Y3p = Rs[i][1][0] * X3 + Rs[i][1][1] * Y3 + Rs[i][1][2] * Z3 + ts[i][1]; 76 double Z3p = Rs[i][2][0] * X3 + Rs[i][2][1] * Y3 + Rs[i][2][2] * Z3 + ts[i][2]; 77 double mu3p = cx + fx * X3p / Z3p; 78 double mv3p = cy + fy * Y3p / Z3p; 79 double reproj = (mu3p - mu3) * (mu3p - mu3) + (mv3p - mv3) * (mv3p - mv3); 80 if (i == 0 || min_reproj > reproj) { 81 ns = i; 82 min_reproj = reproj; 83 } 84 } 85 86 for(int i = 0; i < 3; i++) { 87 for(int j = 0; j < 3; j++) 88 R[i][j] = Rs[ns][i][j]; 89 t[i] = ts[ns][i]; 90 } 91 92 return true; 93 } 94 95 int p3p::solve(double R[4][3][3], double t[4][3], 96 double mu0, double mv0, double X0, double Y0, double Z0, 97 double mu1, double mv1, double X1, double Y1, double Z1, 98 double mu2, double mv2, double X2, double Y2, double Z2) 99 { 100 double mk0, mk1, mk2; 101 double norm; 102 103 mu0 = inv_fx * mu0 - cx_fx; 104 mv0 = inv_fy * mv0 - cy_fy; 105 norm = sqrt(mu0 * mu0 + mv0 * mv0 + 1); 106 mk0 = 1. / norm; mu0 *= mk0; mv0 *= mk0; 107 108 mu1 = inv_fx * mu1 - cx_fx; 109 mv1 = inv_fy * mv1 - cy_fy; 110 norm = sqrt(mu1 * mu1 + mv1 * mv1 + 1); 111 mk1 = 1. / norm; mu1 *= mk1; mv1 *= mk1; 112 113 mu2 = inv_fx * mu2 - cx_fx; 114 mv2 = inv_fy * mv2 - cy_fy; 115 norm = sqrt(mu2 * mu2 + mv2 * mv2 + 1); 116 mk2 = 1. / norm; mu2 *= mk2; mv2 *= mk2; 117 118 double distances[3]; 119 distances[0] = sqrt( (X1 - X2) * (X1 - X2) + (Y1 - Y2) * (Y1 - Y2) + (Z1 - Z2) * (Z1 - Z2) ); 120 distances[1] = sqrt( (X0 - X2) * (X0 - X2) + (Y0 - Y2) * (Y0 - Y2) + (Z0 - Z2) * (Z0 - Z2) ); 121 distances[2] = sqrt( (X0 - X1) * (X0 - X1) + (Y0 - Y1) * (Y0 - Y1) + (Z0 - Z1) * (Z0 - Z1) ); 122 123 // Calculate angles 124 double cosines[3]; 125 cosines[0] = mu1 * mu2 + mv1 * mv2 + mk1 * mk2; 126 cosines[1] = mu0 * mu2 + mv0 * mv2 + mk0 * mk2; 127 cosines[2] = mu0 * mu1 + mv0 * mv1 + mk0 * mk1; 128 129 double lengths[4][3]; 130 int n = solve_for_lengths(lengths, distances, cosines); 131 132 int nb_solutions = 0; 133 for(int i = 0; i < n; i++) { 134 double M_orig[3][3]; 135 136 M_orig[0][0] = lengths[i][0] * mu0; 137 M_orig[0][1] = lengths[i][0] * mv0; 138 M_orig[0][2] = lengths[i][0] * mk0; 139 140 M_orig[1][0] = lengths[i][1] * mu1; 141 M_orig[1][1] = lengths[i][1] * mv1; 142 M_orig[1][2] = lengths[i][1] * mk1; 143 144 M_orig[2][0] = lengths[i][2] * mu2; 145 M_orig[2][1] = lengths[i][2] * mv2; 146 M_orig[2][2] = lengths[i][2] * mk2; 147 148 if (!align(M_orig, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, R[nb_solutions], t[nb_solutions])) 149 continue; 150 151 nb_solutions++; 152 } 153 154 return nb_solutions; 155 } 156 157 /// Given 3D distances between three points and cosines of 3 angles at the apex, calculates 158 /// the lentghs of the line segments connecting projection center (P) and the three 3D points (A, B, C). 159 /// Returned distances are for |PA|, |PB|, |PC| respectively. 160 /// Only the solution to the main branch. 161 /// Reference : X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang; "Complete Solution Classification for the Perspective-Three-Point Problem" 162 /// IEEE Trans. on PAMI, vol. 25, No. 8, August 2003 163 /// \param lengths3D Lengths of line segments up to four solutions. 164 /// \param dist3D Distance between 3D points in pairs |BC|, |AC|, |AB|. 165 /// \param cosines Cosine of the angles /_BPC, /_APC, /_APB. 166 /// \returns Number of solutions. 167 /// WARNING: NOT ALL THE DEGENERATE CASES ARE IMPLEMENTED 168 169 int p3p::solve_for_lengths(double lengths[4][3], double distances[3], double cosines[3]) 170 { 171 double p = cosines[0] * 2; 172 double q = cosines[1] * 2; 173 double r = cosines[2] * 2; 174 175 double inv_d22 = 1. / (distances[2] * distances[2]); 176 double a = inv_d22 * (distances[0] * distances[0]); 177 double b = inv_d22 * (distances[1] * distances[1]); 178 179 double a2 = a * a, b2 = b * b, p2 = p * p, q2 = q * q, r2 = r * r; 180 double pr = p * r, pqr = q * pr; 181 182 // Check reality condition (the four points should not be coplanar) 183 if (p2 + q2 + r2 - pqr - 1 == 0) 184 return 0; 185 186 double ab = a * b, a_2 = 2*a; 187 188 double A = -2 * b + b2 + a2 + 1 + ab*(2 - r2) - a_2; 189 190 // Check reality condition 191 if (A == 0) return 0; 192 193 double a_4 = 4*a; 194 195 double B = q*(-2*(ab + a2 + 1 - b) + r2*ab + a_4) + pr*(b - b2 + ab); 196 double C = q2 + b2*(r2 + p2 - 2) - b*(p2 + pqr) - ab*(r2 + pqr) + (a2 - a_2)*(2 + q2) + 2; 197 double D = pr*(ab-b2+b) + q*((p2-2)*b + 2 * (ab - a2) + a_4 - 2); 198 double E = 1 + 2*(b - a - ab) + b2 - b*p2 + a2; 199 200 double temp = (p2*(a-1+b) + r2*(a-1-b) + pqr - a*pqr); 201 double b0 = b * temp * temp; 202 // Check reality condition 203 if (b0 == 0) 204 return 0; 205 206 double real_roots[4]; 207 int n = solve_deg4(A, B, C, D, E, real_roots[0], real_roots[1], real_roots[2], real_roots[3]); 208 209 if (n == 0) 210 return 0; 211 212 int nb_solutions = 0; 213 double r3 = r2*r, pr2 = p*r2, r3q = r3 * q; 214 double inv_b0 = 1. / b0; 215 216 // For each solution of x 217 for(int i = 0; i < n; i++) { 218 double x = real_roots[i]; 219 220 // Check reality condition 221 if (x <= 0) 222 continue; 223 224 double x2 = x*x; 225 226 double b1 = 227 ((1-a-b)*x2 + (q*a-q)*x + 1 - a + b) * 228 (((r3*(a2 + ab*(2 - r2) - a_2 + b2 - 2*b + 1)) * x + 229 230 (r3q*(2*(b-a2) + a_4 + ab*(r2 - 2) - 2) + pr2*(1 + a2 + 2*(ab-a-b) + r2*(b - b2) + b2))) * x2 + 231 232 (r3*(q2*(1-2*a+a2) + r2*(b2-ab) - a_4 + 2*(a2 - b2) + 2) + r*p2*(b2 + 2*(ab - b - a) + 1 + a2) + pr2*q*(a_4 + 2*(b - ab - a2) - 2 - r2*b)) * x + 233 234 2*r3q*(a_2 - b - a2 + ab - 1) + pr2*(q2 - a_4 + 2*(a2 - b2) + r2*b + q2*(a2 - a_2) + 2) + 235 p2*(p*(2*(ab - a - b) + a2 + b2 + 1) + 2*q*r*(b + a_2 - a2 - ab - 1))); 236 237 // Check reality condition 238 if (b1 <= 0) 239 continue; 240 241 double y = inv_b0 * b1; 242 double v = x2 + y*y - x*y*r; 243 244 if (v <= 0) 245 continue; 246 247 double Z = distances[2] / sqrt(v); 248 double X = x * Z; 249 double Y = y * Z; 250 251 lengths[nb_solutions][0] = X; 252 lengths[nb_solutions][1] = Y; 253 lengths[nb_solutions][2] = Z; 254 255 nb_solutions++; 256 } 257 258 return nb_solutions; 259 } 260 261 bool p3p::align(double M_end[3][3], 262 double X0, double Y0, double Z0, 263 double X1, double Y1, double Z1, 264 double X2, double Y2, double Z2, 265 double R[3][3], double T[3]) 266 { 267 // Centroids: 268 double C_start[3], C_end[3]; 269 for(int i = 0; i < 3; i++) C_end[i] = (M_end[0][i] + M_end[1][i] + M_end[2][i]) / 3; 270 C_start[0] = (X0 + X1 + X2) / 3; 271 C_start[1] = (Y0 + Y1 + Y2) / 3; 272 C_start[2] = (Z0 + Z1 + Z2) / 3; 273 274 // Covariance matrix s: 275 double s[3 * 3]; 276 for(int j = 0; j < 3; j++) { 277 s[0 * 3 + j] = (X0 * M_end[0][j] + X1 * M_end[1][j] + X2 * M_end[2][j]) / 3 - C_end[j] * C_start[0]; 278 s[1 * 3 + j] = (Y0 * M_end[0][j] + Y1 * M_end[1][j] + Y2 * M_end[2][j]) / 3 - C_end[j] * C_start[1]; 279 s[2 * 3 + j] = (Z0 * M_end[0][j] + Z1 * M_end[1][j] + Z2 * M_end[2][j]) / 3 - C_end[j] * C_start[2]; 280 } 281 282 double Qs[16], evs[4], U[16]; 283 284 Qs[0 * 4 + 0] = s[0 * 3 + 0] + s[1 * 3 + 1] + s[2 * 3 + 2]; 285 Qs[1 * 4 + 1] = s[0 * 3 + 0] - s[1 * 3 + 1] - s[2 * 3 + 2]; 286 Qs[2 * 4 + 2] = s[1 * 3 + 1] - s[2 * 3 + 2] - s[0 * 3 + 0]; 287 Qs[3 * 4 + 3] = s[2 * 3 + 2] - s[0 * 3 + 0] - s[1 * 3 + 1]; 288 289 Qs[1 * 4 + 0] = Qs[0 * 4 + 1] = s[1 * 3 + 2] - s[2 * 3 + 1]; 290 Qs[2 * 4 + 0] = Qs[0 * 4 + 2] = s[2 * 3 + 0] - s[0 * 3 + 2]; 291 Qs[3 * 4 + 0] = Qs[0 * 4 + 3] = s[0 * 3 + 1] - s[1 * 3 + 0]; 292 Qs[2 * 4 + 1] = Qs[1 * 4 + 2] = s[1 * 3 + 0] + s[0 * 3 + 1]; 293 Qs[3 * 4 + 1] = Qs[1 * 4 + 3] = s[2 * 3 + 0] + s[0 * 3 + 2]; 294 Qs[3 * 4 + 2] = Qs[2 * 4 + 3] = s[2 * 3 + 1] + s[1 * 3 + 2]; 295 296 jacobi_4x4(Qs, evs, U); 297 298 // Looking for the largest eigen value: 299 int i_ev = 0; 300 double ev_max = evs[i_ev]; 301 for(int i = 1; i < 4; i++) 302 if (evs[i] > ev_max) 303 ev_max = evs[i_ev = i]; 304 305 // Quaternion: 306 double q[4]; 307 for(int i = 0; i < 4; i++) 308 q[i] = U[i * 4 + i_ev]; 309 310 double q02 = q[0] * q[0], q12 = q[1] * q[1], q22 = q[2] * q[2], q32 = q[3] * q[3]; 311 double q0_1 = q[0] * q[1], q0_2 = q[0] * q[2], q0_3 = q[0] * q[3]; 312 double q1_2 = q[1] * q[2], q1_3 = q[1] * q[3]; 313 double q2_3 = q[2] * q[3]; 314 315 R[0][0] = q02 + q12 - q22 - q32; 316 R[0][1] = 2. * (q1_2 - q0_3); 317 R[0][2] = 2. * (q1_3 + q0_2); 318 319 R[1][0] = 2. * (q1_2 + q0_3); 320 R[1][1] = q02 + q22 - q12 - q32; 321 R[1][2] = 2. * (q2_3 - q0_1); 322 323 R[2][0] = 2. * (q1_3 - q0_2); 324 R[2][1] = 2. * (q2_3 + q0_1); 325 R[2][2] = q02 + q32 - q12 - q22; 326 327 for(int i = 0; i < 3; i++) 328 T[i] = C_end[i] - (R[i][0] * C_start[0] + R[i][1] * C_start[1] + R[i][2] * C_start[2]); 329 330 return true; 331 } 332 333 bool p3p::jacobi_4x4(double * A, double * D, double * U) 334 { 335 double B[4], Z[4]; 336 double Id[16] = {1., 0., 0., 0., 337 0., 1., 0., 0., 338 0., 0., 1., 0., 339 0., 0., 0., 1.}; 340 341 memcpy(U, Id, 16 * sizeof(double)); 342 343 B[0] = A[0]; B[1] = A[5]; B[2] = A[10]; B[3] = A[15]; 344 memcpy(D, B, 4 * sizeof(double)); 345 memset(Z, 0, 4 * sizeof(double)); 346 347 for(int iter = 0; iter < 50; iter++) { 348 double sum = fabs(A[1]) + fabs(A[2]) + fabs(A[3]) + fabs(A[6]) + fabs(A[7]) + fabs(A[11]); 349 350 if (sum == 0.0) 351 return true; 352 353 double tresh = (iter < 3) ? 0.2 * sum / 16. : 0.0; 354 for(int i = 0; i < 3; i++) { 355 double * pAij = A + 5 * i + 1; 356 for(int j = i + 1 ; j < 4; j++) { 357 double Aij = *pAij; 358 double eps_machine = 100.0 * fabs(Aij); 359 360 if ( iter > 3 && fabs(D[i]) + eps_machine == fabs(D[i]) && fabs(D[j]) + eps_machine == fabs(D[j]) ) 361 *pAij = 0.0; 362 else if (fabs(Aij) > tresh) { 363 double hh = D[j] - D[i], t; 364 if (fabs(hh) + eps_machine == fabs(hh)) 365 t = Aij / hh; 366 else { 367 double theta = 0.5 * hh / Aij; 368 t = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta)); 369 if (theta < 0.0) t = -t; 370 } 371 372 hh = t * Aij; 373 Z[i] -= hh; 374 Z[j] += hh; 375 D[i] -= hh; 376 D[j] += hh; 377 *pAij = 0.0; 378 379 double c = 1.0 / sqrt(1 + t * t); 380 double s = t * c; 381 double tau = s / (1.0 + c); 382 for(int k = 0; k <= i - 1; k++) { 383 double g = A[k * 4 + i], h = A[k * 4 + j]; 384 A[k * 4 + i] = g - s * (h + g * tau); 385 A[k * 4 + j] = h + s * (g - h * tau); 386 } 387 for(int k = i + 1; k <= j - 1; k++) { 388 double g = A[i * 4 + k], h = A[k * 4 + j]; 389 A[i * 4 + k] = g - s * (h + g * tau); 390 A[k * 4 + j] = h + s * (g - h * tau); 391 } 392 for(int k = j + 1; k < 4; k++) { 393 double g = A[i * 4 + k], h = A[j * 4 + k]; 394 A[i * 4 + k] = g - s * (h + g * tau); 395 A[j * 4 + k] = h + s * (g - h * tau); 396 } 397 for(int k = 0; k < 4; k++) { 398 double g = U[k * 4 + i], h = U[k * 4 + j]; 399 U[k * 4 + i] = g - s * (h + g * tau); 400 U[k * 4 + j] = h + s * (g - h * tau); 401 } 402 } 403 pAij++; 404 } 405 } 406 407 for(int i = 0; i < 4; i++) B[i] += Z[i]; 408 memcpy(D, B, 4 * sizeof(double)); 409 memset(Z, 0, 4 * sizeof(double)); 410 } 411 412 return false; 413 } 414