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