1
+ // Implementation of SQPnP as described in the paper:
2
+ //
3
+ // "A Consistently Fast and Globally Optimal Solution to the Perspective-n-Point Problem" by G. Terzakis and M. Lourakis
4
+ // a) Paper: https://www.ecva.net/papers/eccv_2020/papers_ECCV/papers/123460460.pdf
5
+ // b) Supplementary: https://www.ecva.net/papers/eccv_2020/papers_ECCV/papers/123460460-supp.pdf
6
+
7
+
1
8
// This file is part of OpenCV project.
2
9
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
10
// of this distribution and at http://opencv.org/license.html
@@ -39,6 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
46
#include " precomp.hpp"
40
47
#include " sqpnp.hpp"
41
48
49
+ #ifdef HAVE_EIGEN
50
+ #include < Eigen/Dense>
51
+ #endif
52
+
42
53
#include < opencv2/calib3d.hpp>
43
54
44
55
namespace cv {
@@ -54,8 +65,8 @@ const double PoseSolver::POINT_VARIANCE_THRESHOLD = 1e-5;
54
65
const double PoseSolver::SQRT3 = std::sqrt(3 );
55
66
const int PoseSolver::SQP_MAX_ITERATION = 15 ;
56
67
57
- // No checking done here for overflow, since this is not public all call instances
58
- // are assumed to be valid
68
+ // No checking done here for overflow, since this is not public all call instances
69
+ // are assumed to be valid
59
70
template <typename tp, int snrows, int sncols,
60
71
int dnrows, int dncols>
61
72
void set (int row, int col, cv::Matx<tp, dnrows, dncols>& dest,
@@ -80,7 +91,7 @@ PoseSolver::PoseSolver()
80
91
void PoseSolver::solve (InputArray objectPoints, InputArray imagePoints, OutputArrayOfArrays rvecs,
81
92
OutputArrayOfArrays tvecs)
82
93
{
83
- // Input checking
94
+ // Input checking
84
95
int objType = objectPoints.getMat ().type ();
85
96
CV_CheckType (objType, objType == CV_32FC3 || objType == CV_64FC3,
86
97
" Type of objectPoints must be CV_32FC3 or CV_64FC3" );
@@ -160,12 +171,12 @@ void PoseSolver::computeOmega(InputArray objectPoints, InputArray imagePoints)
160
171
sum_img += img_pt;
161
172
sum_obj += obj_pt;
162
173
163
- const double & x = img_pt.x , & y = img_pt.y ;
164
- const double & X = obj_pt.x , & Y = obj_pt.y , & Z = obj_pt.z ;
174
+ const double x = img_pt.x , y = img_pt.y ;
175
+ const double X = obj_pt.x , Y = obj_pt.y , Z = obj_pt.z ;
165
176
double sq_norm = x * x + y * y;
166
177
sq_norm_sum += sq_norm;
167
178
168
- double X2 = X * X,
179
+ const double X2 = X * X,
169
180
XY = X * Y,
170
181
XZ = X * Z,
171
182
Y2 = Y * Y,
@@ -180,47 +191,47 @@ void PoseSolver::computeOmega(InputArray objectPoints, InputArray imagePoints)
180
191
omega_ (2 , 2 ) += Z2;
181
192
182
193
183
- // Populating this manually saves operations by only calculating upper triangle
184
- omega_ (0 , 6 ) += - x * X2; omega_ (0 , 7 ) += - x * XY; omega_ (0 , 8 ) += - x * XZ;
185
- omega_ (1 , 7 ) += - x * Y2; omega_ (1 , 8 ) += - x * YZ;
186
- omega_ (2 , 8 ) += - x * Z2;
194
+ // Populating this manually saves operations by only calculating upper triangle
195
+ omega_ (0 , 6 ) -= x * X2; omega_ (0 , 7 ) -= x * XY; omega_ (0 , 8 ) -= x * XZ;
196
+ omega_ (1 , 7 ) -= x * Y2; omega_ (1 , 8 ) -= x * YZ;
197
+ omega_ (2 , 8 ) -= x * Z2;
187
198
188
- omega_ (3 , 6 ) += - y * X2; omega_ (3 , 7 ) += - y * XY; omega_ (3 , 8 ) += - y * XZ;
189
- omega_ (4 , 7 ) += - y * Y2; omega_ (4 , 8 ) += - y * YZ;
190
- omega_ (5 , 8 ) += - y * Z2;
199
+ omega_ (3 , 6 ) -= y * X2; omega_ (3 , 7 ) -= y * XY; omega_ (3 , 8 ) -= y * XZ;
200
+ omega_ (4 , 7 ) -= y * Y2; omega_ (4 , 8 ) -= y * YZ;
201
+ omega_ (5 , 8 ) -= y * Z2;
191
202
192
203
193
204
omega_ (6 , 6 ) += sq_norm * X2; omega_ (6 , 7 ) += sq_norm * XY; omega_ (6 , 8 ) += sq_norm * XZ;
194
205
omega_ (7 , 7 ) += sq_norm * Y2; omega_ (7 , 8 ) += sq_norm * YZ;
195
206
omega_ (8 , 8 ) += sq_norm * Z2;
196
207
197
- // Compute qa_sum. Certain pairs of elements are equal, so filling them outside the loop saves some operations
208
+ // Compute qa_sum. Certain pairs of elements are equal, so filling them outside the loop saves some operations
198
209
qa_sum (0 , 0 ) += X; qa_sum (0 , 1 ) += Y; qa_sum (0 , 2 ) += Z;
199
210
200
- qa_sum (0 , 6 ) += - x * X; qa_sum (0 , 7 ) += - x * Y; qa_sum (0 , 8 ) += - x * Z;
201
- qa_sum (1 , 6 ) += - y * X; qa_sum (1 , 7 ) += - y * Y; qa_sum (1 , 8 ) += - y * Z;
211
+ qa_sum (0 , 6 ) -= x * X; qa_sum (0 , 7 ) -= x * Y; qa_sum (0 , 8 ) -= x * Z;
212
+ qa_sum (1 , 6 ) -= y * X; qa_sum (1 , 7 ) -= y * Y; qa_sum (1 , 8 ) -= y * Z;
202
213
203
214
qa_sum (2 , 6 ) += sq_norm * X; qa_sum (2 , 7 ) += sq_norm * Y; qa_sum (2 , 8 ) += sq_norm * Z;
204
215
}
205
216
206
- // Complete qa_sum
217
+ // Complete qa_sum
207
218
qa_sum (1 , 3 ) = qa_sum (0 , 0 ); qa_sum (1 , 4 ) = qa_sum (0 , 1 ); qa_sum (1 , 5 ) = qa_sum (0 , 2 );
208
219
qa_sum (2 , 0 ) = qa_sum (0 , 6 ); qa_sum (2 , 1 ) = qa_sum (0 , 7 ); qa_sum (2 , 2 ) = qa_sum (0 , 8 );
209
220
qa_sum (2 , 3 ) = qa_sum (1 , 6 ); qa_sum (2 , 4 ) = qa_sum (1 , 7 ); qa_sum (2 , 5 ) = qa_sum (1 , 8 );
210
221
211
222
212
- // lower triangles of omega_'s off-diagonal blocks (0:2, 6:8), (3:5, 6:8) and (6:8, 6:8)
223
+ // lower triangles of omega_'s off-diagonal blocks (0:2, 6:8), (3:5, 6:8) and (6:8, 6:8)
213
224
omega_ (1 , 6 ) = omega_ (0 , 7 ); omega_ (2 , 6 ) = omega_ (0 , 8 ); omega_ (2 , 7 ) = omega_ (1 , 8 );
214
225
omega_ (4 , 6 ) = omega_ (3 , 7 ); omega_ (5 , 6 ) = omega_ (3 , 8 ); omega_ (5 , 7 ) = omega_ (4 , 8 );
215
226
omega_ (7 , 6 ) = omega_ (6 , 7 ); omega_ (8 , 6 ) = omega_ (6 , 8 ); omega_ (8 , 7 ) = omega_ (7 , 8 );
216
227
217
- // upper triangle of omega_'s block (3:5, 3:5)
228
+ // upper triangle of omega_'s block (3:5, 3:5)
218
229
omega_ (3 , 3 ) = omega_ (0 , 0 ); omega_ (3 , 4 ) = omega_ (0 , 1 ); omega_ (3 , 5 ) = omega_ (0 , 2 );
219
230
omega_ (4 , 4 ) = omega_ (1 , 1 ); omega_ (4 , 5 ) = omega_ (1 , 2 );
220
231
omega_ (5 , 5 ) = omega_ (2 , 2 );
221
232
222
- // Mirror omega_'s upper triangle to lower triangle
223
- // Note that elements (7, 6), (8, 6) & (8, 7) have already been assigned above
233
+ // Mirror omega_'s upper triangle to lower triangle
234
+ // Note that elements (7, 6), (8, 6) & (8, 7) have already been assigned above
224
235
omega_ (1 , 0 ) = omega_ (0 , 1 );
225
236
omega_ (2 , 0 ) = omega_ (0 , 2 ); omega_ (2 , 1 ) = omega_ (1 , 2 );
226
237
omega_ (3 , 0 ) = omega_ (0 , 3 ); omega_ (3 , 1 ) = omega_ (1 , 3 ); omega_ (3 , 2 ) = omega_ (2 , 3 );
@@ -242,12 +253,26 @@ void PoseSolver::computeOmega(InputArray objectPoints, InputArray imagePoints)
242
253
CV_Assert (point_coordinate_variance >= POINT_VARIANCE_THRESHOLD);
243
254
244
255
Matx<double , 3 , 3 > q_inv;
245
- analyticalInverse3x3Symm (q, q_inv);
256
+ if (! invertSPD3x3 (q, q_inv)) analyticalInverse3x3Symm (q, q_inv);
246
257
247
258
p_ = -q_inv * qa_sum;
248
259
249
260
omega_ += qa_sum.t () * p_;
250
261
262
+ #ifdef HAVE_EIGEN
263
+ // Rank revealing QR nullspace computation with full pivoting.
264
+ // This is slightly less accurate compared to SVD but x2-x3 faster
265
+ Eigen::Matrix<double , 9 , 9 > omega_eig, tmp_eig;
266
+ cv::cv2eigen (omega_, omega_eig);
267
+ Eigen::FullPivHouseholderQR<Eigen::Matrix<double , 9 , 9 > > rrqr (omega_eig);
268
+ tmp_eig = rrqr.matrixQ ();
269
+ cv::eigen2cv (tmp_eig, u_);
270
+
271
+ tmp_eig = rrqr.matrixQR ().template triangularView <Eigen::Upper>(); // R
272
+ Eigen::Matrix<double , 9 , 1 > S_eig = tmp_eig.diagonal ().array ().abs ();
273
+ cv::eigen2cv (S_eig, s_);
274
+ #else
275
+ // Use OpenCV's SVD
251
276
cv::SVD omega_svd (omega_, cv::SVD::FULL_UV);
252
277
s_ = omega_svd.w ;
253
278
u_ = cv::Mat (omega_svd.vt .t ());
@@ -257,6 +282,8 @@ void PoseSolver::computeOmega(InputArray objectPoints, InputArray imagePoints)
257
282
u_ = u_.t(); // eigenvectors were returned as rows
258
283
#endif
259
284
285
+ #endif // HAVE_EIGEN
286
+
260
287
CV_Assert (s_ (0 ) >= 1e-7 );
261
288
262
289
while (s_ (7 - num_null_vectors_) < RANK_TOLERANCE) num_null_vectors_++;
@@ -278,7 +305,7 @@ void PoseSolver::solveInternal(InputArray objectPoints)
278
305
279
306
SQPSolution solutions[2 ];
280
307
281
- // If e is orthogonal, we can skip SQP
308
+ // If e is orthogonal, we can skip SQP
282
309
if (orthogonality_sq_err < ORTHOGONALITY_SQUARED_ERROR_THRESHOLD)
283
310
{
284
311
solutions[0 ].r_hat = det3x3 (e) * e;
@@ -395,6 +422,76 @@ void PoseSolver::solveSQPSystem(const cv::Matx<double, 9, 1>& r, cv::Matx<double
395
422
delta += N * y;
396
423
}
397
424
425
+ // Inverse of SPD 3x3 A via a lower triangular sqrt-free Cholesky
426
+ // factorization A=L*D*L' (L has ones on its diagonal, D is diagonal).
427
+ //
428
+ // Only the lower triangular part of A is accessed.
429
+ //
430
+ // The function returns true if successful
431
+ //
432
+ // see http://euler.nmt.edu/~brian/ldlt.html
433
+ //
434
+ bool PoseSolver::invertSPD3x3 (const cv::Matx<double , 3 , 3 >& A, cv::Matx<double , 3 , 3 >& A1)
435
+ {
436
+ double L[3 *3 ], D[3 ], v[2 ], x[3 ];
437
+
438
+ v[0 ]=D[0 ]=A (0 , 0 );
439
+ if (v[0 ]<=1E-10 ) return false ;
440
+ v[1 ]=1.0 /v[0 ];
441
+ L[3 ]=A (1 , 0 )*v[1 ];
442
+ L[6 ]=A (2 , 0 )*v[1 ];
443
+ // L[0]=1.0;
444
+ // L[1]=L[2]=0.0;
445
+
446
+ v[0 ]=L[3 ]*D[0 ];
447
+ v[1 ]=D[1 ]=A (1 , 1 )-L[3 ]*v[0 ];
448
+ if (v[1 ]<=1E-10 ) return false ;
449
+ L[7 ]=(A (2 , 1 )-L[6 ]*v[0 ])/v[1 ];
450
+ // L[4]=1.0;
451
+ // L[5]=0.0;
452
+
453
+ v[0 ]=L[6 ]*D[0 ];
454
+ v[1 ]=L[7 ]*D[1 ];
455
+ D[2 ]=A (2 , 2 )-L[6 ]*v[0 ]-L[7 ]*v[1 ];
456
+ // L[8]=1.0;
457
+
458
+ D[0 ]=1.0 /D[0 ];
459
+ D[1 ]=1.0 /D[1 ];
460
+ D[2 ]=1.0 /D[2 ];
461
+
462
+ /* Forward solve Lx = e0 */
463
+ // x[0]=1.0;
464
+ x[1 ]=-L[3 ];
465
+ x[2 ]=-L[6 ]+L[7 ]*L[3 ];
466
+
467
+ /* Backward solve D*L'x = y */
468
+ A1 (0 , 2 )=x[2 ]=x[2 ]*D[2 ];
469
+ A1 (0 , 1 )=x[1 ]=x[1 ]*D[1 ]-L[7 ]*x[2 ];
470
+ A1 (0 , 0 ) = D[0 ]-L[3 ]*x[1 ]-L[6 ]*x[2 ];
471
+
472
+ /* Forward solve Lx = e1 */
473
+ // x[0]=0.0;
474
+ // x[1]=1.0;
475
+ x[2 ]=-L[7 ];
476
+
477
+ /* Backward solve D*L'x = y */
478
+ A1 (1 , 2 )=x[2 ]=x[2 ]*D[2 ];
479
+ A1 (1 , 1 )=x[1 ]= D[1 ]-L[7 ]*x[2 ];
480
+ A1 (1 , 0 ) = -L[3 ]*x[1 ]-L[6 ]*x[2 ];
481
+
482
+ /* Forward solve Lx = e2 */
483
+ // x[0]=0.0;
484
+ // x[1]=0.0;
485
+ // x[2]=1.0;
486
+
487
+ /* Backward solve D*L'x = y */
488
+ A1 (2 , 2 )=x[2 ]=D[2 ];
489
+ A1 (2 , 1 )=x[1 ]= -L[7 ]*x[2 ];
490
+ A1 (2 , 0 ) = -L[3 ]*x[1 ]-L[6 ]*x[2 ];
491
+
492
+ return true ;
493
+ }
494
+
398
495
bool PoseSolver::analyticalInverse3x3Symm (const cv::Matx<double , 3 , 3 >& Q,
399
496
cv::Matx<double , 3 , 3 >& Qinv,
400
497
const double & threshold)
@@ -504,7 +601,7 @@ void PoseSolver::computeRowAndNullspace(const cv::Matx<double, 9, 1>& r,
504
601
H (6 , 4 ) = r (3 ) - dot_j5q3 * H (6 , 2 ); H (7 , 4 ) = r (4 ) - dot_j5q3 * H (7 , 2 ); H (8 , 4 ) = r (5 ) - dot_j5q3 * H (8 , 2 );
505
602
506
603
Matx<double , 9 , 1 > q4 = H.col (4 );
507
- q4 /= cv::norm (q4);
604
+ q4 *= ( 1.0 / cv::norm (q4) );
508
605
set<double , 9 , 1 , 9 , 6 >(0 , 4 , H, q4);
509
606
510
607
K (4 , 0 ) = 0 ;
@@ -533,7 +630,7 @@ void PoseSolver::computeRowAndNullspace(const cv::Matx<double, 9, 1>& r,
533
630
H (8 , 5 ) = r (2 ) - dot_j6q3 * H (8 , 2 ) - dot_j6q5 * H (8 , 4 );
534
631
535
632
Matx<double , 9 , 1 > q5 = H.col (5 );
536
- q5 /= cv::norm (q5);
633
+ q5 *= ( 1.0 / cv::norm (q5) );
537
634
set<double , 9 , 1 , 9 , 6 >(0 , 5 , H, q5);
538
635
539
636
K (5 , 0 ) = r (6 ) * H (0 , 0 ) + r (7 ) * H (1 , 0 ) + r (8 ) * H (2 , 0 );
@@ -575,10 +672,11 @@ void PoseSolver::computeRowAndNullspace(const cv::Matx<double, 9, 1>& r,
575
672
Matx<double , 9 , 1 > v1 = Pn.col (index1);
576
673
v1 /= max_norm1;
577
674
set<double , 9 , 1 , 9 , 3 >(0 , 0 , N, v1);
675
+ col_norms[index1] = -1.0 ; // mark to avoid use in subsequent loops
578
676
579
677
for (int i = 0 ; i < 9 ; i++)
580
678
{
581
- if (i == index1) continue ;
679
+ // if (i == index1) continue;
582
680
if (col_norms[i] >= norm_threshold)
583
681
{
584
682
double cos_v1_x_col = fabs (Pn.col (i).dot (v1) / col_norms[i]);
@@ -594,16 +692,18 @@ void PoseSolver::computeRowAndNullspace(const cv::Matx<double, 9, 1>& r,
594
692
Matx<double , 9 , 1 > v2 = Pn.col (index2);
595
693
Matx<double , 9 , 1 > n0 = N.col (0 );
596
694
v2 -= v2.dot (n0) * n0;
597
- v2 /= cv::norm (v2);
695
+ v2 *= ( 1.0 / cv::norm (v2) );
598
696
set<double , 9 , 1 , 9 , 3 >(0 , 1 , N, v2);
697
+ col_norms[index2] = -1.0 ; // mark to avoid use in subsequent loops
599
698
600
699
for (int i = 0 ; i < 9 ; i++)
601
700
{
602
- if (i == index2 || i == index1) continue ;
701
+ // if (i == index2 || i == index1) continue;
603
702
if (col_norms[i] >= norm_threshold)
604
703
{
605
- double cos_v1_x_col = fabs (Pn.col (i).dot (v1) / col_norms[i]);
606
- double cos_v2_x_col = fabs (Pn.col (i).dot (v2) / col_norms[i]);
704
+ double inv_norm = 1.0 / col_norms[i];
705
+ double cos_v1_x_col = fabs (Pn.col (i).dot (v1) * inv_norm);
706
+ double cos_v2_x_col = fabs (Pn.col (i).dot (v2) * inv_norm);
607
707
608
708
if (cos_v1_x_col + cos_v2_x_col <= min_dot1323)
609
709
{
@@ -616,7 +716,7 @@ void PoseSolver::computeRowAndNullspace(const cv::Matx<double, 9, 1>& r,
616
716
Matx<double , 9 , 1 > v3 = Pn.col (index3);
617
717
Matx<double , 9 , 1 > n1 = N.col (1 );
618
718
v3 -= (v3.dot (n1)) * n1 - (v3.dot (n0)) * n0;
619
- v3 /= cv::norm (v3);
719
+ v3 *= ( 1.0 / cv::norm (v3) );
620
720
set<double , 9 , 1 , 9 , 3 >(0 , 2 , N, v3);
621
721
622
722
}
@@ -637,25 +737,25 @@ void PoseSolver::nearestRotationMatrixSVD(const cv::Matx<double, 9, 1>& e,
637
737
// Faster nearest rotation computation based on FOAM. See M. Lourakis: "An Efficient Solution to Absolute Orientation", ICPR 2016
638
738
// and M. Lourakis, G. Terzakis: "Efficient Absolute Orientation Revisited", IROS 2018.
639
739
/* Solve the nearest orthogonal approximation problem
640
- * i.e., given e, find R minimizing ||R-e||_F
641
- *
642
- * The computation borrows from Markley's FOAM algorithm
643
- * "Attitude Determination Using Vector Observations: A Fast Optimal Matrix Algorithm", J. Astronaut. Sci. 1993.
644
- *
645
- * See also M. Lourakis: "An Efficient Solution to Absolute Orientation", ICPR 2016
646
- *
647
- * Copyright (C) 2019 Manolis Lourakis (lourakis **at** ics forth gr)
648
- * Institute of Computer Science, Foundation for Research & Technology - Hellas
649
- * Heraklion, Crete, Greece.
650
- */
740
+ * i.e., given e, find R minimizing ||R-e||_F
741
+ *
742
+ * The computation borrows from Markley's FOAM algorithm
743
+ * "Attitude Determination Using Vector Observations: A Fast Optimal Matrix Algorithm", J. Astronaut. Sci. 1993.
744
+ *
745
+ * See also M. Lourakis: "An Efficient Solution to Absolute Orientation", ICPR 2016
746
+ *
747
+ * Copyright (C) 2019 Manolis Lourakis (lourakis **at** ics forth gr)
748
+ * Institute of Computer Science, Foundation for Research & Technology - Hellas
749
+ * Heraklion, Crete, Greece.
750
+ */
651
751
void PoseSolver::nearestRotationMatrixFOAM (const cv::Matx<double , 9 , 1 >& e,
652
752
cv::Matx<double , 9 , 1 >& r)
653
753
{
654
754
int i;
655
755
double l, lprev, det_e, e_sq, adj_e_sq, adj_e[9 ];
656
756
657
757
// det(e)
658
- det_e = e (0 ) * e (4 ) * e (8 ) - e (0 ) * e (5 ) * e (7 ) - e (1 ) * e (3 ) * e (8 ) + e (2 ) * e (3 ) * e (7 ) + e (1 ) * e (6 ) * e (5 ) - e (2 ) * e (6 ) * e (4 );
758
+ det_e = ( e (0 ) * e (4 ) * e (8 ) - e (0 ) * e (5 ) * e (7 ) - e (1 ) * e (3 ) * e (8 ) ) + ( e (2 ) * e (3 ) * e (7 ) + e (1 ) * e (6 ) * e (5 ) - e (2 ) * e (6 ) * e (4 ) );
659
759
if (fabs (det_e) < 1E-04 ) { // singular, handle it with SVD
660
760
PoseSolver::nearestRotationMatrixSVD (e, r);
661
761
return ;
@@ -667,8 +767,8 @@ void PoseSolver::nearestRotationMatrixFOAM(const cv::Matx<double, 9, 1>& e,
667
767
adj_e[6 ] = e (3 ) * e (7 ) - e (4 ) * e (6 ); adj_e[7 ] = e (1 ) * e (6 ) - e (0 ) * e (7 ); adj_e[8 ] = e (0 ) * e (4 ) - e (1 ) * e (3 );
668
768
669
769
// ||e||^2, ||adj(e)||^2
670
- e_sq = e (0 ) * e (0 ) + e (1 ) * e (1 ) + e (2 ) * e (2 ) + e (3 ) * e (3 ) + e (4 ) * e (4 ) + e (5 ) * e (5 ) + e (6 ) * e (6 ) + e (7 ) * e (7 ) + e (8 ) * e (8 );
671
- adj_e_sq = adj_e[0 ] * adj_e[0 ] + adj_e[1 ] * adj_e[1 ] + adj_e[2 ] * adj_e[2 ] + adj_e[3 ] * adj_e[3 ] + adj_e[4 ] * adj_e[4 ] + adj_e[5 ] * adj_e[5 ] + adj_e[6 ] * adj_e[6 ] + adj_e[7 ] * adj_e[7 ] + adj_e[8 ] * adj_e[8 ];
770
+ e_sq = ( e (0 ) * e (0 ) + e (1 ) * e (1 ) + e (2 ) * e (2 ) ) + ( e (3 ) * e (3 ) + e (4 ) * e (4 ) + e (5 ) * e (5 ) ) + ( e (6 ) * e (6 ) + e (7 ) * e (7 ) + e (8 ) * e (8 ) );
771
+ adj_e_sq = ( adj_e[0 ] * adj_e[0 ] + adj_e[1 ] * adj_e[1 ] + adj_e[2 ] * adj_e[2 ] ) + ( adj_e[3 ] * adj_e[3 ] + adj_e[4 ] * adj_e[4 ] + adj_e[5 ] * adj_e[5 ] ) + ( adj_e[6 ] * adj_e[6 ] + adj_e[7 ] * adj_e[7 ] + adj_e[8 ] * adj_e[8 ] ) ;
672
772
673
773
// compute l_max with Newton-Raphson from FOAM's characteristic polynomial, i.e. eq.(23) - (26)
674
774
l = 0.5 *(e_sq + 3.0 ); // 1/2*(trace(mat(e)*mat(e)') + trace(eye(3)))
@@ -735,8 +835,8 @@ void PoseSolver::nearestRotationMatrixFOAM(const cv::Matx<double, 9, 1>& e,
735
835
736
836
double PoseSolver::det3x3 (const cv::Matx<double , 9 , 1 >& e)
737
837
{
738
- return e (0 ) * e (4 ) * e (8 ) + e (1 ) * e (5 ) * e (6 ) + e (2 ) * e (3 ) * e (7 )
739
- - e (6 ) * e (4 ) * e (2 ) - e (7 ) * e (5 ) * e (0 ) - e (8 ) * e (3 ) * e (1 );
838
+ return ( e (0 ) * e (4 ) * e (8 ) + e (1 ) * e (5 ) * e (6 ) + e (2 ) * e (3 ) * e (7 ) )
839
+ - ( e (6 ) * e (4 ) * e (2 ) + e (7 ) * e (5 ) * e (0 ) + e (8 ) * e (3 ) * e (1 ) );
740
840
}
741
841
742
842
inline bool PoseSolver::positiveDepth (const SQPSolution& solution) const
@@ -817,8 +917,8 @@ double PoseSolver::orthogonalityError(const cv::Matx<double, 9, 1>& e)
817
917
double dot_e1e3 = e (0 ) * e (6 ) + e (1 ) * e (7 ) + e (2 ) * e (8 );
818
918
double dot_e2e3 = e (3 ) * e (6 ) + e (4 ) * e (7 ) + e (5 ) * e (8 );
819
919
820
- return (sq_norm_e1 - 1 ) * (sq_norm_e1 - 1 ) + (sq_norm_e2 - 1 ) * (sq_norm_e2 - 1 ) + (sq_norm_e3 - 1 ) * (sq_norm_e3 - 1 ) +
821
- 2 * (dot_e1e2 * dot_e1e2 + dot_e1e3 * dot_e1e3 + dot_e2e3 * dot_e2e3);
920
+ return ( ( sq_norm_e1 - 1 ) * (sq_norm_e1 - 1 ) + (sq_norm_e2 - 1 ) * (sq_norm_e2 - 1 ) ) + ( (sq_norm_e3 - 1 ) * (sq_norm_e3 - 1 ) +
921
+ 2 * (dot_e1e2 * dot_e1e2 + dot_e1e3 * dot_e1e3 + dot_e2e3 * dot_e2e3) ) ;
822
922
}
823
923
824
924
}
0 commit comments