1 /******************************************************************************
2  * Author:   Laurent Kneip                                                    *
3  * Contact:  kneip.laurent@gmail.com                                          *
4  * License:  Copyright (c) 2013 Laurent Kneip, ANU. All rights reserved.      *
5  *                                                                            *
6  * Redistribution and use in source and binary forms, with or without         *
7  * modification, are permitted provided that the following conditions         *
8  * are met:                                                                   *
9  * * Redistributions of source code must retain the above copyright           *
10  *   notice, this list of conditions and the following disclaimer.            *
11  * * Redistributions in binary form must reproduce the above copyright        *
12  *   notice, this list of conditions and the following disclaimer in the      *
13  *   documentation and/or other materials provided with the distribution.     *
14  * * Neither the name of ANU nor the names of its contributors may be         *
15  *   used to endorse or promote products derived from this software without   *
16  *   specific prior written permission.                                       *
17  *                                                                            *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"*
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  *
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
21  * ARE DISCLAIMED. IN NO EVENT SHALL ANU OR THE CONTRIBUTORS BE LIABLE        *
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT         *
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  *
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF     *
28  * SUCH DAMAGE.                                                               *
29  ******************************************************************************/
30 
31 
32 #include <math.h>
33 #include <vector>
34 #include <Eigen/NonLinearOptimization>
35 #include <Eigen/NumericalDiff>
36 
37 #include <opengv/relative_pose/modules/main.hpp>
38 #include <opengv/relative_pose/modules/fivept_nister/modules.hpp>
39 #include <opengv/relative_pose/modules/fivept_stewenius/modules.hpp>
40 #include <opengv/relative_pose/modules/fivept_kneip/modules.hpp>
41 #include <opengv/relative_pose/modules/eigensolver/modules.hpp>
42 #include <opengv/relative_pose/modules/sixpt/modules.hpp>
43 #include <opengv/relative_pose/modules/ge/modules.hpp>
44 #include <opengv/OptimizationFunctor.hpp>
45 #include <opengv/math/arun.hpp>
46 #include <opengv/math/cayley.hpp>
47 #include <opengv/math/Sturm.hpp>
48 
49 #include <stdio.h>
50 #include <iostream>
51 
52 void
fivept_stewenius_main(const Eigen::Matrix<double,9,4> & EE,complexEssentials_t & complexEssentials)53 opengv::relative_pose::modules::fivept_stewenius_main(
54     const Eigen::Matrix<double,9,4> & EE,
55     complexEssentials_t & complexEssentials )
56 {
57   Eigen::Matrix<double,10,20> A;
58   fivept_stewenius::composeA(EE,A);
59 
60   Eigen::Matrix<double,10,10> A1 = A.block(0,0,10,10);
61   Eigen::Matrix<double,10,10> A2 = A.block(0,10,10,10);
62 
63   Eigen::FullPivLU< Eigen::Matrix<double,10,10> > luA1(A1);
64   Eigen::Matrix<double,10,10> A3 = luA1.inverse()*A2;
65 
66   Eigen::Matrix<double,10,10> M;
67   M.block(0,0,3,10) = -A3.block(0,0,3,10);
68   M.block(3,0,2,10) = -A3.block(4,0,2,10);
69   M.row(5) = -A3.row(7);
70   M.block(6,0,4,10) = Eigen::Matrix<double,4,10>::Zero();
71   M(6,0) = 1.0;
72   M(7,1) = 1.0;
73   M(8,3) = 1.0;
74   M(9,6) = 1.0;
75 
76   Eigen::EigenSolver< Eigen::Matrix<double,10,10> > Eig(M,true);
77 
78   //Eigen::Matrix<std::complex<double>,10,1> D = Eig.eigenvalues();
79   Eigen::Matrix<std::complex<double>,10,10> V = Eig.eigenvectors();
80 
81   Eigen::Matrix<std::complex<double>,3,10> V1;
82   V1 = V.block(6,0,3,10);
83 
84   Eigen::Matrix<std::complex<double>,3,10> V2;
85   V2.row(0) = V.row(9);
86   V2.row(1) = V.row(9);
87   V2.row(2) = V.row(9);
88 
89   Eigen::Matrix<std::complex<double>,4,10> SOLS;
90 
91   for( int r = 0; r < 3; r++ )
92   {
93     for( int c = 0; c < 10; c++ )
94       SOLS(r,c) = V1(r,c)/V2(r,c);
95   }
96 
97   SOLS.row(3) = Eigen::Matrix<std::complex<double>,1,10>::
98       Constant(std::complex<double>(1.0,0.0));
99 
100   Eigen::Matrix<std::complex<double>,9,10> Evec = EE * SOLS;
101 
102   Eigen::Matrix<std::complex<double>,1,10> norms;
103   for( int c = 0; c < 10; c++ )
104   {
105     norms(0,c) = std::complex<double>(0.0,0.0);
106 
107     for( int r = 0; r < 9; r++ )
108       norms(0,c) += pow( Evec(r,c), 2 );
109 
110     norms(0,c) = sqrt(norms(0,c));
111   }
112 
113   Eigen::Matrix<std::complex<double>,9,10> EvecNorms;
114   for( int i = 0; i < 9; i++ )
115     EvecNorms.row(i) = norms;
116 
117   for( int r = 0; r < 9; r++ )
118   {
119     for( int c = 0; c < 10; c++ )
120       Evec(r,c) = Evec(r,c) / EvecNorms(r,c);
121   }
122 
123   for( int c = 0; c < 10; c++ )
124   {
125     complexEssential_t complexEssential;
126 
127     complexEssential.row(0) = Evec.block(0,c,3,1).transpose();
128     complexEssential.row(1) = Evec.block(3,c,3,1).transpose();
129     complexEssential.row(2) = Evec.block(6,c,3,1).transpose();
130 
131     complexEssentials.push_back(complexEssential);
132   }
133 }
134 
135 void
fivept_nister_main(const Eigen::Matrix<double,9,4> & EE,essentials_t & essentials)136 opengv::relative_pose::modules::fivept_nister_main(
137     const Eigen::Matrix<double,9,4> & EE,
138     essentials_t & essentials )
139 {
140   Eigen::Matrix<double,10,20> A;
141   fivept_nister::composeA(EE,A);
142 
143   Eigen::Matrix<double,10,10> A1 = A.block(0,0,10,10);
144   Eigen::Matrix<double,10,10> A2 = A.block(0,10,10,10);
145 
146   Eigen::FullPivLU< Eigen::Matrix<double,10,10> > luA1(A1);
147   Eigen::Matrix<double,10,10> A3 = luA1.inverse()*A2;
148 
149   Eigen::Matrix<double,1,4> b11_part1 = Eigen::Matrix<double,1,4>::Zero();
150   b11_part1.block<1,3>(0,1) = A3.block<1,3>(4,0);
151   Eigen::Matrix<double,1,4> b11_part2 = Eigen::Matrix<double,1,4>::Zero();
152   b11_part2.block<1,3>(0,0) = A3.block<1,3>(5,0);
153   Eigen::Matrix<double,1,4> b11 = b11_part1 - b11_part2;
154 
155   Eigen::Matrix<double,1,4> b21_part1 = Eigen::Matrix<double,1,4>::Zero();
156   b21_part1.block<1,3>(0,1) = A3.block<1,3>(6,0);
157   Eigen::Matrix<double,1,4> b21_part2 = Eigen::Matrix<double,1,4>::Zero();
158   b21_part2.block<1,3>(0,0) = A3.block<1,3>(7,0);
159   Eigen::Matrix<double,1,4> b21 = b21_part1 - b21_part2;
160 
161   Eigen::Matrix<double,1,4> b31_part1 = Eigen::Matrix<double,1,4>::Zero();
162   b31_part1.block<1,3>(0,1) = A3.block<1,3>(8,0);
163   Eigen::Matrix<double,1,4> b31_part2 = Eigen::Matrix<double,1,4>::Zero();
164   b31_part2.block<1,3>(0,0) = A3.block<1,3>(9,0);
165   Eigen::Matrix<double,1,4> b31 = b31_part1 - b31_part2;
166 
167   Eigen::Matrix<double,1,4> b12_part1 = Eigen::Matrix<double,1,4>::Zero();
168   b12_part1.block<1,3>(0,1) = A3.block<1,3>(4,3);
169   Eigen::Matrix<double,1,4> b12_part2 = Eigen::Matrix<double,1,4>::Zero();
170   b12_part2.block<1,3>(0,0) = A3.block<1,3>(5,3);
171   Eigen::Matrix<double,1,4> b12 = b12_part1 - b12_part2;
172 
173   Eigen::Matrix<double,1,4> b22_part1 = Eigen::Matrix<double,1,4>::Zero();
174   b22_part1.block<1,3>(0,1) = A3.block<1,3>(6,3);
175   Eigen::Matrix<double,1,4> b22_part2 = Eigen::Matrix<double,1,4>::Zero();
176   b22_part2.block<1,3>(0,0) = A3.block<1,3>(7,3);
177   Eigen::Matrix<double,1,4> b22 = b22_part1 - b22_part2;
178 
179   Eigen::Matrix<double,1,4> b32_part1 = Eigen::Matrix<double,1,4>::Zero();
180   b32_part1.block<1,3>(0,1) = A3.block<1,3>(8,3);
181   Eigen::Matrix<double,1,4> b32_part2 = Eigen::Matrix<double,1,4>::Zero();
182   b32_part2.block<1,3>(0,0) = A3.block<1,3>(9,3);
183   Eigen::Matrix<double,1,4> b32 = b32_part1 - b32_part2;
184 
185   Eigen::Matrix<double,1,5> b13_part1 = Eigen::Matrix<double,1,5>::Zero();
186   b13_part1.block<1,4>(0,1) = A3.block<1,4>(4,6);
187   Eigen::Matrix<double,1,5> b13_part2 = Eigen::Matrix<double,1,5>::Zero();
188   b13_part2.block<1,4>(0,0) = A3.block<1,4>(5,6);
189   Eigen::Matrix<double,1,5> b13 = b13_part1 - b13_part2;
190 
191   Eigen::Matrix<double,1,5> b23_part1 = Eigen::Matrix<double,1,5>::Zero();
192   b23_part1.block<1,4>(0,1) = A3.block<1,4>(6,6);
193   Eigen::Matrix<double,1,5> b23_part2 = Eigen::Matrix<double,1,5>::Zero();
194   b23_part2.block<1,4>(0,0) = A3.block<1,4>(7,6);
195   Eigen::Matrix<double,1,5> b23 = b23_part1 - b23_part2;
196 
197   Eigen::Matrix<double,1,5> b33_part1 = Eigen::Matrix<double,1,5>::Zero();
198   b33_part1.block<1,4>(0,1) = A3.block<1,4>(8,6);
199   Eigen::Matrix<double,1,5> b33_part2 = Eigen::Matrix<double,1,5>::Zero();
200   b33_part2.block<1,4>(0,0) = A3.block<1,4>(9,6);
201   Eigen::Matrix<double,1,5> b33 = b33_part1 - b33_part2;
202 
203   Eigen::Matrix<double,1,8> p1_part1;
204   fivept_nister::computeSeventhOrderPolynomial(b23,b12,p1_part1);
205   Eigen::Matrix<double,1,8> p1_part2;
206   fivept_nister::computeSeventhOrderPolynomial(b13,b22,p1_part2);
207   Eigen::Matrix<double,1,8> p1 = p1_part1 - p1_part2;
208   Eigen::Matrix<double,1,8> p2_part1;
209   fivept_nister::computeSeventhOrderPolynomial(b13,b21,p2_part1);
210   Eigen::Matrix<double,1,8> p2_part2;
211   fivept_nister::computeSeventhOrderPolynomial(b23,b11,p2_part2);
212   Eigen::Matrix<double,1,8> p2 = p2_part1 - p2_part2;
213   Eigen::Matrix<double,1,7> p3_part1;
214   fivept_nister::computeSixthOrderPolynomial(b11,b22,p3_part1);
215   Eigen::Matrix<double,1,7> p3_part2;
216   fivept_nister::computeSixthOrderPolynomial(b12,b21,p3_part2);
217   Eigen::Matrix<double,1,7> p3 = p3_part1 - p3_part2;
218 
219   Eigen::Matrix<double,1,11> p_order10_part1;
220   fivept_nister::computeTenthOrderPolynomialFrom73(p1,b31,p_order10_part1);
221   Eigen::Matrix<double,1,11> p_order10_part2;
222   fivept_nister::computeTenthOrderPolynomialFrom73(p2,b32,p_order10_part2);
223   Eigen::Matrix<double,1,11> p_order10_part3;
224   fivept_nister::computeTenthOrderPolynomialFrom64(p3,b33,p_order10_part3);
225   Eigen::Matrix<double,1,11> p_order10 =
226       p_order10_part1 + p_order10_part2 + p_order10_part3;
227 
228   math::Sturm sturmSequence(p_order10);
229   std::vector<double> roots = sturmSequence.findRoots();
230 
231   Eigen::MatrixXd Evec(9,roots.size());
232 
233   for( size_t i = 0; i < roots.size(); i++ )
234   {
235     double z = roots[i];
236     double x = fivept_nister::polyVal(p1,z)/fivept_nister::polyVal(p3,z);
237     double y = fivept_nister::polyVal(p2,z)/fivept_nister::polyVal(p3,z);
238 
239     //pollishing here
240     fivept_nister::pollishCoefficients(A,x,y,z);
241 
242     Evec.col(i) = x*EE.col(0) + y*EE.col(1) + z*EE.col(2) + EE.col(3);
243   }
244 
245   Eigen::MatrixXd norms(1,roots.size());
246   for( size_t c = 0; c < roots.size(); c++ )
247   {
248     norms(0,c) = 0.0;
249 
250     for( int r = 0; r < 9; r++ )
251       norms(0,c) += pow( Evec(r,c), 2 );
252 
253     norms(0,c) = sqrt(norms(0,c));
254   }
255 
256   Eigen::MatrixXd EvecNorms(9,roots.size());
257   for( size_t i = 0; i < 9; i++ )
258     EvecNorms.row(i) = norms;
259 
260   for( size_t r = 0; r < 9; r++ )
261   {
262     for( size_t c = 0; c < roots.size(); c++ )
263       Evec(r,c) = Evec(r,c) / EvecNorms(r,c);
264   }
265 
266   for( size_t c = 0; c < roots.size(); c++ )
267   {
268     essential_t essential;
269 
270     essential.row(0) = Evec.block<3,1>(0,c).transpose();
271     essential.row(1) = Evec.block<3,1>(3,c).transpose();
272     essential.row(2) = Evec.block<3,1>(6,c).transpose();
273 
274     essentials.push_back(essential);
275   }
276 }
277 
278 void
fivept_kneip_main(const Eigen::Matrix<double,3,5> & f1,const Eigen::Matrix<double,3,5> & f2,rotations_t & rotations)279 opengv::relative_pose::modules::fivept_kneip_main(
280     const Eigen::Matrix<double,3,5> & f1,
281     const Eigen::Matrix<double,3,5> & f2,
282     rotations_t & rotations )
283 {
284   Eigen::Matrix<double,66,197> groebnerMatrix =
285       Eigen::Matrix<double,66,197>::Zero();
286   Eigen::Matrix3d temp1 = Eigen::Matrix3d::Zero();
287   Eigen::Matrix3d temp2 = Eigen::Matrix3d::Zero();
288   std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> > c_1;
289   c_1.push_back(temp1);
290   c_1.push_back(temp1);
291   c_1.push_back(temp1);
292   std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> > c_2;
293   c_2.push_back(temp2);
294   c_2.push_back(temp2);
295   c_2.push_back(temp2);
296 
297   int currentRow = 0;
298 
299   for( int firstFeat = 0; firstFeat < 5; firstFeat++ )
300   {
301     for( int secondFeat = firstFeat + 1; secondFeat < 5; secondFeat++ )
302     {
303       temp1 = f1.col(firstFeat)*f1.col(secondFeat).transpose();
304       temp2 = f2.col(firstFeat)*f2.col(secondFeat).transpose();
305 
306       for( int thirdFeat = secondFeat + 1; thirdFeat < 5; thirdFeat++ )
307       {
308         c_1[0] = temp1 * f1(0,thirdFeat);
309         c_1[1] = temp1 * f1(1,thirdFeat);
310         c_1[2] = temp1 * f1(2,thirdFeat);
311         c_2[0] = temp2 * f2(0,thirdFeat);
312         c_2[1] = temp2 * f2(1,thirdFeat);
313         c_2[2] = temp2 * f2(2,thirdFeat);
314 
315         groebnerMatrix.row(currentRow++) =
316             fivept_kneip::initEpncpRowR( c_1, c_2 );
317       }
318     }
319   }
320 
321   fivept_kneip::initMatrix(groebnerMatrix);
322   fivept_kneip::computeBasis(groebnerMatrix);
323 
324   Eigen::Matrix<double,20,20> M = Eigen::Matrix<double,20,20>::Zero();
325   M.block<10,20>(0,0) = -groebnerMatrix.block<10,20>(51,177);
326   M(10,1) = 1.0;
327   M(11,2) = 1.0;
328   M(12,3) = 1.0;
329   M(13,4) = 1.0;
330   M(14,5) = 1.0;
331   M(15,6) = 1.0;
332   M(16,7) = 1.0;
333   M(17,8) = 1.0;
334   M(18,9) = 1.0;
335   M(19,18) = 1.0;
336 
337   Eigen::EigenSolver< Eigen::Matrix<double,20,20> > Eig(M,true);
338   Eigen::Matrix<std::complex<double>,20,1> D = Eig.eigenvalues();
339   Eigen::Matrix<std::complex<double>,20,20> V = Eig.eigenvectors();
340 
341   //Eigen::Matrix<std::complex<double>,9,1> tempVector;
342   rotation_t finalRotation = Eigen::Matrix3d::Zero();
343   for( unsigned int i = 0; i < 20; i++ )
344   {
345     std::complex<double> tempp;
346     tempp = D[i];
347 
348     //check if we have a real solution
349     if( fabs(tempp.imag()) < 0.1 )
350     {
351       tempp = V(18,i)/V(19,i);
352       finalRotation(0,0) = tempp.real();// tempVector[0] = tempp;
353       tempp = V(17,i)/V(19,i);
354       finalRotation(0,1) = tempp.real();// tempVector[1] = tempp;
355       tempp = V(16,i)/V(19,i);
356       finalRotation(0,2) = tempp.real();// tempVector[2] = tempp;
357       tempp = V(15,i)/V(19,i);
358       finalRotation(1,0) = tempp.real();// tempVector[3] = tempp;
359       tempp = V(14,i)/V(19,i);
360       finalRotation(1,1) = tempp.real();// tempVector[4] = tempp;
361       tempp = V(13,i)/V(19,i);
362       finalRotation(1,2) = tempp.real();// tempVector[5] = tempp;
363       tempp = V(12,i)/V(19,i);
364       finalRotation(2,0) = tempp.real();// tempVector[6] = tempp;
365       tempp = V(11,i)/V(19,i);
366       finalRotation(2,1) = tempp.real();// tempVector[7] = tempp;
367       tempp = V(10,i)/V(19,i);
368       finalRotation(2,2) = tempp.real();// tempVector[8] = tempp;
369 
370       double tempNorm = finalRotation.row(1).norm();
371       finalRotation.row(1) = finalRotation.row(1) / tempNorm;
372       tempNorm = finalRotation.row(2).norm();
373       finalRotation.row(2) = finalRotation.row(2) / tempNorm;
374 
375       //check if the normalized rotation matrix has determinant close enough to 1
376       if( fabs( finalRotation.determinant() - 1.0 ) < 0.1 )
377       {
378         Eigen::Matrix3d eval;
379         double totalEval = 0.0;
380         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
381         eval.col(1) = f1.col(1).cross(finalRotation*f2.col(1));
382         eval.col(2) = f1.col(2).cross(finalRotation*f2.col(2));
383         totalEval += fabs(eval.determinant());
384         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
385         eval.col(1) = f1.col(1).cross(finalRotation*f2.col(1));
386         eval.col(2) = f1.col(3).cross(finalRotation*f2.col(3));
387         totalEval += fabs(eval.determinant());
388         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
389         eval.col(1) = f1.col(1).cross(finalRotation*f2.col(1));
390         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
391         totalEval += fabs(eval.determinant());
392         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
393         eval.col(1) = f1.col(2).cross(finalRotation*f2.col(2));
394         eval.col(2) = f1.col(3).cross(finalRotation*f2.col(3));
395         totalEval += fabs(eval.determinant());
396         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
397         eval.col(1) = f1.col(2).cross(finalRotation*f2.col(2));
398         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
399         totalEval += fabs(eval.determinant());
400         eval.col(0) = f1.col(0).cross(finalRotation*f2.col(0));
401         eval.col(1) = f1.col(3).cross(finalRotation*f2.col(3));
402         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
403         totalEval += fabs(eval.determinant());
404         eval.col(0) = f1.col(1).cross(finalRotation*f2.col(1));
405         eval.col(1) = f1.col(2).cross(finalRotation*f2.col(2));
406         eval.col(2) = f1.col(3).cross(finalRotation*f2.col(3));
407         totalEval += fabs(eval.determinant());
408         eval.col(0) = f1.col(1).cross(finalRotation*f2.col(1));
409         eval.col(1) = f1.col(2).cross(finalRotation*f2.col(2));
410         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
411         totalEval += fabs(eval.determinant());
412         eval.col(0) = f1.col(1).cross(finalRotation*f2.col(1));
413         eval.col(1) = f1.col(3).cross(finalRotation*f2.col(3));
414         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
415         totalEval += fabs(eval.determinant());
416         eval.col(0) = f1.col(2).cross(finalRotation*f2.col(2));
417         eval.col(1) = f1.col(3).cross(finalRotation*f2.col(3));
418         eval.col(2) = f1.col(4).cross(finalRotation*f2.col(4));
419         totalEval += fabs(eval.determinant());
420         totalEval += fabs(
421             finalRotation(0,0)*finalRotation(0,0)+
422             finalRotation(0,1)*finalRotation(0,1)+
423             finalRotation(0,2)*finalRotation(0,2)-1);
424         totalEval += fabs(
425             finalRotation(0,0)*finalRotation(1,0)+
426             finalRotation(0,1)*finalRotation(1,1)+
427             finalRotation(0,2)*finalRotation(1,2));
428         totalEval += fabs(
429             finalRotation(0,0)*finalRotation(2,0)+
430             finalRotation(0,1)*finalRotation(2,1)+
431             finalRotation(0,2)*finalRotation(2,2));
432         totalEval += fabs(
433             finalRotation(1,0)*finalRotation(1,0)+
434             finalRotation(1,1)*finalRotation(1,1)+
435             finalRotation(1,2)*finalRotation(1,2)-1);
436         totalEval += fabs(
437             finalRotation(1,0)*finalRotation(2,0)+
438             finalRotation(1,1)*finalRotation(2,1)+
439             finalRotation(1,2)*finalRotation(2,2));
440         totalEval += fabs(
441             finalRotation(2,0)*finalRotation(2,0)+
442             finalRotation(2,1)*finalRotation(2,1)+
443             finalRotation(2,2)*finalRotation(2,2)-1);
444         totalEval += fabs(
445             finalRotation(1,0)*finalRotation(2,1)-
446             finalRotation(2,0)*finalRotation(1,1)-finalRotation(0,2));
447         totalEval += fabs(
448             finalRotation(2,0)*finalRotation(0,1)-
449             finalRotation(0,0)*finalRotation(2,1)-finalRotation(1,2));
450         totalEval += fabs(
451             finalRotation(0,0)*finalRotation(1,1)-
452             finalRotation(1,0)*finalRotation(0,1)-finalRotation(2,2));
453 
454         //check if the initial constraints are fullfilled to a sufficient extend
455         if( totalEval < 0.001 )
456         {
457           Eigen::Matrix<double,3,5> normalVectors;
458           normalVectors.col(0) = f1.col(0).cross(finalRotation * f2.col(0));
459           normalVectors.col(1) = f1.col(1).cross(finalRotation * f2.col(1));
460           normalVectors.col(2) = f1.col(2).cross(finalRotation * f2.col(2));
461           normalVectors.col(3) = f1.col(3).cross(finalRotation * f2.col(3));
462           normalVectors.col(4) = f1.col(4).cross(finalRotation * f2.col(4));
463 
464           Eigen::Vector3d trans01 =
465               normalVectors.col(0).cross(normalVectors.col(1));
466           Eigen::Vector3d trans02 =
467               normalVectors.col(0).cross(normalVectors.col(2));
468           Eigen::Vector3d trans03 =
469               normalVectors.col(0).cross(normalVectors.col(3));
470           Eigen::Vector3d trans04 =
471               normalVectors.col(0).cross(normalVectors.col(4));
472           Eigen::Vector3d trans12 =
473               normalVectors.col(1).cross(normalVectors.col(2));
474           Eigen::Vector3d trans13 =
475               normalVectors.col(1).cross(normalVectors.col(3));
476           Eigen::Vector3d trans14 =
477               normalVectors.col(1).cross(normalVectors.col(4));
478           Eigen::Vector3d trans23 =
479               normalVectors.col(2).cross(normalVectors.col(3));
480           Eigen::Vector3d trans24 =
481               normalVectors.col(2).cross(normalVectors.col(4));
482           Eigen::Vector3d trans34 =
483               normalVectors.col(3).cross(normalVectors.col(4));
484 
485           Eigen::Vector3d tempVector1;
486           Eigen::Vector3d tempVector2;
487 
488           bool positive = true;
489 
490           for( int i = 0; i < 5; i++ )
491           {
492             tempVector1 = trans01.cross( f1.col(i) );
493             tempVector2 = trans01.cross( finalRotation * f2.col(i) );
494             if( tempVector1.dot(tempVector2) < 0 )
495             {
496               positive = false;
497               break;
498             }
499             tempVector1 = trans02.cross( f1.col(i) );
500             tempVector2 = trans02.cross( finalRotation * f2.col(i) );
501             if( tempVector1.dot(tempVector2) < 0 )
502             {
503               positive = false;
504               break;
505             }
506             tempVector1 = trans03.cross( f1.col(i) );
507             tempVector2 = trans03.cross( finalRotation * f2.col(i) );
508             if( tempVector1.dot(tempVector2) < 0 )
509             {
510               positive = false;
511               break;
512             }
513             tempVector1 = trans04.cross( f1.col(i) );
514             tempVector2 = trans04.cross( finalRotation * f2.col(i) );
515             if( tempVector1.dot(tempVector2) < 0 )
516             {
517               positive = false;
518               break;
519             }
520             tempVector1 = trans12.cross( f1.col(i) );
521             tempVector2 = trans12.cross( finalRotation * f2.col(i) );
522             if( tempVector1.dot(tempVector2) < 0 )
523             {
524               positive = false;
525               break;
526             }
527             tempVector1 = trans13.cross( f1.col(i) );
528             tempVector2 = trans13.cross( finalRotation * f2.col(i) );
529             if( tempVector1.dot(tempVector2) < 0 )
530             {
531               positive = false;
532               break;
533             }
534             tempVector1 = trans14.cross( f1.col(i) );
535             tempVector2 = trans14.cross( finalRotation * f2.col(i) );
536             if( tempVector1.dot(tempVector2) < 0 )
537             {
538               positive = false;
539               break;
540             }
541             tempVector1 = trans23.cross( f1.col(i) );
542             tempVector2 = trans23.cross( finalRotation * f2.col(i) );
543             if( tempVector1.dot(tempVector2) < 0 )
544             {
545               positive = false;
546               break;
547             }
548             tempVector1 = trans24.cross( f1.col(i) );
549             tempVector2 = trans24.cross( finalRotation * f2.col(i) );
550             if( tempVector1.dot(tempVector2) < 0 )
551             {
552               positive = false;
553               break;
554             }
555             tempVector1 = trans34.cross( f1.col(i) );
556             tempVector2 = trans34.cross( finalRotation * f2.col(i) );
557             if( tempVector1.dot(tempVector2) < 0 )
558             {
559               positive = false;
560               break;
561             }
562           }
563 
564           //finally, check if the cheiriality constraint is fullfilled to
565           //sufficient extend
566           if( positive )
567             rotations.push_back(finalRotation);
568         }
569       }
570     }
571   }
572 }
573 
574 namespace opengv
575 {
576 namespace relative_pose
577 {
578 namespace modules
579 {
580 
581 struct Eigensolver_step : OptimizationFunctor<double>
582 {
583   const Eigen::Matrix3d & _xxF;
584   const Eigen::Matrix3d & _yyF;
585   const Eigen::Matrix3d & _zzF;
586   const Eigen::Matrix3d & _xyF;
587   const Eigen::Matrix3d & _yzF;
588   const Eigen::Matrix3d & _zxF;
589 
Eigensolver_stepopengv::relative_pose::modules::Eigensolver_step590   Eigensolver_step(
591     const Eigen::Matrix3d & xxF,
592     const Eigen::Matrix3d & yyF,
593     const Eigen::Matrix3d & zzF,
594     const Eigen::Matrix3d & xyF,
595     const Eigen::Matrix3d & yzF,
596     const Eigen::Matrix3d & zxF ) :
597     OptimizationFunctor<double>(3,3),
598     _xxF(xxF),_yyF(yyF),_zzF(zzF),_xyF(xyF),_yzF(yzF),_zxF(zxF) {}
599 
operator ()opengv::relative_pose::modules::Eigensolver_step600   int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
601   {
602     cayley_t cayley = x;
603     Eigen::Matrix<double,1,3> jacobian;
604     eigensolver::getSmallestEVwithJacobian(
605         _xxF,_yyF,_zzF,_xyF,_yzF,_zxF,cayley,jacobian);
606 
607     fvec[0] = jacobian(0,0);
608     fvec[1] = jacobian(0,1);
609     fvec[2] = jacobian(0,2);
610     return 0;
611   }
612 };
613 
614 }
615 }
616 }
617 
618 struct myPair {
619   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
620 
621   Eigen::Vector3d first;
622   double second;
623 };
624 
operator <(const myPair & p1,const myPair & p2)625 bool operator<( const myPair & p1, const myPair & p2 ) {
626   if( p1.second > p2.second )
627     return true;
628   return false;
629 }
630 
631 void
eigensolver_main(const Eigen::Matrix3d & xxF,const Eigen::Matrix3d & yyF,const Eigen::Matrix3d & zzF,const Eigen::Matrix3d & xyF,const Eigen::Matrix3d & yzF,const Eigen::Matrix3d & zxF,eigensolverOutput_t & output)632 opengv::relative_pose::modules::eigensolver_main(
633   const Eigen::Matrix3d & xxF,
634   const Eigen::Matrix3d & yyF,
635   const Eigen::Matrix3d & zzF,
636   const Eigen::Matrix3d & xyF,
637   const Eigen::Matrix3d & yzF,
638   const Eigen::Matrix3d & zxF,
639   eigensolverOutput_t & output )
640 {
641   const int n=3;
642   VectorXd x(n);
643 
644   x = math::rot2cayley(output.rotation);
645   Eigensolver_step functor(xxF,yyF,zzF,xyF,yzF,zxF );
646   NumericalDiff<Eigensolver_step> numDiff(functor);
647   LevenbergMarquardt< NumericalDiff<Eigensolver_step> > lm(numDiff);
648 
649   lm.resetParameters();
650   lm.parameters.ftol = 0.00005;
651   lm.parameters.xtol = 1.E1*NumTraits<double>::epsilon();
652   lm.parameters.maxfev = 100;
653   lm.minimize(x);
654 
655   cayley_t cayley = x;
656   rotation_t R = math::cayley2rot(cayley);
657 
658   Eigen::Matrix3d M = eigensolver::composeM(xxF,yyF,zzF,xyF,yzF,zxF,cayley);
659   Eigen::EigenSolver< Eigen::Matrix3d > Eig(M,true);
660   Eigen::Matrix<std::complex<double>,3,1> D_complex = Eig.eigenvalues();
661   Eigen::Matrix<std::complex<double>,3,3> V_complex = Eig.eigenvectors();
662   eigenvalues_t D;
663   eigenvectors_t V;
664 
665   std::vector< myPair > pairs;
666   for(size_t i = 0; i < 3; i++) {
667     myPair newPair;
668     newPair.second = D_complex[i].real();
669     for(size_t j = 0; j < 3; j++)
670       newPair.first(j,0) = V_complex(j,i).real();
671     pairs.push_back(newPair);
672   }
673   std::sort(pairs.begin(),pairs.end());
674   for(size_t i = 0; i < 3; i++) {
675     D[i] = pairs[i].second;
676     V.col(i) = pairs[i].first;
677   }
678 
679   double translationMagnitude = sqrt(pow(D[0],2) + pow(D[1],2));
680   translation_t t = translationMagnitude * V.col(2);
681 
682   output.translation = t;
683   output.rotation = R;
684   output.eigenvalues = D;
685   output.eigenvectors = V;
686 
687 }
688 
689 void
sixpt_main(Eigen::Matrix<double,6,6> & L1,Eigen::Matrix<double,6,6> & L2,rotations_t & solutions)690 opengv::relative_pose::modules::sixpt_main(
691   Eigen::Matrix<double,6,6> & L1,
692   Eigen::Matrix<double,6,6> & L2,
693   rotations_t & solutions)
694 {
695 
696   //create vectors of Pluecker coordinates
697   std::vector< Eigen::Matrix<double,6,1>, Eigen::aligned_allocator<Eigen::Matrix<double,6,1> > > L1vec;
698   std::vector< Eigen::Matrix<double,6,1>, Eigen::aligned_allocator<Eigen::Matrix<double,6,1> > > L2vec;
699   for(int i = 0; i < 6; i++ )
700   {
701     L1vec.push_back( L1.col(i) );
702     L2vec.push_back( L2.col(i) );
703   }
704 
705   //setup the action matrix
706   Eigen::Matrix<double,64,64> Action = Eigen::Matrix<double,64,64>::Zero();
707   sixpt::setupAction( L1vec, L2vec, Action );
708 
709   //finally eigen-decompose the action-matrix and obtain the solutions
710   Eigen::EigenSolver< Eigen::Matrix<double,64,64> > Eig(Action,true);
711   Eigen::Matrix<std::complex<double>,64,64> EV = Eig.eigenvectors();
712 
713   solutions.reserve(64);
714   for( int c = 0; c < 64; c++ )
715   {
716     cayley_t solution;
717     for( int r = 0; r < 3; r++ )
718     {
719       std::complex<double> temp = EV(60+r,c)/EV(63,c);
720       solution[r] = temp.real();
721     }
722 
723     solutions.push_back(math::cayley2rot(solution).transpose());
724   }
725 }
726 
727 namespace opengv
728 {
729 namespace relative_pose
730 {
731 namespace modules
732 {
733 
734 struct Ge_step : OptimizationFunctor<double>
735 {
736   const Eigen::Matrix3d & _xxF;
737   const Eigen::Matrix3d & _yyF;
738   const Eigen::Matrix3d & _zzF;
739   const Eigen::Matrix3d & _xyF;
740   const Eigen::Matrix3d & _yzF;
741   const Eigen::Matrix3d & _zxF;
742   const Eigen::Matrix<double,3,9> & _x1P;
743   const Eigen::Matrix<double,3,9> & _y1P;
744   const Eigen::Matrix<double,3,9> & _z1P;
745   const Eigen::Matrix<double,3,9> & _x2P;
746   const Eigen::Matrix<double,3,9> & _y2P;
747   const Eigen::Matrix<double,3,9> & _z2P;
748   const Eigen::Matrix<double,9,9> & _m11P;
749   const Eigen::Matrix<double,9,9> & _m12P;
750   const Eigen::Matrix<double,9,9> & _m22P;
751 
Ge_stepopengv::relative_pose::modules::Ge_step752   Ge_step(
753     const Eigen::Matrix3d & xxF,
754     const Eigen::Matrix3d & yyF,
755     const Eigen::Matrix3d & zzF,
756     const Eigen::Matrix3d & xyF,
757     const Eigen::Matrix3d & yzF,
758     const Eigen::Matrix3d & zxF,
759     const Eigen::Matrix<double,3,9> & x1P,
760     const Eigen::Matrix<double,3,9> & y1P,
761     const Eigen::Matrix<double,3,9> & z1P,
762     const Eigen::Matrix<double,3,9> & x2P,
763     const Eigen::Matrix<double,3,9> & y2P,
764     const Eigen::Matrix<double,3,9> & z2P,
765     const Eigen::Matrix<double,9,9> & m11P,
766     const Eigen::Matrix<double,9,9> & m12P,
767     const Eigen::Matrix<double,9,9> & m22P ) :
768     OptimizationFunctor<double>(3,3),
769     _xxF(xxF),_yyF(yyF),_zzF(zzF),_xyF(xyF),_yzF(yzF),_zxF(zxF),
770     _x1P(x1P),_y1P(y1P),_z1P(z1P),_x2P(x2P),_y2P(y2P),_z2P(z2P),
771     _m11P(m11P),_m12P(m12P),_m22P(m22P) {}
772 
operator ()opengv::relative_pose::modules::Ge_step773   int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
774   {
775     cayley_t cayley = x;
776     Eigen::Matrix<double,1,3> jacobian;
777     ge::getCostWithJacobian(
778         _xxF,_yyF,_zzF,_xyF,_yzF,_zxF,
779         _x1P,_y1P,_z1P,_x2P,_y2P,_z2P,_m11P,_m12P,_m22P,cayley,jacobian,1);
780 
781     fvec[0] = jacobian(0,0);
782     fvec[1] = jacobian(0,1);
783     fvec[2] = jacobian(0,2);
784 
785     return 0;
786   }
787 };
788 
789 }
790 }
791 }
792 
793 struct myPair_ge {
794   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
795 
796   Eigen::Vector4d first;
797   double second;
798 };
799 
operator <(const myPair_ge & p1,const myPair_ge & p2)800 bool operator<( const myPair_ge & p1, const myPair_ge & p2 ) {
801   if( p1.second > p2.second )
802     return true;
803   return false;
804 }
805 
806 void
ge_main(const Eigen::Matrix3d & xxF,const Eigen::Matrix3d & yyF,const Eigen::Matrix3d & zzF,const Eigen::Matrix3d & xyF,const Eigen::Matrix3d & yzF,const Eigen::Matrix3d & zxF,const Eigen::Matrix<double,3,9> & x1P,const Eigen::Matrix<double,3,9> & y1P,const Eigen::Matrix<double,3,9> & z1P,const Eigen::Matrix<double,3,9> & x2P,const Eigen::Matrix<double,3,9> & y2P,const Eigen::Matrix<double,3,9> & z2P,const Eigen::Matrix<double,9,9> & m11P,const Eigen::Matrix<double,9,9> & m12P,const Eigen::Matrix<double,9,9> & m22P,const cayley_t & startingPoint,geOutput_t & output)807 opengv::relative_pose::modules::ge_main(
808     const Eigen::Matrix3d & xxF,
809     const Eigen::Matrix3d & yyF,
810     const Eigen::Matrix3d & zzF,
811     const Eigen::Matrix3d & xyF,
812     const Eigen::Matrix3d & yzF,
813     const Eigen::Matrix3d & zxF,
814     const Eigen::Matrix<double,3,9> & x1P,
815     const Eigen::Matrix<double,3,9> & y1P,
816     const Eigen::Matrix<double,3,9> & z1P,
817     const Eigen::Matrix<double,3,9> & x2P,
818     const Eigen::Matrix<double,3,9> & y2P,
819     const Eigen::Matrix<double,3,9> & z2P,
820     const Eigen::Matrix<double,9,9> & m11P,
821     const Eigen::Matrix<double,9,9> & m12P,
822     const Eigen::Matrix<double,9,9> & m22P,
823     const cayley_t & startingPoint,
824     geOutput_t & output )
825 {
826   //this one doesn't work, probably because of double numerical differentiation
827   //use ge_main2, which is an implementation of gradient descent
828   const int n=3;
829   VectorXd x(n);
830 
831   x = startingPoint;
832   Ge_step functor(xxF,yyF,zzF,xyF,yzF,zxF,
833       x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P);
834   NumericalDiff<Ge_step> numDiff(functor);
835   LevenbergMarquardt< NumericalDiff<Ge_step> > lm(numDiff);
836 
837   lm.resetParameters();
838   lm.parameters.ftol = 0.000001;//1.E1*NumTraits<double>::epsilon();
839   lm.parameters.xtol = 1.E1*NumTraits<double>::epsilon();
840   lm.parameters.maxfev = 100;
841   lm.minimize(x);
842 
843   cayley_t cayley = x;
844   rotation_t R = math::cayley2rot(cayley);
845 
846   Eigen::Matrix4d G = ge::composeG(xxF,yyF,zzF,xyF,yzF,zxF,
847       x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley);
848 
849   Eigen::EigenSolver< Eigen::Matrix4d > Eig(G,true);
850   Eigen::Matrix<std::complex<double>,4,1> D_complex = Eig.eigenvalues();
851   Eigen::Matrix<std::complex<double>,4,4> V_complex = Eig.eigenvectors();
852   Eigen::Vector4d D;
853   Eigen::Matrix4d V;
854 
855   std::vector< myPair_ge > pairs;
856   for(size_t i = 0; i < 4; i++) {
857     myPair_ge newPair;
858     newPair.second = D_complex[i].real();
859     for(size_t j = 0; j < 4; j++)
860       newPair.first(j,0) = V_complex(j,i).real();
861     pairs.push_back(newPair);
862   }
863   std::sort(pairs.begin(),pairs.end());
864   for(size_t i = 0; i < 4; i++) {
865     D[i] = pairs[i].second;
866     V.col(i) = pairs[i].first;
867   }
868 
869   double factor = V(3,3);
870   Eigen::Vector4d t = (1.0/factor) * V.col(3);
871 
872   output.translation = t;
873   output.rotation = R;
874   output.eigenvalues = D;
875   output.eigenvectors = V;
876 }
877 
878 void
ge_main2(const Eigen::Matrix3d & xxF,const Eigen::Matrix3d & yyF,const Eigen::Matrix3d & zzF,const Eigen::Matrix3d & xyF,const Eigen::Matrix3d & yzF,const Eigen::Matrix3d & zxF,const Eigen::Matrix<double,3,9> & x1P,const Eigen::Matrix<double,3,9> & y1P,const Eigen::Matrix<double,3,9> & z1P,const Eigen::Matrix<double,3,9> & x2P,const Eigen::Matrix<double,3,9> & y2P,const Eigen::Matrix<double,3,9> & z2P,const Eigen::Matrix<double,9,9> & m11P,const Eigen::Matrix<double,9,9> & m12P,const Eigen::Matrix<double,9,9> & m22P,const cayley_t & startingPoint,geOutput_t & output)879 opengv::relative_pose::modules::ge_main2(
880     const Eigen::Matrix3d & xxF,
881     const Eigen::Matrix3d & yyF,
882     const Eigen::Matrix3d & zzF,
883     const Eigen::Matrix3d & xyF,
884     const Eigen::Matrix3d & yzF,
885     const Eigen::Matrix3d & zxF,
886     const Eigen::Matrix<double,3,9> & x1P,
887     const Eigen::Matrix<double,3,9> & y1P,
888     const Eigen::Matrix<double,3,9> & z1P,
889     const Eigen::Matrix<double,3,9> & x2P,
890     const Eigen::Matrix<double,3,9> & y2P,
891     const Eigen::Matrix<double,3,9> & z2P,
892     const Eigen::Matrix<double,9,9> & m11P,
893     const Eigen::Matrix<double,9,9> & m12P,
894     const Eigen::Matrix<double,9,9> & m22P,
895     const cayley_t & startingPoint,
896     geOutput_t & output )
897 {
898   //todo: the optimization strategy is something that can possibly be improved:
899   //-one idea is to check the gradient at the new sampling point, if that derives
900   // too much, we have to stop
901   //-another idea consists of having linear change of lambda, instead of exponential (safer, but slower)
902 
903   double lambda = 0.01;
904   double maxLambda = 0.08;
905   double modifier = 2.0;
906   int maxIterations = 50;
907   double min_xtol = 0.00001;
908   bool disablingIncrements = true;
909   bool print = false;
910 
911   cayley_t cayley;
912 
913   double disturbanceAmplitude = 0.3;
914   bool found = false;
915   int randomTrialCount = 0;
916 
917   while( !found && randomTrialCount < 5 )
918   {
919     if(randomTrialCount > 2)
920       disturbanceAmplitude = 0.6;
921 
922     if( randomTrialCount == 0 )
923       cayley = startingPoint;
924     else
925     {
926       cayley = startingPoint;
927       Eigen::Vector3d disturbance;
928       disturbance[0] = (((double) rand())/ ((double) RAND_MAX)-0.5)*2.0*disturbanceAmplitude;
929       disturbance[1] = (((double) rand())/ ((double) RAND_MAX)-0.5)*2.0*disturbanceAmplitude;
930       disturbance[2] = (((double) rand())/ ((double) RAND_MAX)-0.5)*2.0*disturbanceAmplitude;
931       cayley += disturbance;
932     }
933 
934     lambda = 0.01;
935     int iterations = 0;
936     double smallestEV = ge::getCost(xxF,yyF,zzF,xyF,yzF,zxF,
937         x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley,1);
938 
939     while( iterations < maxIterations )
940     {
941       Eigen::Matrix<double,1,3> jacobian;
942       ge::getQuickJacobian(xxF,yyF,zzF,xyF,yzF,zxF,
943           x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley,smallestEV,jacobian,1);
944 
945       double norm = sqrt(pow(jacobian[0],2.0) + pow(jacobian[1],2.0) + pow(jacobian[2],2.0));
946       cayley_t normalizedJacobian = (1/norm) * jacobian.transpose();
947 
948       cayley_t samplingPoint = cayley - lambda * normalizedJacobian;
949       double samplingEV = ge::getCost(xxF,yyF,zzF,xyF,yzF,zxF,
950           x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,samplingPoint,1);
951 
952       if(print)
953       {
954         std::cout << iterations << ": " << samplingPoint.transpose();
955         std::cout << " lambda: " << lambda << " EV: " << samplingEV << std::endl;
956       }
957 
958       if( iterations == 0 || !disablingIncrements )
959       {
960         while( samplingEV < smallestEV )
961         {
962           smallestEV = samplingEV;
963           if( lambda * modifier > maxLambda )
964             break;
965           lambda *= modifier;
966           samplingPoint = cayley - lambda * normalizedJacobian;
967           samplingEV = ge::getCost(xxF,yyF,zzF,xyF,yzF,zxF,
968               x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,samplingPoint,1);
969 
970           if(print)
971           {
972             std::cout << iterations << ": " << samplingPoint.transpose();
973             std::cout << " lambda: " << lambda << " EV: " << samplingEV << std::endl;
974           }
975         }
976       }
977 
978       while( samplingEV > smallestEV )
979       {
980         lambda /= modifier;
981         samplingPoint = cayley - lambda * normalizedJacobian;
982         samplingEV = ge::getCost(xxF,yyF,zzF,xyF,yzF,zxF,
983             x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,samplingPoint,1);
984 
985         if(print)
986         {
987           std::cout << iterations << ": " << samplingPoint.transpose();
988           std::cout << " lambda: " << lambda << " EV: " << samplingEV << std::endl;
989         }
990       }
991 
992       //apply update
993       cayley = samplingPoint;
994       smallestEV = samplingEV;
995 
996       //stopping condition (check if the update was too small)
997       if( lambda < min_xtol )
998         break;
999 
1000       iterations++;
1001     }
1002 
1003     //try to see if we can robustly identify each time we enter up in the wrong minimum
1004     if( cayley.norm() < 0.01 )
1005     {
1006       //we are close to the origin, test the EV 2
1007       double ev2 = ge::getCost(xxF,yyF,zzF,xyF,yzF,zxF,
1008             x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley,0);
1009       if( ev2 > 0.001 )
1010         randomTrialCount++;
1011       else
1012         found = true;
1013     }
1014     else
1015       found = true;
1016   }
1017 
1018   Eigen::Matrix4d G = ge::composeG(xxF,yyF,zzF,xyF,yzF,zxF,
1019       x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley);
1020 
1021   Eigen::EigenSolver< Eigen::Matrix4d > Eig(G,true);
1022   Eigen::Matrix<std::complex<double>,4,1> D_complex = Eig.eigenvalues();
1023   Eigen::Matrix<std::complex<double>,4,4> V_complex = Eig.eigenvectors();
1024   Eigen::Vector4d D;
1025   Eigen::Matrix4d V;
1026 
1027   std::vector< myPair_ge > pairs;
1028   for(size_t i = 0; i < 4; i++) {
1029     myPair_ge newPair;
1030     newPair.second = D_complex[i].real();
1031     for(size_t j = 0; j < 4; j++)
1032       newPair.first(j,0) = V_complex(j,i).real();
1033     pairs.push_back(newPair);
1034   }
1035   std::sort(pairs.begin(),pairs.end());
1036   for(size_t i = 0; i < 4; i++) {
1037     D[i] = pairs[i].second;
1038     V.col(i) = pairs[i].first;
1039   }
1040 
1041   double factor = V(3,3);
1042   Eigen::Vector4d t = (1.0/factor) * V.col(3);
1043 
1044   output.translation = t;
1045   output.rotation = math::cayley2rot(cayley);
1046   output.eigenvalues = D;
1047   output.eigenvectors = V;
1048 }
1049 
1050 void
ge_plot(const Eigen::Matrix3d & xxF,const Eigen::Matrix3d & yyF,const Eigen::Matrix3d & zzF,const Eigen::Matrix3d & xyF,const Eigen::Matrix3d & yzF,const Eigen::Matrix3d & zxF,const Eigen::Matrix<double,3,9> & x1P,const Eigen::Matrix<double,3,9> & y1P,const Eigen::Matrix<double,3,9> & z1P,const Eigen::Matrix<double,3,9> & x2P,const Eigen::Matrix<double,3,9> & y2P,const Eigen::Matrix<double,3,9> & z2P,const Eigen::Matrix<double,9,9> & m11P,const Eigen::Matrix<double,9,9> & m12P,const Eigen::Matrix<double,9,9> & m22P,geOutput_t & output)1051 opengv::relative_pose::modules::ge_plot(
1052     const Eigen::Matrix3d & xxF,
1053     const Eigen::Matrix3d & yyF,
1054     const Eigen::Matrix3d & zzF,
1055     const Eigen::Matrix3d & xyF,
1056     const Eigen::Matrix3d & yzF,
1057     const Eigen::Matrix3d & zxF,
1058     const Eigen::Matrix<double,3,9> & x1P,
1059     const Eigen::Matrix<double,3,9> & y1P,
1060     const Eigen::Matrix<double,3,9> & z1P,
1061     const Eigen::Matrix<double,3,9> & x2P,
1062     const Eigen::Matrix<double,3,9> & y2P,
1063     const Eigen::Matrix<double,3,9> & z2P,
1064     const Eigen::Matrix<double,9,9> & m11P,
1065     const Eigen::Matrix<double,9,9> & m12P,
1066     const Eigen::Matrix<double,9,9> & m22P,
1067     geOutput_t & output )
1068 {
1069   cayley_t cayley = math::rot2cayley(output.rotation);
1070 
1071   ge::getEV(xxF,yyF,zzF,xyF,yzF,zxF,
1072       x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley,output.eigenvalues);
1073 
1074   output.eigenvectors = ge::composeG(xxF,yyF,zzF,xyF,yzF,zxF,
1075       x1P,y1P,z1P,x2P,y2P,z2P,m11P,m12P,m22P,cayley);
1076 }
1077