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