Visual Servoing Platform  version 3.1.0
vpPoseLagrange.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Pose computation.
33  *
34  * Authors:
35  * Eric Marchand
36  * Francois Chaumette
37  *
38  *****************************************************************************/
39 
40 #include <visp3/vision/vpPose.h>
41 
42 #define DEBUG_LEVEL1 0
43 #define DEBUG_LEVEL2 0
44 
45 /**********************************************************************/
46 /* FONCTION : CalculTranslation */
47 /* ROLE : Calcul de la translation entre la */
48 /* camera et l'outil connaissant la */
49 /* rotation */
50 /**********************************************************************/
51 
52 static void calculTranslation(vpMatrix &a, vpMatrix &b, unsigned int nl, unsigned int nc1, unsigned int nc3,
53  vpColVector &x1, vpColVector &x2)
54 {
55 
56  try {
57  unsigned int i, j;
58 
59  vpMatrix ct(3, nl);
60  for (i = 0; i < 3; i++) {
61  for (j = 0; j < nl; j++)
62  ct[i][j] = b[j][i + nc3];
63  }
64 
65  vpMatrix c;
66  c = ct.t();
67 
68  vpMatrix ctc;
69  ctc = ct * c;
70 
71  vpMatrix ctc1; // (C^T C)^(-1)
72  ctc1 = ctc.inverseByLU();
73 
74  vpMatrix cta;
75  vpMatrix ctb;
76  cta = ct * a; /* C^T A */
77  ctb = ct * b; /* C^T B */
78 
79 #if (DEBUG_LEVEL2)
80  {
81  std::cout << "ctc " << std::endl << ctc;
82  std::cout << "cta " << std::endl << cta;
83  std::cout << "ctb " << std::endl << ctb;
84  }
85 #endif
86 
87  vpColVector X2(nc3);
88  vpMatrix CTB(nc1, nc3);
89  for (i = 0; i < nc1; i++) {
90  for (j = 0; j < nc3; j++)
91  CTB[i][j] = ctb[i][j];
92  }
93 
94  for (j = 0; j < nc3; j++)
95  X2[j] = x2[j];
96 
97  vpColVector sv; // C^T A X1 + C^T B X2)
98  sv = cta * x1 + CTB * X2; // C^T A X1 + C^T B X2)
99 
100 #if (DEBUG_LEVEL2)
101  std::cout << "sv " << sv.t();
102 #endif
103 
104  vpColVector X3; /* X3 = - (C^T C )^{-1} C^T (A X1 + B X2) */
105  X3 = -ctc1 * sv;
106 
107 #if (DEBUG_LEVEL2)
108  std::cout << "x3 " << X3.t();
109 #endif
110 
111  for (i = 0; i < nc1; i++)
112  x2[i + nc3] = X3[i];
113  } catch (...) {
114 
115  // en fait il y a des dizaines de raisons qui font que cette fonction
116  // rende une erreur (matrice pas inversible, pb de memoire etc...)
117  vpERROR_TRACE(" ");
118  throw;
119  }
120 }
121 
122 //*********************************************************************
123 // FONCTION LAGRANGE :
124 // -------------------
125 // Resolution d'un systeme lineaire de la forme A x1 + B x2 = 0
126 // sous la contrainte || x1 || = 1
127 // ou A est de dimension nl x nc1 et B nl x nc2
128 //*********************************************************************
129 
130 //#define EPS 1.e-5
131 
132 static void lagrange(vpMatrix &a, vpMatrix &b, vpColVector &x1, vpColVector &x2)
133 {
134 #if (DEBUG_LEVEL1)
135  std::cout << "begin (CLagrange.cc)Lagrange(...) " << std::endl;
136 #endif
137 
138  try {
139  unsigned int i, imin;
140 
141  vpMatrix ata; // A^T A
142  ata = a.t() * a;
143  vpMatrix btb; // B^T B
144  btb = b.t() * b;
145 
146  vpMatrix bta; // B^T A
147  bta = b.t() * a;
148 
149  vpMatrix btb1; // (B^T B)^(-1)
150 
151 /* Warning:
152  when using btb.inverseByLU() that call cv::inv(cv::DECOMP_LU) with
153  OpenCV 3.1.0 and 3.2.0 we notice that OpenCV is not able to compute the
154  inverse of the following matrix:
155 
156  btb[9,9]=
157  0.015925 0.0 0.0030866 0.00035 0.0 0.000041 0.105
158  0.0 0.0346242 0.0 0.015925 -0.0050979 0.0 0.00035
159  -0.000063 0.0 0.105 -0.0637464 0.0030866 -0.0050979 0.0032301
160  0.000041 -0.000063 0.000016 0.0346242 -0.0637464 0.0311185 0.00035
161  0.0 0.000041 0.0001 0.0 0.000012 0.01 0.0
162  0.0011594 0.0 0.00035 -0.000063 0.0 0.0001 -0.000018
163  0.0 0.01 -0.0018040 0.000041 -0.000063 0.000016 0.000012
164  -0.000018 0.000005 0.0011594 -0.0018040 0.0004599 0.105 0.0
165  0.0346242 0.01 0.0 0.0011594 5.0 0.0 0.13287
166  0.0 0.105 -0.0637464 0.0 0.01 -0.0018040 0.0
167  5.0 -0.731499 0.0346242 -0.0637464 0.0311185 0.0011594 -0.0018040
168  0.0004599 0.13287 -0.731499 0.454006
169 
170  That's why instead of using inverseByLU() we are now using pseudoInverse()
171  */
172 #if 0
173  if (b.getRows() >= b.getCols()) {
174  btb1 = btb.inverseByLU();
175  }
176  else {
177  btb1 = btb.pseudoInverse();
178  }
179 #else
180  btb1 = btb.pseudoInverse();
181 #endif
182 
183 #if (DEBUG_LEVEL1)
184  {
185  std::cout << " BTB1 * BTB : " << std::endl << btb1 * btb << std::endl;
186  std::cout << " BTB * BTB1 : " << std::endl << btb * btb1 << std::endl;
187  }
188 #endif
189 
190  vpMatrix r; // (B^T B)^(-1) B^T A
191  r = btb1 * bta;
192 
193  vpMatrix e; // - A^T B (B^T B)^(-1) B^T A
194  e = -(a.t() * b) * r;
195 
196  e += ata; // calcul E = A^T A - A^T B (B^T B)^(-1) B^T A
197 
198 #if (DEBUG_LEVEL1)
199  {
200  std::cout << " E :" << std::endl << e << std::endl;
201  }
202 #endif
203 
204  // vpColVector sv ;
205  // vpMatrix v ;
206  e.svd(x1, ata); // destructif sur e
207  // calcul du vecteur propre de E correspondant a la valeur propre min.
208  /* calcul de SVmax */
209  imin = 0;
210  // FC : Pourquoi calculer SVmax ??????
211  // double svm = 0.0;
212  // for (i=0;i<x1.getRows();i++)
213  // {
214  // if (x1[i] > svm) { svm = x1[i]; imin = i; }
215  // }
216  // svm *= EPS; /* pour le rang */
217 
218  for (i = 0; i < x1.getRows(); i++)
219  if (x1[i] < x1[imin])
220  imin = i;
221 
222 #if (DEBUG_LEVEL1)
223  {
224  printf("SV(E) : %.15lf %.15lf %.15lf\n", x1[0], x1[1], x1[2]);
225  std::cout << " i_min " << imin << std::endl;
226  }
227 #endif
228  for (i = 0; i < x1.getRows(); i++)
229  x1[i] = ata[i][imin];
230 
231  x2 = -(r * x1); // X_2 = - (B^T B)^(-1) B^T A X_1
232 
233 #if (DEBUG_LEVEL1)
234  {
235  std::cout << " X1 : " << x1.t() << std::endl;
236  std::cout << " V : " << std::endl << ata << std::endl;
237  }
238 #endif
239  } catch (...) {
240  vpERROR_TRACE(" ");
241  throw;
242  }
243 #if (DEBUG_LEVEL1)
244  std::cout << "end (CLagrange.cc)Lagrange(...) " << std::endl;
245 #endif
246 }
247 
248 //#undef EPS
249 
260 void vpPose::poseLagrangePlan(vpHomogeneousMatrix &cMo, const int coplanar_plane_type)
261 {
262 
263 #if (DEBUG_LEVEL1)
264  std::cout << "begin vpPose::PoseLagrange(...) " << std::endl;
265 #endif
266  try {
267  double s;
268  unsigned int i;
269 
270  unsigned int k = 0;
271  unsigned int nl = npt * 2;
272 
273  vpMatrix a(nl, 3);
274  vpMatrix b(nl, 6);
275  vpPoint P;
276  i = 0;
277 
278  if (coplanar_plane_type == 1) { // plane ax=d
279  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
280  P = *it;
281  a[k][0] = -P.get_oY();
282  a[k][1] = 0.0;
283  a[k][2] = P.get_oY() * P.get_x();
284 
285  a[k + 1][0] = 0.0;
286  a[k + 1][1] = -P.get_oY();
287  a[k + 1][2] = P.get_oY() * P.get_y();
288 
289  b[k][0] = -P.get_oZ();
290  b[k][1] = 0.0;
291  b[k][2] = P.get_oZ() * P.get_x();
292  b[k][3] = -1.0;
293  b[k][4] = 0.0;
294  b[k][5] = P.get_x();
295 
296  b[k + 1][0] = 0.0;
297  b[k + 1][1] = -P.get_oZ();
298  b[k + 1][2] = P.get_oZ() * P.get_y();
299  b[k + 1][3] = 0.0;
300  b[k + 1][4] = -1.0;
301  b[k + 1][5] = P.get_y();
302 
303  k += 2;
304  }
305 
306  } else if (coplanar_plane_type == 2) { // plane by=d
307  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
308  P = *it;
309  a[k][0] = -P.get_oX();
310  a[k][1] = 0.0;
311  a[k][2] = P.get_oX() * P.get_x();
312 
313  a[k + 1][0] = 0.0;
314  a[k + 1][1] = -P.get_oX();
315  a[k + 1][2] = P.get_oX() * P.get_y();
316 
317  b[k][0] = -P.get_oZ();
318  b[k][1] = 0.0;
319  b[k][2] = P.get_oZ() * P.get_x();
320  b[k][3] = -1.0;
321  b[k][4] = 0.0;
322  b[k][5] = P.get_x();
323 
324  b[k + 1][0] = 0.0;
325  b[k + 1][1] = -P.get_oZ();
326  b[k + 1][2] = P.get_oZ() * P.get_y();
327  b[k + 1][3] = 0.0;
328  b[k + 1][4] = -1.0;
329  b[k + 1][5] = P.get_y();
330 
331  k += 2;
332  }
333 
334  } else { // plane cz=d or any other
335 
336  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
337  P = *it;
338  a[k][0] = -P.get_oX();
339  a[k][1] = 0.0;
340  a[k][2] = P.get_oX() * P.get_x();
341 
342  a[k + 1][0] = 0.0;
343  a[k + 1][1] = -P.get_oX();
344  a[k + 1][2] = P.get_oX() * P.get_y();
345 
346  b[k][0] = -P.get_oY();
347  b[k][1] = 0.0;
348  b[k][2] = P.get_oY() * P.get_x();
349  b[k][3] = -1.0;
350  b[k][4] = 0.0;
351  b[k][5] = P.get_x();
352 
353  b[k + 1][0] = 0.0;
354  b[k + 1][1] = -P.get_oY();
355  b[k + 1][2] = P.get_oY() * P.get_y();
356  b[k + 1][3] = 0.0;
357  b[k + 1][4] = -1.0;
358  b[k + 1][5] = P.get_y();
359 
360  k += 2;
361  }
362  }
363  vpColVector X1(3);
364  vpColVector X2(6);
365 
366 #if (DEBUG_LEVEL2)
367  {
368  std::cout << "a " << a << std::endl;
369  std::cout << "b " << b << std::endl;
370  }
371 #endif
372 
373  lagrange(a, b, X1, X2);
374 
375 #if (DEBUG_LEVEL2)
376  {
377  std::cout << "ax1+bx2 (devrait etre 0) " << (a * X1 + b * X2).t() << std::endl;
378  std::cout << "norme X1 " << X1.sumSquare() << std::endl;
379  ;
380  }
381 #endif
382 
383  if (X2[5] < 0.0) { /* car Zo > 0 */
384  for (i = 0; i < 3; i++)
385  X1[i] = -X1[i];
386  for (i = 0; i < 6; i++)
387  X2[i] = -X2[i];
388  }
389  s = 0.0;
390  for (i = 0; i < 3; i++) {
391  s += (X1[i] * X2[i]);
392  }
393  for (i = 0; i < 3; i++) {
394  X2[i] -= (s * X1[i]);
395  } /* X1^T X2 = 0 */
396 
397  // s = 0.0;
398  // for (i=0;i<3;i++) {s += (X2[i]*X2[i]);}
399  s = X2[0] * X2[0] + X2[1] * X2[1] + X2[2] * X2[2]; // To avoid a Coverity copy/past error
400 
401  if (s < 1e-10) {
402  // std::cout << "Points that produce an error: " << std::endl;
403  // for (std::list<vpPoint>::const_iterator it = listP.begin(); it
404  // != listP.end(); ++it)
405  // {
406  // std::cout << "P: " << (*it).get_x() << " " << (*it).get_y() <<
407  // " "
408  // << (*it).get_oX() << " " << (*it).get_oY() << " " <<
409  // (*it).get_oZ() << std::endl;
410  // }
411  throw(vpException(vpException::divideByZeroError, "Division by zero in Lagrange pose computation "
412  "(planar plane case)"));
413  }
414 
415  s = 1.0 / sqrt(s);
416  for (i = 0; i < 3; i++) {
417  X2[i] *= s;
418  } /* X2^T X2 = 1 */
419 
420  calculTranslation(a, b, nl, 3, 3, X1, X2);
421 
422  // if (err != OK)
423  {
424  // std::cout << "in (vpCalculPose_plan.cc)CalculTranslation returns " ;
425  // PrintError(err) ;
426  // return err ;
427  }
428 
429  if (coplanar_plane_type == 1) { // plane ax=d
430  cMo[0][0] = (X1[1] * X2[2]) - (X1[2] * X2[1]);
431  cMo[1][0] = (X1[2] * X2[0]) - (X1[0] * X2[2]);
432  cMo[2][0] = (X1[0] * X2[1]) - (X1[1] * X2[0]);
433 
434  for (i = 0; i < 3; i++) { /* calcul de la matrice de passage */
435  cMo[i][1] = X1[i];
436  cMo[i][2] = X2[i];
437  cMo[i][3] = X2[i + 3];
438  }
439 
440  } else if (coplanar_plane_type == 2) { // plane by=d
441  cMo[0][1] = (X1[2] * X2[1]) - (X1[1] * X2[2]);
442  cMo[1][1] = (X1[0] * X2[2]) - (X1[2] * X2[0]);
443  cMo[2][1] = (X1[1] * X2[0]) - (X1[0] * X2[1]);
444 
445  for (i = 0; i < 3; i++) { /* calcul de la matrice de passage */
446  cMo[i][0] = X1[i];
447  cMo[i][2] = X2[i];
448  cMo[i][3] = X2[i + 3];
449  }
450  } else { // plane cz=d or any other
451  cMo[0][2] = (X1[1] * X2[2]) - (X1[2] * X2[1]);
452  cMo[1][2] = (X1[2] * X2[0]) - (X1[0] * X2[2]);
453  cMo[2][2] = (X1[0] * X2[1]) - (X1[1] * X2[0]);
454 
455  for (i = 0; i < 3; i++) { /* calcul de la matrice de passage */
456  cMo[i][0] = X1[i];
457  cMo[i][1] = X2[i];
458  cMo[i][3] = X2[i + 3];
459  }
460  }
461  } catch (...) {
462  throw; // throw the original exception
463  }
464 
465 #if (DEBUG_LEVEL1)
466  std::cout << "end vpCalculPose::PoseLagrange(...) " << std::endl;
467 #endif
468  // return(OK);
469 }
470 
472 {
473 
474 #if (DEBUG_LEVEL1)
475  std::cout << "begin CPose::PoseLagrange(...) " << std::endl;
476 #endif
477  try {
478  double s;
479  unsigned int i;
480 
481  unsigned int k = 0;
482  unsigned int nl = npt * 2;
483 
484  vpMatrix a(nl, 3);
485  vpMatrix b(nl, 9);
486  b = 0;
487 
488  vpPoint P;
489  i = 0;
490  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
491  P = *it;
492  a[k][0] = -P.get_oX();
493  a[k][1] = 0.0;
494  a[k][2] = P.get_oX() * P.get_x();
495 
496  a[k + 1][0] = 0.0;
497  a[k + 1][1] = -P.get_oX();
498  a[k + 1][2] = P.get_oX() * P.get_y();
499 
500  b[k][0] = -P.get_oY();
501  b[k][1] = 0.0;
502  b[k][2] = P.get_oY() * P.get_x();
503 
504  b[k][3] = -P.get_oZ();
505  b[k][4] = 0.0;
506  b[k][5] = P.get_oZ() * P.get_x();
507 
508  b[k][6] = -1.0;
509  b[k][7] = 0.0;
510  b[k][8] = P.get_x();
511 
512  b[k + 1][0] = 0.0;
513  b[k + 1][1] = -P.get_oY();
514  b[k + 1][2] = P.get_oY() * P.get_y();
515 
516  b[k + 1][3] = 0.0;
517  b[k + 1][4] = -P.get_oZ();
518  b[k + 1][5] = P.get_oZ() * P.get_y();
519 
520  b[k + 1][6] = 0.0;
521  b[k + 1][7] = -1.0;
522  b[k + 1][8] = P.get_y();
523 
524  k += 2;
525  }
526  vpColVector X1(3);
527  vpColVector X2(9);
528 
529 #if (DEBUG_LEVEL2)
530  {
531  std::cout << "a " << a << std::endl;
532  std::cout << "b " << b << std::endl;
533  }
534 #endif
535 
536  lagrange(a, b, X1, X2);
537  // if (err != OK)
538  {
539  // std::cout << "in (CLagrange.cc)Lagrange returns " ;
540  // PrintError(err) ;
541  // return err ;
542  }
543 
544 #if (DEBUG_LEVEL2)
545  {
546  std::cout << "ax1+bx2 (devrait etre 0) " << (a * X1 + b * X2).t() << std::endl;
547  std::cout << "norme X1 " << X1.sumSquare() << std::endl;
548  ;
549  }
550 #endif
551 
552  if (X2[8] < 0.0) { /* car Zo > 0 */
553  X1 *= -1;
554  X2 *= -1;
555  }
556  s = 0.0;
557  for (i = 0; i < 3; i++) {
558  s += (X1[i] * X2[i]);
559  }
560  for (i = 0; i < 3; i++) {
561  X2[i] -= (s * X1[i]);
562  } /* X1^T X2 = 0 */
563 
564  // s = 0.0;
565  // for (i=0;i<3;i++) {s += (X2[i]*X2[i]);}
566  s = X2[0] * X2[0] + X2[1] * X2[1] + X2[2] * X2[2]; // To avoid a Coverity copy/past error
567 
568  if (s < 1e-10) {
569  // std::cout << "Points that produce an error: " << std::endl;
570  // for (std::list<vpPoint>::const_iterator it = listP.begin(); it
571  // != listP.end(); ++it)
572  // {
573  // std::cout << "P: " << (*it).get_x() << " " << (*it).get_y() <<
574  // " "
575  // << (*it).get_oX() << " " << (*it).get_oY() << " " <<
576  // (*it).get_oZ() << std::endl;
577  // }
578  // vpERROR_TRACE(" division par zero " ) ;
579  throw(vpException(vpException::divideByZeroError, "Division by zero in Lagrange pose computation (non "
580  "planar plane case)"));
581  }
582 
583  s = 1.0 / sqrt(s);
584  for (i = 0; i < 3; i++) {
585  X2[i] *= s;
586  } /* X2^T X2 = 1 */
587 
588  X2[3] = (X1[1] * X2[2]) - (X1[2] * X2[1]);
589  X2[4] = (X1[2] * X2[0]) - (X1[0] * X2[2]);
590  X2[5] = (X1[0] * X2[1]) - (X1[1] * X2[0]);
591 
592  calculTranslation(a, b, nl, 3, 6, X1, X2);
593 
594  for (i = 0; i < 3; i++) {
595  cMo[i][0] = X1[i];
596  cMo[i][1] = X2[i];
597  cMo[i][2] = X2[i + 3];
598  cMo[i][3] = X2[i + 6];
599  }
600 
601  } catch (...) {
602  throw; // throw the original exception
603  }
604 
605 #if (DEBUG_LEVEL1)
606  std::cout << "end vpCalculPose::PoseLagrange(...) " << std::endl;
607 #endif
608 }
609 
610 #undef DEBUG_LEVEL1
611 #undef DEBUG_LEVEL2
void svd(vpColVector &w, vpMatrix &V)
Definition: vpMatrix.cpp:1791
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1931
double get_oY() const
Get the point Y coordinate in the object frame.
Definition: vpPoint.cpp:422
void poseLagrangePlan(vpHomogeneousMatrix &cMo, const int coplanar_plane_type=0)
Compute the pose of a planar object using Lagrange approach.
Implementation of an homogeneous matrix and operations on such kind of matrices.
void poseLagrangeNonPlan(vpHomogeneousMatrix &cMo)
#define vpERROR_TRACE
Definition: vpDebug.h:393
vpMatrix inverseByLU() const
error that can be emited by ViSP classes.
Definition: vpException.h:71
unsigned int getRows() const
Definition: vpArray2D.h:156
vpRowVector t() const
std::list< vpPoint > listP
Array of point (use here class vpPoint)
Definition: vpPose.h:115
double get_oX() const
Get the point X coordinate in the object frame.
Definition: vpPoint.cpp:420
Class that defines what is a point.
Definition: vpPoint.h:58
unsigned int getCols() const
Definition: vpArray2D.h:146
vpMatrix t() const
Definition: vpMatrix.cpp:375
double get_oZ() const
Get the point Z coordinate in the object frame.
Definition: vpPoint.cpp:424
unsigned int npt
Number of point used in pose computation.
Definition: vpPose.h:114
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
double get_x() const
Get the point x coordinate in the image plane.
Definition: vpPoint.cpp:429
double sumSquare() const
double get_y() const
Get the point y coordinate in the image plane.
Definition: vpPoint.cpp:431