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