Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/calib3d/src/ap3p.cpp
16354 views
1
#include "ap3p.h"
2
3
#include <cmath>
4
#include <complex>
5
#if defined (_MSC_VER) && (_MSC_VER <= 1700)
6
static inline double cbrt(double x) { return (double)cv::cubeRoot((float)x); };
7
#endif
8
9
using namespace std;
10
11
namespace {
12
void solveQuartic(const double *factors, double *realRoots) {
13
const double &a4 = factors[0];
14
const double &a3 = factors[1];
15
const double &a2 = factors[2];
16
const double &a1 = factors[3];
17
const double &a0 = factors[4];
18
19
double a4_2 = a4 * a4;
20
double a3_2 = a3 * a3;
21
double a4_3 = a4_2 * a4;
22
double a2a4 = a2 * a4;
23
24
double p4 = (8 * a2a4 - 3 * a3_2) / (8 * a4_2);
25
double q4 = (a3_2 * a3 - 4 * a2a4 * a3 + 8 * a1 * a4_2) / (8 * a4_3);
26
double r4 = (256 * a0 * a4_3 - 3 * (a3_2 * a3_2) - 64 * a1 * a3 * a4_2 + 16 * a2a4 * a3_2) / (256 * (a4_3 * a4));
27
28
double p3 = ((p4 * p4) / 12 + r4) / 3; // /=-3
29
double q3 = (72 * r4 * p4 - 2 * p4 * p4 * p4 - 27 * q4 * q4) / 432; // /=2
30
31
double t; // *=2
32
complex<double> w;
33
if (q3 >= 0)
34
w = -sqrt(static_cast<complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
35
else
36
w = sqrt(static_cast<complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
37
if (w.imag() == 0.0) {
38
w.real(cbrt(w.real()));
39
t = 2.0 * (w.real() + p3 / w.real());
40
} else {
41
w = pow(w, 1.0 / 3);
42
t = 4.0 * w.real();
43
}
44
45
complex<double> sqrt_2m = sqrt(static_cast<complex<double> >(-2 * p4 / 3 + t));
46
double B_4A = -a3 / (4 * a4);
47
double complex1 = 4 * p4 / 3 + t;
48
#if defined(__clang__) && defined(__arm__) && (__clang_major__ == 3 || __clang_minor__ == 4) && !defined(__ANDROID__)
49
// details: https://github.com/opencv/opencv/issues/11135
50
// details: https://github.com/opencv/opencv/issues/11056
51
complex<double> complex2 = 2 * q4;
52
complex2 = complex<double>(complex2.real() / sqrt_2m.real(), 0);
53
#else
54
complex<double> complex2 = 2 * q4 / sqrt_2m;
55
#endif
56
double sqrt_2m_rh = sqrt_2m.real() / 2;
57
double sqrt1 = sqrt(-(complex1 + complex2)).real() / 2;
58
realRoots[0] = B_4A + sqrt_2m_rh + sqrt1;
59
realRoots[1] = B_4A + sqrt_2m_rh - sqrt1;
60
double sqrt2 = sqrt(-(complex1 - complex2)).real() / 2;
61
realRoots[2] = B_4A - sqrt_2m_rh + sqrt2;
62
realRoots[3] = B_4A - sqrt_2m_rh - sqrt2;
63
}
64
65
void polishQuarticRoots(const double *coeffs, double *roots) {
66
const int iterations = 2;
67
for (int i = 0; i < iterations; ++i) {
68
for (int j = 0; j < 4; ++j) {
69
double error =
70
(((coeffs[0] * roots[j] + coeffs[1]) * roots[j] + coeffs[2]) * roots[j] + coeffs[3]) * roots[j] +
71
coeffs[4];
72
double
73
derivative =
74
((4 * coeffs[0] * roots[j] + 3 * coeffs[1]) * roots[j] + 2 * coeffs[2]) * roots[j] + coeffs[3];
75
roots[j] -= error / derivative;
76
}
77
}
78
}
79
80
inline void vect_cross(const double *a, const double *b, double *result) {
81
result[0] = a[1] * b[2] - a[2] * b[1];
82
result[1] = -(a[0] * b[2] - a[2] * b[0]);
83
result[2] = a[0] * b[1] - a[1] * b[0];
84
}
85
86
inline double vect_dot(const double *a, const double *b) {
87
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
88
}
89
90
inline double vect_norm(const double *a) {
91
return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
92
}
93
94
inline void vect_scale(const double s, const double *a, double *result) {
95
result[0] = a[0] * s;
96
result[1] = a[1] * s;
97
result[2] = a[2] * s;
98
}
99
100
inline void vect_sub(const double *a, const double *b, double *result) {
101
result[0] = a[0] - b[0];
102
result[1] = a[1] - b[1];
103
result[2] = a[2] - b[2];
104
}
105
106
inline void vect_divide(const double *a, const double d, double *result) {
107
result[0] = a[0] / d;
108
result[1] = a[1] / d;
109
result[2] = a[2] / d;
110
}
111
112
inline void mat_mult(const double a[3][3], const double b[3][3], double result[3][3]) {
113
result[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0];
114
result[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1];
115
result[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2];
116
117
result[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0];
118
result[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1];
119
result[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2];
120
121
result[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0];
122
result[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1];
123
result[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2];
124
}
125
}
126
127
namespace cv {
128
void ap3p::init_inverse_parameters() {
129
inv_fx = 1. / fx;
130
inv_fy = 1. / fy;
131
cx_fx = cx / fx;
132
cy_fy = cy / fy;
133
}
134
135
ap3p::ap3p(cv::Mat cameraMatrix) {
136
if (cameraMatrix.depth() == CV_32F)
137
init_camera_parameters<float>(cameraMatrix);
138
else
139
init_camera_parameters<double>(cameraMatrix);
140
init_inverse_parameters();
141
}
142
143
ap3p::ap3p(double _fx, double _fy, double _cx, double _cy) {
144
fx = _fx;
145
fy = _fy;
146
cx = _cx;
147
cy = _cy;
148
init_inverse_parameters();
149
}
150
151
// This algorithm is from "Tong Ke, Stergios Roumeliotis, An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (Accepted by CVPR 2017)
152
// See https://arxiv.org/pdf/1701.08237.pdf
153
// featureVectors: The 3 bearing measurements (normalized) stored as column vectors
154
// worldPoints: The positions of the 3 feature points stored as column vectors
155
// solutionsR: 4 possible solutions of rotation matrix of the world w.r.t the camera frame
156
// solutionsT: 4 possible solutions of translation of the world origin w.r.t the camera frame
157
int ap3p::computePoses(const double featureVectors[3][3],
158
const double worldPoints[3][3],
159
double solutionsR[4][3][3],
160
double solutionsT[4][3]) {
161
162
//world point vectors
163
double w1[3] = {worldPoints[0][0], worldPoints[1][0], worldPoints[2][0]};
164
double w2[3] = {worldPoints[0][1], worldPoints[1][1], worldPoints[2][1]};
165
double w3[3] = {worldPoints[0][2], worldPoints[1][2], worldPoints[2][2]};
166
// k1
167
double u0[3];
168
vect_sub(w1, w2, u0);
169
170
double nu0 = vect_norm(u0);
171
double k1[3];
172
vect_divide(u0, nu0, k1);
173
// bi
174
double b1[3] = {featureVectors[0][0], featureVectors[1][0], featureVectors[2][0]};
175
double b2[3] = {featureVectors[0][1], featureVectors[1][1], featureVectors[2][1]};
176
double b3[3] = {featureVectors[0][2], featureVectors[1][2], featureVectors[2][2]};
177
// k3,tz
178
double k3[3];
179
vect_cross(b1, b2, k3);
180
double nk3 = vect_norm(k3);
181
vect_divide(k3, nk3, k3);
182
183
double tz[3];
184
vect_cross(b1, k3, tz);
185
// ui,vi
186
double v1[3];
187
vect_cross(b1, b3, v1);
188
double v2[3];
189
vect_cross(b2, b3, v2);
190
191
double u1[3];
192
vect_sub(w1, w3, u1);
193
// coefficients related terms
194
double u1k1 = vect_dot(u1, k1);
195
double k3b3 = vect_dot(k3, b3);
196
// f1i
197
double f11 = k3b3;
198
double f13 = vect_dot(k3, v1);
199
double f15 = -u1k1 * f11;
200
//delta
201
double nl[3];
202
vect_cross(u1, k1, nl);
203
double delta = vect_norm(nl);
204
vect_divide(nl, delta, nl);
205
f11 *= delta;
206
f13 *= delta;
207
// f2i
208
double u2k1 = u1k1 - nu0;
209
double f21 = vect_dot(tz, v2);
210
double f22 = nk3 * k3b3;
211
double f23 = vect_dot(k3, v2);
212
double f24 = u2k1 * f22;
213
double f25 = -u2k1 * f21;
214
f21 *= delta;
215
f22 *= delta;
216
f23 *= delta;
217
double g1 = f13 * f22;
218
double g2 = f13 * f25 - f15 * f23;
219
double g3 = f11 * f23 - f13 * f21;
220
double g4 = -f13 * f24;
221
double g5 = f11 * f22;
222
double g6 = f11 * f25 - f15 * f21;
223
double g7 = -f15 * f24;
224
double coeffs[5] = {g5 * g5 + g1 * g1 + g3 * g3,
225
2 * (g5 * g6 + g1 * g2 + g3 * g4),
226
g6 * g6 + 2 * g5 * g7 + g2 * g2 + g4 * g4 - g1 * g1 - g3 * g3,
227
2 * (g6 * g7 - g1 * g2 - g3 * g4),
228
g7 * g7 - g2 * g2 - g4 * g4};
229
double s[4];
230
solveQuartic(coeffs, s);
231
polishQuarticRoots(coeffs, s);
232
233
double temp[3];
234
vect_cross(k1, nl, temp);
235
236
double Ck1nl[3][3] =
237
{{k1[0], nl[0], temp[0]},
238
{k1[1], nl[1], temp[1]},
239
{k1[2], nl[2], temp[2]}};
240
241
double Cb1k3tzT[3][3] =
242
{{b1[0], b1[1], b1[2]},
243
{k3[0], k3[1], k3[2]},
244
{tz[0], tz[1], tz[2]}};
245
246
double b3p[3];
247
vect_scale((delta / k3b3), b3, b3p);
248
249
int nb_solutions = 0;
250
for (int i = 0; i < 4; ++i) {
251
double ctheta1p = s[i];
252
if (abs(ctheta1p) > 1)
253
continue;
254
double stheta1p = sqrt(1 - ctheta1p * ctheta1p);
255
stheta1p = (k3b3 > 0) ? stheta1p : -stheta1p;
256
double ctheta3 = g1 * ctheta1p + g2;
257
double stheta3 = g3 * ctheta1p + g4;
258
double ntheta3 = stheta1p / ((g5 * ctheta1p + g6) * ctheta1p + g7);
259
ctheta3 *= ntheta3;
260
stheta3 *= ntheta3;
261
262
double C13[3][3] =
263
{{ctheta3, 0, -stheta3},
264
{stheta1p * stheta3, ctheta1p, stheta1p * ctheta3},
265
{ctheta1p * stheta3, -stheta1p, ctheta1p * ctheta3}};
266
267
double temp_matrix[3][3];
268
double R[3][3];
269
mat_mult(Ck1nl, C13, temp_matrix);
270
mat_mult(temp_matrix, Cb1k3tzT, R);
271
272
// R' * p3
273
double rp3[3] =
274
{w3[0] * R[0][0] + w3[1] * R[1][0] + w3[2] * R[2][0],
275
w3[0] * R[0][1] + w3[1] * R[1][1] + w3[2] * R[2][1],
276
w3[0] * R[0][2] + w3[1] * R[1][2] + w3[2] * R[2][2]};
277
278
double pxstheta1p[3];
279
vect_scale(stheta1p, b3p, pxstheta1p);
280
281
vect_sub(pxstheta1p, rp3, solutionsT[nb_solutions]);
282
283
solutionsR[nb_solutions][0][0] = R[0][0];
284
solutionsR[nb_solutions][1][0] = R[0][1];
285
solutionsR[nb_solutions][2][0] = R[0][2];
286
solutionsR[nb_solutions][0][1] = R[1][0];
287
solutionsR[nb_solutions][1][1] = R[1][1];
288
solutionsR[nb_solutions][2][1] = R[1][2];
289
solutionsR[nb_solutions][0][2] = R[2][0];
290
solutionsR[nb_solutions][1][2] = R[2][1];
291
solutionsR[nb_solutions][2][2] = R[2][2];
292
293
nb_solutions++;
294
}
295
296
return nb_solutions;
297
}
298
299
bool ap3p::solve(cv::Mat &R, cv::Mat &tvec, const cv::Mat &opoints, const cv::Mat &ipoints) {
300
CV_INSTRUMENT_REGION();
301
302
double rotation_matrix[3][3], translation[3];
303
std::vector<double> points;
304
if (opoints.depth() == ipoints.depth()) {
305
if (opoints.depth() == CV_32F)
306
extract_points<cv::Point3f, cv::Point2f>(opoints, ipoints, points);
307
else
308
extract_points<cv::Point3d, cv::Point2d>(opoints, ipoints, points);
309
} else if (opoints.depth() == CV_32F)
310
extract_points<cv::Point3f, cv::Point2d>(opoints, ipoints, points);
311
else
312
extract_points<cv::Point3d, cv::Point2f>(opoints, ipoints, points);
313
314
bool result = solve(rotation_matrix, translation, points[0], points[1], points[2], points[3], points[4], points[5],
315
points[6], points[7], points[8], points[9], points[10], points[11], points[12], points[13],
316
points[14],
317
points[15], points[16], points[17], points[18], points[19]);
318
cv::Mat(3, 1, CV_64F, translation).copyTo(tvec);
319
cv::Mat(3, 3, CV_64F, rotation_matrix).copyTo(R);
320
return result;
321
}
322
323
int ap3p::solve(std::vector<cv::Mat> &Rs, std::vector<cv::Mat> &tvecs, const cv::Mat &opoints, const cv::Mat &ipoints) {
324
CV_INSTRUMENT_REGION();
325
326
double rotation_matrix[4][3][3], translation[4][3];
327
std::vector<double> points;
328
if (opoints.depth() == ipoints.depth()) {
329
if (opoints.depth() == CV_32F)
330
extract_points<cv::Point3f, cv::Point2f>(opoints, ipoints, points);
331
else
332
extract_points<cv::Point3d, cv::Point2d>(opoints, ipoints, points);
333
} else if (opoints.depth() == CV_32F)
334
extract_points<cv::Point3f, cv::Point2d>(opoints, ipoints, points);
335
else
336
extract_points<cv::Point3d, cv::Point2f>(opoints, ipoints, points);
337
338
int solutions = solve(rotation_matrix, translation,
339
points[0], points[1], points[2], points[3], points[4],
340
points[5], points[6], points[7], points[8], points[9],
341
points[10], points[11], points[12], points[13], points[14]);
342
343
for (int i = 0; i < solutions; i++) {
344
cv::Mat R, tvec;
345
cv::Mat(3, 1, CV_64F, translation[i]).copyTo(tvec);
346
cv::Mat(3, 3, CV_64F, rotation_matrix[i]).copyTo(R);
347
348
Rs.push_back(R);
349
tvecs.push_back(tvec);
350
}
351
352
return solutions;
353
}
354
355
bool
356
ap3p::solve(double R[3][3], double t[3], double mu0, double mv0, double X0, double Y0, double Z0, double mu1,
357
double mv1,
358
double X1, double Y1, double Z1, double mu2, double mv2, double X2, double Y2, double Z2, double mu3,
359
double mv3, double X3, double Y3, double Z3) {
360
double Rs[4][3][3], ts[4][3];
361
362
int n = solve(Rs, ts, mu0, mv0, X0, Y0, Z0, mu1, mv1, X1, Y1, Z1, mu2, mv2, X2, Y2, Z2);
363
if (n == 0)
364
return false;
365
366
int ns = 0;
367
double min_reproj = 0;
368
for (int i = 0; i < n; i++) {
369
double X3p = Rs[i][0][0] * X3 + Rs[i][0][1] * Y3 + Rs[i][0][2] * Z3 + ts[i][0];
370
double Y3p = Rs[i][1][0] * X3 + Rs[i][1][1] * Y3 + Rs[i][1][2] * Z3 + ts[i][1];
371
double Z3p = Rs[i][2][0] * X3 + Rs[i][2][1] * Y3 + Rs[i][2][2] * Z3 + ts[i][2];
372
double mu3p = cx + fx * X3p / Z3p;
373
double mv3p = cy + fy * Y3p / Z3p;
374
double reproj = (mu3p - mu3) * (mu3p - mu3) + (mv3p - mv3) * (mv3p - mv3);
375
if (i == 0 || min_reproj > reproj) {
376
ns = i;
377
min_reproj = reproj;
378
}
379
}
380
381
for (int i = 0; i < 3; i++) {
382
for (int j = 0; j < 3; j++)
383
R[i][j] = Rs[ns][i][j];
384
t[i] = ts[ns][i];
385
}
386
387
return true;
388
}
389
390
int ap3p::solve(double R[4][3][3], double t[4][3], double mu0, double mv0, double X0, double Y0, double Z0, double mu1,
391
double mv1, double X1, double Y1, double Z1, double mu2, double mv2, double X2, double Y2, double Z2) {
392
double mk0, mk1, mk2;
393
double norm;
394
395
mu0 = inv_fx * mu0 - cx_fx;
396
mv0 = inv_fy * mv0 - cy_fy;
397
norm = sqrt(mu0 * mu0 + mv0 * mv0 + 1);
398
mk0 = 1. / norm;
399
mu0 *= mk0;
400
mv0 *= mk0;
401
402
mu1 = inv_fx * mu1 - cx_fx;
403
mv1 = inv_fy * mv1 - cy_fy;
404
norm = sqrt(mu1 * mu1 + mv1 * mv1 + 1);
405
mk1 = 1. / norm;
406
mu1 *= mk1;
407
mv1 *= mk1;
408
409
mu2 = inv_fx * mu2 - cx_fx;
410
mv2 = inv_fy * mv2 - cy_fy;
411
norm = sqrt(mu2 * mu2 + mv2 * mv2 + 1);
412
mk2 = 1. / norm;
413
mu2 *= mk2;
414
mv2 *= mk2;
415
416
double featureVectors[3][3] = {{mu0, mu1, mu2},
417
{mv0, mv1, mv2},
418
{mk0, mk1, mk2}};
419
double worldPoints[3][3] = {{X0, X1, X2},
420
{Y0, Y1, Y2},
421
{Z0, Z1, Z2}};
422
423
return computePoses(featureVectors, worldPoints, R, t);
424
}
425
}
426
427