Visual Servoing Platform  version 3.6.1 under development (2024-04-28)
vpPoseDementhon.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Pose computation.
32  */
33 
34 #include <visp3/core/vpMath.h>
35 #include <visp3/vision/vpPose.h>
36 
37 #define DEBUG_LEVEL1 0
38 #define DEBUG_LEVEL2 0
39 #define DEBUG_LEVEL3 0
40 
41 #define SEUIL_RESIDUAL 0.0001 /* avant 0.01 dans while du calculArbreDementhon */
42 #define EPS_DEM 0.001
43 
44 #define ITER_MAX 30 /* max number of iterations for Demonthon's loop */
45 
46 static void calculSolutionDementhon(vpColVector &I4, vpColVector &J4, vpHomogeneousMatrix &cMo)
47 {
48 
49 #if (DEBUG_LEVEL1)
50  std::cout << "begin (Dementhon.cc)CalculSolutionDementhon() " << std::endl;
51 #endif
52 
53  // norm of the 3 first components of I4 and J4
54  double normI3 = sqrt((I4[0] * I4[0]) + (I4[1] * I4[1]) + (I4[2] * I4[2]));
55  double normJ3 = sqrt((J4[0] * J4[0]) + (J4[1] * J4[1]) + (J4[2] * J4[2]));
56 
57  if ((normI3 < 1e-10) || (normJ3 < 1e-10)) {
58  // vpERROR_TRACE(" normI+normJ = 0, division par zero " ) ;
60  "Division by zero in Dementhon pose computation: normI or normJ = 0"));
61  }
62 
63  double Z0 = 2.0 / (normI3 + normJ3);
64 
65  vpColVector I3(3), J3(3), K3(3);
66  for (unsigned int i = 0; i < 3; ++i) {
67  I3[i] = I4[i] / normI3;
68  J3[i] = J4[i] / normJ3;
69  }
70 
71  K3 = vpColVector::cross(I3, J3); // k = I x J
72  K3.normalize();
73 
74  J3 = vpColVector::cross(K3, I3);
75 
76  // calcul de la matrice de passage
77  cMo[0][0] = I3[0];
78  cMo[0][1] = I3[1];
79  cMo[0][2] = I3[2];
80  cMo[0][3] = I4[3] * Z0;
81 
82  cMo[1][0] = J3[0];
83  cMo[1][1] = J3[1];
84  cMo[1][2] = J3[2];
85  cMo[1][3] = J4[3] * Z0;
86 
87  cMo[2][0] = K3[0];
88  cMo[2][1] = K3[1];
89  cMo[2][2] = K3[2];
90  cMo[2][3] = Z0;
91 
92 #if (DEBUG_LEVEL1)
93  std::cout << "end (Dementhon.cc)CalculSolutionDementhon() " << std::endl;
94 #endif
95 }
96 
98 {
99  vpPoint P;
100  double cdg[3];
101  /* compute the cog of the 3D points */
102  cdg[0] = 0.0;
103  cdg[1] = 0.0;
104  cdg[2] = 0.0;
105  std::list<vpPoint>::const_iterator listp_end = listP.end();
106  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listp_end; ++it) {
107  P = (*it);
108  cdg[0] += P.get_oX();
109  cdg[1] += P.get_oY();
110  cdg[2] += P.get_oZ();
111  }
112  for (unsigned int i = 0; i < 3; ++i) {
113  cdg[i] /= npt;
114  }
115  // --comment: print cdg cdg of 0 cdg of 1 cdg of 2
116 
117  c3d.clear();
118  /* translate the 3D points wrt cog */
119  std::list<vpPoint>::const_iterator listp_end_s = listP.end();
120  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listp_end_s; ++it) {
121  P = (*it);
122  P.set_oX(P.get_oX() - cdg[0]);
123  P.set_oY(P.get_oY() - cdg[1]);
124  P.set_oZ(P.get_oZ() - cdg[2]);
125  c3d.push_back(P);
126  }
127 
128  vpMatrix A(npt, 4), Ap;
129 
130  for (unsigned int i = 0; i < npt; ++i) {
131  A[i][0] = c3d[i].get_oX();
132  A[i][1] = c3d[i].get_oY();
133  A[i][2] = c3d[i].get_oZ();
134  A[i][3] = 1.0;
135  }
137 
138 #if (DEBUG_LEVEL2)
139  {
140  std::cout << "A" << std::endl << A << std::endl;
141  std::cout << "A^+" << std::endl << Ap << std::endl;
142  }
143 #endif
144 
145  vpColVector xprim(npt);
146  vpColVector yprim(npt);
147 
148  for (unsigned int i = 0; i < npt; ++i) {
149  xprim[i] = c3d[i].get_x();
150  yprim[i] = c3d[i].get_y();
151  }
152  vpColVector I4(4), J4(4);
153 
154  I4 = Ap * xprim;
155  J4 = Ap * yprim;
156 
157  calculSolutionDementhon(I4, J4, cMo);
158 
159  int erreur = 0;
160  for (unsigned int i = 0; i < npt; ++i) {
161  double z;
162  z = (cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ()) + cMo[2][3];
163  if (z <= 0.0) {
164  erreur = -1;
165  }
166  }
167  if (erreur == -1) {
168  throw(vpException(vpException::fatalError, "End of Dementhon since z < 0 for both solutions at the beginning"));
169  }
170  int cpt = 0;
171  double res = sqrt(computeResidualDementhon(cMo) / npt);
172  double res_old = 2.0 * res;
173 
174  // In his paper, Dementhon suggests to use the difference
175  // between 2 successive norm of eps. We prefer to use the mean of the
176  // residuals in the image
177  while ((cpt < ITER_MAX) && (res > SEUIL_RESIDUAL) && (res < res_old)) {
178 
179  vpHomogeneousMatrix cMo_old;
180  res_old = res;
181  cMo_old = cMo;
182 
183  for (unsigned int i = 0; i < npt; ++i) {
184  double eps =
185  ((cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ())) / cMo[2][3];
186 
187  xprim[i] = (1.0 + eps) * c3d[i].get_x();
188  yprim[i] = (1.0 + eps) * c3d[i].get_y();
189  }
190  I4 = Ap * xprim;
191  J4 = Ap * yprim;
192 
193  calculSolutionDementhon(I4, J4, cMo);
194  res = sqrt(computeResidualDementhon(cMo) / npt);
195  for (unsigned int i = 0; i < npt; ++i) {
196  double z;
197  z = (cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ()) + cMo[2][3];
198  if (z <= 0.0) {
199  erreur = -1;
200  }
201  }
202  if (erreur == -1) {
203  cMo = cMo_old;
204  res = res_old; // to leave the while loop
205 #if (DEBUG_LEVEL3)
206  std::cout << "Pb z < 0 with cMo in Dementhon's loop" << std::endl;
207 #endif
208  }
209 #if (DEBUG_LEVEL3)
210  vpThetaUVector erc;
211  cMo.extract(erc);
212  std::cout << "it = " << cpt << " residu = " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
213  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
214 #endif
215  if (res > res_old) {
216 #if (DEBUG_LEVEL3)
217  std::cout << "Divergence : res = " << res << " res_old = " << res_old << std::endl;
218 #endif
219  cMo = cMo_old;
220  }
221  ++cpt;
222  }
223  // go back to the initial frame
224  cMo[0][3] -= ((cdg[0] * cMo[0][0]) + (cdg[1] * cMo[0][1]) + (cdg[2] * cMo[0][2]));
225  cMo[1][3] -= ((cdg[0] * cMo[1][0]) + (cdg[1] * cMo[1][1]) + (cdg[2] * cMo[1][2]));
226  cMo[2][3] -= ((cdg[0] * cMo[2][0]) + (cdg[1] * cMo[2][1]) + (cdg[2] * cMo[2][2]));
227 }
228 
229 static void calculRTheta(double s, double c, double &r, double &theta)
230 {
231  if ((fabs(c) > EPS_DEM) || (fabs(s) > EPS_DEM)) {
232  r = sqrt(sqrt((s * s) + (c * c)));
233  theta = atan2(s, c) / 2.0;
234  }
235  else {
236  if (fabs(c) > fabs(s)) {
237  r = fabs(c);
238  if (c >= 0.0) {
239  theta = M_PI / 2;
240  }
241  else {
242  theta = -M_PI / 2;
243  }
244  }
245  else {
246  r = fabs(s);
247  if (s >= 0.0) {
248  theta = M_PI / 4.0;
249  }
250  else {
251  theta = -M_PI / 4.0;
252  }
253  }
254  }
255 }
256 
257 static void calculTwoSolutionsDementhonPlan(vpColVector &I04, vpColVector &J04, vpColVector &U,
259 {
260  vpColVector I0(3), J0(3);
261  for (unsigned int i = 0; i < 3; ++i) {
262  I0[i] = I04[i];
263  J0[i] = J04[i];
264  }
265  double s = -2.0 * vpColVector::dotProd(I0, J0);
266  double c = J0.sumSquare() - I0.sumSquare();
267 
268  double r, theta;
269  calculRTheta(s, c, r, theta);
270  double co = cos(theta);
271  double si = sin(theta);
272 
273  // calcul de la premiere solution
274  vpColVector I(4), J(4);
275  I = I04 + (U * r * co);
276  J = J04 + (U * r * si);
277 
278 #if (DEBUG_LEVEL2)
279  {
280  std::cout << "I0 " << I04.t() << std::endl;
281  std::cout << "J0 " << J04.t() << std::endl;
282  std::cout << "I1 " << I.t() << std::endl;
283  std::cout << "J1 " << J.t() << std::endl;
284  }
285 #endif
286  calculSolutionDementhon(I, J, cMo1);
287 
288  // calcul de la deuxieme solution
289  I = I04 - (U * r * co);
290  J = J04 - (U * r * si);
291 #if (DEBUG_LEVEL2)
292  {
293  std::cout << "I2 " << I.t() << std::endl;
294  std::cout << "J2 " << J.t() << std::endl;
295  }
296 #endif
297  calculSolutionDementhon(I, J, cMo2);
298 }
299 
301 {
302 #if (DEBUG_LEVEL1)
303  std::cout << "begin vpPose::CalculArbreDementhon() " << std::endl;
304 #endif
305 
306  int erreur = 0;
307 
308  // test if all points are in front of the camera
309  for (unsigned int i = 0; i < npt; ++i) {
310  double z;
311  z = (cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ()) + cMo[2][3];
312  if (z <= 0.0) {
313  erreur = -1;
314  return erreur;
315  }
316  }
317 
318  unsigned int cpt = 0;
319  double res_min = sqrt(computeResidualDementhon(cMo) / npt);
320  double res_old = 2.0 * res_min;
321 
322  /* FC modif SEUIL_RESIDUAL 0.01 a 0.001 */
323  while ((cpt < ITER_MAX) && (res_min > SEUIL_RESIDUAL) && (res_min < res_old)) {
324  vpHomogeneousMatrix cMo1, cMo2, cMo_old;
325 
326  res_old = res_min;
327  cMo_old = cMo;
328 
329  vpColVector xprim(npt), yprim(npt);
330  for (unsigned int i = 0; i < npt; ++i) {
331  double eps =
332  ((cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ())) / cMo[2][3];
333 
334  xprim[i] = (1.0 + eps) * c3d[i].get_x();
335  yprim[i] = (1.0 + eps) * c3d[i].get_y();
336  }
337 
338  vpColVector I04(4), J04(4);
339  I04 = Ap * xprim;
340  J04 = Ap * yprim;
341 
342  calculTwoSolutionsDementhonPlan(I04, J04, U, cMo1, cMo2);
343 
344  // test if all points are in front of the camera for cMo1 and cMo2
345  int erreur1 = 0;
346  int erreur2 = 0;
347  for (unsigned int i = 0; i < npt; ++i) {
348  double z;
349  z = (cMo1[2][0] * c3d[i].get_oX()) + (cMo1[2][1] * c3d[i].get_oY()) + (cMo1[2][2] * c3d[i].get_oZ()) + cMo1[2][3];
350  if (z <= 0.0) {
351  erreur1 = -1;
352  }
353  z = (cMo2[2][0] * c3d[i].get_oX()) + (cMo2[2][1] * c3d[i].get_oY()) + (cMo2[2][2] * c3d[i].get_oZ()) + cMo2[2][3];
354  if (z <= 0.0) {
355  erreur2 = -1;
356  }
357  }
358 
359  if ((erreur1 == -1) && (erreur2 == -1)) {
360  cMo = cMo_old;
361 #if (DEBUG_LEVEL3)
362  std::cout << " End of loop since z < 0 for both solutions" << std::endl;
363 #endif
364  break; // outside of while due to z < 0
365  }
366  if ((erreur1 == 0) && (erreur2 == -1)) {
367  cMo = cMo1;
368  res_min = sqrt(computeResidualDementhon(cMo) / npt);
369  }
370  if ((erreur1 == -1) && (erreur2 == 0)) {
371  cMo = cMo2;
372  res_min = sqrt(computeResidualDementhon(cMo) / npt);
373  }
374  if ((erreur1 == 0) && (erreur2 == 0)) {
375  double res1 = sqrt(computeResidualDementhon(cMo1) / npt);
376  double res2 = sqrt(computeResidualDementhon(cMo2) / npt);
377  if (res1 <= res2) {
378  res_min = res1;
379  cMo = cMo1;
380  }
381  else {
382  res_min = res2;
383  cMo = cMo2;
384  }
385  }
386 
387 #if (DEBUG_LEVEL3)
388  if (erreur1 == 0) {
389  double s = sqrt(computeResidualDementhon(cMo1) / npt);
390  vpThetaUVector erc;
391  cMo1.extract(erc);
392  std::cout << "it = " << cpt << " cMo1 : residu: " << s << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
393  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
394  }
395  else
396  std::cout << "Pb z < 0 with cMo1" << std::endl;
397 
398  if (erreur2 == 0) {
399  double s = sqrt(computeResidualDementhon(cMo2) / npt);
400  vpThetaUVector erc;
401  cMo2.extract(erc);
402  std::cout << "it = " << cpt << " cMo2 : residu: " << s << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
403  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
404  }
405  else
406  std::cout << "Pb z < 0 with cMo2" << std::endl;
407 #endif
408 
409  if (res_min > res_old) {
410 #if (DEBUG_LEVEL3)
411  std::cout << "Divergence : res_min = " << res_min << " res_old = " << res_old << std::endl;
412 #endif
413  cMo = cMo_old;
414  }
415  ++cpt;
416  } /* end of while */
417 
418 #if (DEBUG_LEVEL1)
419  std::cout << "end vpPose::CalculArbreDementhon() return " << erreur << std::endl;
420 #endif
421 
422  return erreur;
423 }
424 
426 {
427 #if (DEBUG_LEVEL1)
428  std::cout << "begin CCalculPose::PoseDementhonPlan()" << std::endl;
429 #endif
430  const double svdFactorUsedWhenFailure = 10.; // Factor by which is multipled m_dementhonSvThresh each time the svdDecomposition fails
431  const double svdThresholdLimit = 1e-2; // The svd decomposition will be tested with a threshold up to this value. If with this threshold, the rank of A is still !=3, an exception is thrown
432  const double lnOfSvdFactorUsed = std::log(svdFactorUsedWhenFailure);
433  const double logNOfSvdThresholdLimit = std::log(svdThresholdLimit)/lnOfSvdFactorUsed;
434  vpPoint P;
435  double cdg[3];
436  /* compute the cog of the 3D points */
437  cdg[0] = 0.0;
438  cdg[1] = 0.0;
439  cdg[2] = 0.0;
440  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
441  P = (*it);
442  cdg[0] += P.get_oX();
443  cdg[1] += P.get_oY();
444  cdg[2] += P.get_oZ();
445  }
446  for (unsigned int i = 0; i < 3; ++i) {
447  cdg[i] /= npt;
448  }
449  // --comment: print cdg cdg of 0 of 1 and of 2
450 
451  c3d.clear();
452  /* translate the 3D points wrt cog */
453  std::list<vpPoint>::const_iterator listp_end = listP.end();
454  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listp_end; ++it) {
455  P = (*it);
456  P.set_oX(P.get_oX() - cdg[0]);
457  P.set_oY(P.get_oY() - cdg[1]);
458  P.set_oZ(P.get_oZ() - cdg[2]);
459  c3d.push_back(P);
460  }
461 
462  vpMatrix A(npt, 4);
463 
464  for (unsigned int i = 0; i < npt; ++i) {
465  A[i][0] = c3d[i].get_oX();
466  A[i][1] = c3d[i].get_oY();
467  A[i][2] = c3d[i].get_oZ();
468  A[i][3] = 1.0;
469  }
470  vpColVector sv;
471  vpMatrix Ap, imA, imAt, kAt;
472  bool isRankEqualTo3 = false; // Indicates if the rank of A is the expected one
473  // Get the log_n(m_dementhonSvThresh), where n is the factor by which we will multiply it if the svd decomposition fails.
474  double logNofSvdThresh = std::log(m_dementhonSvThresh)/lnOfSvdFactorUsed;
475  // Ensure that if the user chose a threshold > svdThresholdLimit, at least 1 iteration of svd decomposition is performed
476  int nbMaxIter = static_cast<int>(std::max<double>(std::ceil(logNOfSvdThresholdLimit - logNofSvdThresh), 1.));
477  double svdThreshold = m_dementhonSvThresh;
478  int irank = 0;
479  for (int i = 0; (i < nbMaxIter) && (!isRankEqualTo3); ++i) {
480  irank = A.pseudoInverse(Ap, sv, svdThreshold, imA, imAt, kAt);
481  if (irank == 3) {
482  isRankEqualTo3 = true;
483  }
484  else {
485  isRankEqualTo3 = false;
486  svdThreshold *= svdFactorUsedWhenFailure;
487  }
488  }
489 
490  if (!isRankEqualTo3) {
491  std::stringstream errorMsg;
492  errorMsg << "In Dementhon planar, after ";
493  errorMsg << nbMaxIter;
494  errorMsg << " trials multiplying the svd threshold by ";
495  errorMsg << svdFactorUsedWhenFailure;
496  errorMsg << ", rank (";
497  errorMsg << irank;
498  errorMsg << ") is still not 3";
499  throw(vpException(vpException::fatalError, errorMsg.str()));
500  }
501  // calcul de U
502  vpColVector U(4);
503  for (unsigned int i = 0; i < 4; ++i) {
504  U[i] = kAt[0][i];
505  }
506 #if (DEBUG_LEVEL2)
507  {
508  std::cout << "A" << std::endl << A << std::endl;
509  std::cout << "A^+" << std::endl << Ap << std::endl;
510  std::cout << "U^T = " << U.t() << std::endl;
511  }
512 #endif
513 
514  vpColVector xi(npt);
515  vpColVector yi(npt);
516 
517  for (unsigned int i = 0; i < npt; ++i) {
518  xi[i] = c3d[i].get_x();
519  yi[i] = c3d[i].get_y();
520  }
521 
522  vpColVector I04(4), J04(4);
523  I04 = Ap * xi;
524  J04 = Ap * yi;
525 
526  vpHomogeneousMatrix cMo1, cMo2;
527  calculTwoSolutionsDementhonPlan(I04, J04, U, cMo1, cMo2);
528 
529 #if DEBUG_LEVEL3
530  double res = sqrt(computeResidualDementhon(cMo1) / npt);
531  vpThetaUVector erc;
532  cMo1.extract(erc);
533  std::cout << "cMo Start Tree 1 : res " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
534  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
535  res = sqrt(computeResidualDementhon(cMo2) / npt);
536  cMo2.extract(erc);
537  std::cout << "cMo Start Tree 2 : res " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
538  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
539 #endif
540 
541  int erreur1 = calculArbreDementhon(Ap, U, cMo1);
542  int erreur2 = calculArbreDementhon(Ap, U, cMo2);
543 
544  if ((erreur1 == -1) && (erreur2 == -1)) {
545  throw(
546  vpException(vpException::fatalError, "Error in Dementhon planar: z < 0 with Start Tree 1 and Start Tree 2..."));
547  }
548  if ((erreur1 == 0) && (erreur2 == -1)) {
549  cMo = cMo1;
550  }
551  if ((erreur1 == -1) && (erreur2 == 0)) {
552  cMo = cMo2;
553  }
554  if ((erreur1 == 0) && (erreur2 == 0)) {
555  double s1 = computeResidualDementhon(cMo1);
556  double s2 = computeResidualDementhon(cMo2);
557 
558  if (s1 <= s2) {
559  cMo = cMo1;
560  }
561  else {
562  cMo = cMo2;
563  }
564 
565 #if DEBUG_LEVEL3
566  if (erreur1 == -1)
567  std::cout << "Pb z < 0 with Start Tree 1" << std::endl;
568  if (erreur2 == -1)
569  std::cout << "Pb z < 0 with Start Tree 2" << std::endl;
570  if (s1 <= s2)
571  std::cout << " Tree 1 chosen " << std::endl;
572  else
573  std::cout << " Tree 2 chosen " << std::endl;
574 #endif
575  }
576 
577  cMo[0][3] -= ((cdg[0] * cMo[0][0]) + (cdg[1] * cMo[0][1]) + (cdg[2] * cMo[0][2]));
578  cMo[1][3] -= ((cdg[0] * cMo[1][0]) + (cdg[1] * cMo[1][1]) + (cdg[2] * cMo[1][2]));
579  cMo[2][3] -= ((cdg[0] * cMo[2][0]) + (cdg[1] * cMo[2][1]) + (cdg[2] * cMo[2][2]));
580 
581 #if (DEBUG_LEVEL1)
582  std::cout << "end CCalculPose::PoseDementhonPlan()" << std::endl;
583 #endif
584 }
585 
587 {
588  double squared_error = 0;
589 
590  // Be careful: since c3d has been translated so that point0 is at the cdg,
591  // cMo here corresponds to object frame at that point, i.e, only the one used
592  // internally to Dementhon's method
593 
594  for (unsigned int i = 0; i < npt; ++i) {
595 
596  double X = (c3d[i].get_oX() * cMo[0][0]) + (c3d[i].get_oY() * cMo[0][1]) + (c3d[i].get_oZ() * cMo[0][2]) + cMo[0][3];
597  double Y = (c3d[i].get_oX() * cMo[1][0]) + (c3d[i].get_oY() * cMo[1][1]) + (c3d[i].get_oZ() * cMo[1][2]) + cMo[1][3];
598  double Z = (c3d[i].get_oX() * cMo[2][0]) + (c3d[i].get_oY() * cMo[2][1]) + (c3d[i].get_oZ() * cMo[2][2]) + cMo[2][3];
599 
600  double x = X / Z;
601  double y = Y / Z;
602 
603  squared_error += vpMath::sqr(x - c3d[i].get_x()) + vpMath::sqr(y - c3d[i].get_y());
604  }
605  return squared_error;
606 }
607 
608 #undef EPS_DEM
609 #undef SEUIL_RESIDUAL
610 #undef ITER_MAX
611 #undef DEBUG_LEVEL1
612 #undef DEBUG_LEVEL2
613 #undef DEBUG_LEVEL3
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
static double dotProd(const vpColVector &a, const vpColVector &b)
vpRowVector t() const
static vpColVector cross(const vpColVector &a, const vpColVector &b)
Definition: vpColVector.h:1172
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ fatalError
Fatal error.
Definition: vpException.h:84
@ divideByZeroError
Division by zero.
Definition: vpException.h:82
Implementation of an homogeneous matrix and operations on such kind of matrices.
void extract(vpRotationMatrix &R) const
static double sqr(double x)
Definition: vpMath.h:201
static double deg(double rad)
Definition: vpMath.h:117
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:2343
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition: vpPoint.h:77
double get_oX() const
Get the point oX coordinate in the object frame.
Definition: vpPoint.cpp:454
double get_oZ() const
Get the point oZ coordinate in the object frame.
Definition: vpPoint.cpp:458
void set_oY(double oY)
Set the point oY coordinate in the object frame.
Definition: vpPoint.cpp:497
void set_oZ(double oZ)
Set the point oZ coordinate in the object frame.
Definition: vpPoint.cpp:499
void set_oX(double oX)
Set the point oX coordinate in the object frame.
Definition: vpPoint.cpp:495
double get_oY() const
Get the point oY coordinate in the object frame.
Definition: vpPoint.cpp:456
double computeResidualDementhon(const vpHomogeneousMatrix &cMo)
unsigned int npt
Number of point used in pose computation.
Definition: vpPose.h:114
void poseDementhonNonPlan(vpHomogeneousMatrix &cMo)
double m_dementhonSvThresh
SVD threshold use for the pseudo-inverse computation in poseDementhonPlan.
Definition: vpPose.h:766
std::list< vpPoint > listP
Array of point (use here class vpPoint)
Definition: vpPose.h:115
int calculArbreDementhon(vpMatrix &b, vpColVector &U, vpHomogeneousMatrix &cMo)
void poseDementhonPlan(vpHomogeneousMatrix &cMo)
Implementation of a rotation vector as axis-angle minimal representation.