Visual Servoing Platform  version 3.6.1 under development (2024-04-19)
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  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
106  P = (*it);
107  cdg[0] += P.get_oX();
108  cdg[1] += P.get_oY();
109  cdg[2] += P.get_oZ();
110  }
111  for (unsigned int i = 0; i < 3; ++i) {
112  cdg[i] /= npt;
113  }
114  // --comment: print cdg cdg of 0 cdg of 1 cdg of 2
115 
116  c3d.clear();
117  /* translate the 3D points wrt cog */
118  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
119  P = (*it);
120  P.set_oX(P.get_oX() - cdg[0]);
121  P.set_oY(P.get_oY() - cdg[1]);
122  P.set_oZ(P.get_oZ() - cdg[2]);
123  c3d.push_back(P);
124  }
125 
126  vpMatrix A(npt, 4), Ap;
127 
128  for (unsigned int i = 0; i < npt; ++i) {
129  A[i][0] = c3d[i].get_oX();
130  A[i][1] = c3d[i].get_oY();
131  A[i][2] = c3d[i].get_oZ();
132  A[i][3] = 1.0;
133  }
135 
136 #if (DEBUG_LEVEL2)
137  {
138  std::cout << "A" << std::endl << A << std::endl;
139  std::cout << "A^+" << std::endl << Ap << std::endl;
140  }
141 #endif
142 
143  vpColVector xprim(npt);
144  vpColVector yprim(npt);
145 
146  for (unsigned int i = 0; i < npt; ++i) {
147  xprim[i] = c3d[i].get_x();
148  yprim[i] = c3d[i].get_y();
149  }
150  vpColVector I4(4), J4(4);
151 
152  I4 = Ap * xprim;
153  J4 = Ap * yprim;
154 
155  calculSolutionDementhon(I4, J4, cMo);
156 
157  int erreur = 0;
158  for (unsigned int i = 0; i < npt; ++i) {
159  double z;
160  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];
161  if (z <= 0.0) {
162  erreur = -1;
163  }
164  }
165  if (erreur == -1) {
166  throw(vpException(vpException::fatalError, "End of Dementhon since z < 0 for both solutions at the beginning"));
167  }
168  int cpt = 0;
169  double res = sqrt(computeResidualDementhon(cMo) / npt);
170  double res_old = 2.0 * res;
171 
172  // In his paper, Dementhon suggests to use the difference
173  // between 2 successive norm of eps. We prefer to use the mean of the
174  // residuals in the image
175  while ((cpt < ITER_MAX) && (res > SEUIL_RESIDUAL) && (res < res_old)) {
176 
177  vpHomogeneousMatrix cMo_old;
178  res_old = res;
179  cMo_old = cMo;
180 
181  for (unsigned int i = 0; i < npt; ++i) {
182  double eps =
183  ((cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ())) / cMo[2][3];
184 
185  xprim[i] = (1.0 + eps) * c3d[i].get_x();
186  yprim[i] = (1.0 + eps) * c3d[i].get_y();
187  }
188  I4 = Ap * xprim;
189  J4 = Ap * yprim;
190 
191  calculSolutionDementhon(I4, J4, cMo);
192  res = sqrt(computeResidualDementhon(cMo) / npt);
193  for (unsigned int i = 0; i < npt; ++i) {
194  double z;
195  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];
196  if (z <= 0.0) {
197  erreur = -1;
198  }
199  }
200  if (erreur == -1) {
201  cMo = cMo_old;
202  res = res_old; // to leave the while loop
203 #if (DEBUG_LEVEL3)
204  std::cout << "Pb z < 0 with cMo in Dementhon's loop" << std::endl;
205 #endif
206  }
207 #if (DEBUG_LEVEL3)
208  vpThetaUVector erc;
209  cMo.extract(erc);
210  std::cout << "it = " << cpt << " residu = " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
211  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
212 #endif
213  if (res > res_old) {
214 #if (DEBUG_LEVEL3)
215  std::cout << "Divergence : res = " << res << " res_old = " << res_old << std::endl;
216 #endif
217  cMo = cMo_old;
218  }
219  cpt++;
220  }
221  // go back to the initial frame
222  cMo[0][3] -= ((cdg[0] * cMo[0][0]) + (cdg[1] * cMo[0][1]) + (cdg[2] * cMo[0][2]));
223  cMo[1][3] -= ((cdg[0] * cMo[1][0]) + (cdg[1] * cMo[1][1]) + (cdg[2] * cMo[1][2]));
224  cMo[2][3] -= ((cdg[0] * cMo[2][0]) + (cdg[1] * cMo[2][1]) + (cdg[2] * cMo[2][2]));
225 }
226 
227 static void calculRTheta(double s, double c, double &r, double &theta)
228 {
229  if ((fabs(c) > EPS_DEM) || (fabs(s) > EPS_DEM)) {
230  r = sqrt(sqrt((s * s) + (c * c)));
231  theta = atan2(s, c) / 2.0;
232  }
233  else {
234  if (fabs(c) > fabs(s)) {
235  r = fabs(c);
236  if (c >= 0.0) {
237  theta = M_PI / 2;
238  }
239  else {
240  theta = -M_PI / 2;
241  }
242  }
243  else {
244  r = fabs(s);
245  if (s >= 0.0) {
246  theta = M_PI / 4.0;
247  }
248  else {
249  theta = -M_PI / 4.0;
250  }
251  }
252  }
253 }
254 
255 static void calculTwoSolutionsDementhonPlan(vpColVector &I04, vpColVector &J04, vpColVector &U,
257 {
258  vpColVector I0(3), J0(3);
259  for (unsigned int i = 0; i < 3; ++i) {
260  I0[i] = I04[i];
261  J0[i] = J04[i];
262  }
263  double s = -2.0 * vpColVector::dotProd(I0, J0);
264  double c = J0.sumSquare() - I0.sumSquare();
265 
266  double r, theta;
267  calculRTheta(s, c, r, theta);
268  double co = cos(theta);
269  double si = sin(theta);
270 
271  // calcul de la premiere solution
272  vpColVector I(4), J(4);
273  I = I04 + (U * r * co);
274  J = J04 + (U * r * si);
275 
276 #if (DEBUG_LEVEL2)
277  {
278  std::cout << "I0 " << I04.t() << std::endl;
279  std::cout << "J0 " << J04.t() << std::endl;
280  std::cout << "I1 " << I.t() << std::endl;
281  std::cout << "J1 " << J.t() << std::endl;
282  }
283 #endif
284  calculSolutionDementhon(I, J, cMo1);
285 
286  // calcul de la deuxieme solution
287  I = I04 - (U * r * co);
288  J = J04 - (U * r * si);
289 #if (DEBUG_LEVEL2)
290  {
291  std::cout << "I2 " << I.t() << std::endl;
292  std::cout << "J2 " << J.t() << std::endl;
293  }
294 #endif
295  calculSolutionDementhon(I, J, cMo2);
296 }
297 
299 {
300 #if (DEBUG_LEVEL1)
301  std::cout << "begin vpPose::CalculArbreDementhon() " << std::endl;
302 #endif
303 
304  int erreur = 0;
305 
306  // test if all points are in front of the camera
307  for (unsigned int i = 0; i < npt; ++i) {
308  double z;
309  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];
310  if (z <= 0.0) {
311  erreur = -1;
312  return erreur;
313  }
314  }
315 
316  unsigned int cpt = 0;
317  double res_min = sqrt(computeResidualDementhon(cMo) / npt);
318  double res_old = 2.0 * res_min;
319 
320  /* FC modif SEUIL_RESIDUAL 0.01 a 0.001 */
321  while ((cpt < ITER_MAX) && (res_min > SEUIL_RESIDUAL) && (res_min < res_old)) {
322  vpHomogeneousMatrix cMo1, cMo2, cMo_old;
323 
324  res_old = res_min;
325  cMo_old = cMo;
326 
327  vpColVector xprim(npt), yprim(npt);
328  for (unsigned int i = 0; i < npt; ++i) {
329  double eps =
330  ((cMo[2][0] * c3d[i].get_oX()) + (cMo[2][1] * c3d[i].get_oY()) + (cMo[2][2] * c3d[i].get_oZ())) / cMo[2][3];
331 
332  xprim[i] = (1.0 + eps) * c3d[i].get_x();
333  yprim[i] = (1.0 + eps) * c3d[i].get_y();
334  }
335 
336  vpColVector I04(4), J04(4);
337  I04 = Ap * xprim;
338  J04 = Ap * yprim;
339 
340  calculTwoSolutionsDementhonPlan(I04, J04, U, cMo1, cMo2);
341 
342  // test if all points are in front of the camera for cMo1 and cMo2
343  int erreur1 = 0;
344  int erreur2 = 0;
345  for (unsigned int i = 0; i < npt; ++i) {
346  double z;
347  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];
348  if (z <= 0.0) {
349  erreur1 = -1;
350  }
351  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];
352  if (z <= 0.0) {
353  erreur2 = -1;
354  }
355  }
356 
357  if ((erreur1 == -1) && (erreur2 == -1)) {
358  cMo = cMo_old;
359 #if (DEBUG_LEVEL3)
360  std::cout << " End of loop since z < 0 for both solutions" << std::endl;
361 #endif
362  break; // outside of while due to z < 0
363  }
364  if ((erreur1 == 0) && (erreur2 == -1)) {
365  cMo = cMo1;
366  res_min = sqrt(computeResidualDementhon(cMo) / npt);
367  }
368  if ((erreur1 == -1) && (erreur2 == 0)) {
369  cMo = cMo2;
370  res_min = sqrt(computeResidualDementhon(cMo) / npt);
371  }
372  if ((erreur1 == 0) && (erreur2 == 0)) {
373  double res1 = sqrt(computeResidualDementhon(cMo1) / npt);
374  double res2 = sqrt(computeResidualDementhon(cMo2) / npt);
375  if (res1 <= res2) {
376  res_min = res1;
377  cMo = cMo1;
378  }
379  else {
380  res_min = res2;
381  cMo = cMo2;
382  }
383  }
384 
385 #if (DEBUG_LEVEL3)
386  if (erreur1 == 0) {
387  double s = sqrt(computeResidualDementhon(cMo1) / npt);
388  vpThetaUVector erc;
389  cMo1.extract(erc);
390  std::cout << "it = " << cpt << " cMo1 : residu: " << s << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
391  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
392  }
393  else
394  std::cout << "Pb z < 0 with cMo1" << std::endl;
395 
396  if (erreur2 == 0) {
397  double s = sqrt(computeResidualDementhon(cMo2) / npt);
398  vpThetaUVector erc;
399  cMo2.extract(erc);
400  std::cout << "it = " << cpt << " cMo2 : residu: " << s << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
401  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
402  }
403  else
404  std::cout << "Pb z < 0 with cMo2" << std::endl;
405 #endif
406 
407  if (res_min > res_old) {
408 #if (DEBUG_LEVEL3)
409  std::cout << "Divergence : res_min = " << res_min << " res_old = " << res_old << std::endl;
410 #endif
411  cMo = cMo_old;
412  }
413  cpt++;
414  } /* end of while */
415 
416 #if (DEBUG_LEVEL1)
417  std::cout << "end vpPose::CalculArbreDementhon() return " << erreur << std::endl;
418 #endif
419 
420  return erreur;
421 }
422 
424 {
425 #if (DEBUG_LEVEL1)
426  std::cout << "begin CCalculPose::PoseDementhonPlan()" << std::endl;
427 #endif
428  const double svdFactorUsedWhenFailure = 10.; // Factor by which is multipled m_dementhonSvThresh each time the svdDecomposition fails
429  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
430  const double lnOfSvdFactorUsed = std::log(svdFactorUsedWhenFailure);
431  const double logNOfSvdThresholdLimit = std::log(svdThresholdLimit)/lnOfSvdFactorUsed;
432  vpPoint P;
433  double cdg[3];
434  /* compute the cog of the 3D points */
435  cdg[0] = 0.0;
436  cdg[1] = 0.0;
437  cdg[2] = 0.0;
438  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
439  P = (*it);
440  cdg[0] += P.get_oX();
441  cdg[1] += P.get_oY();
442  cdg[2] += P.get_oZ();
443  }
444  for (unsigned int i = 0; i < 3; ++i) {
445  cdg[i] /= npt;
446  }
447  // --comment: print cdg cdg of 0 of 1 and of 2
448 
449  c3d.clear();
450  /* translate the 3D points wrt cog */
451  for (std::list<vpPoint>::const_iterator it = listP.begin(); it != listP.end(); ++it) {
452  P = (*it);
453  P.set_oX(P.get_oX() - cdg[0]);
454  P.set_oY(P.get_oY() - cdg[1]);
455  P.set_oZ(P.get_oZ() - cdg[2]);
456  c3d.push_back(P);
457  }
458 
459  vpMatrix A(npt, 4);
460 
461  for (unsigned int i = 0; i < npt; ++i) {
462  A[i][0] = c3d[i].get_oX();
463  A[i][1] = c3d[i].get_oY();
464  A[i][2] = c3d[i].get_oZ();
465  A[i][3] = 1.0;
466  }
467  vpColVector sv;
468  vpMatrix Ap, imA, imAt, kAt;
469  bool isRankEqualTo3 = false; // Indicates if the rank of A is the expected one
470  // Get the log_n(m_dementhonSvThresh), where n is the factor by which we will multiply it if the svd decomposition fails.
471  double logNofSvdThresh = std::log(m_dementhonSvThresh)/lnOfSvdFactorUsed;
472  // Ensure that if the user chose a threshold > svdThresholdLimit, at least 1 iteration of svd decomposition is performed
473  int nbMaxIter = static_cast<int>(std::max<double>(std::ceil(logNOfSvdThresholdLimit - logNofSvdThresh), 1.));
474  double svdThreshold = m_dementhonSvThresh;
475  int irank = 0;
476  for (int i = 0; (i < nbMaxIter) && (!isRankEqualTo3); ++i) {
477  irank = A.pseudoInverse(Ap, sv, svdThreshold, imA, imAt, kAt);
478  if (irank == 3) {
479  isRankEqualTo3 = true;
480  }
481  else {
482  isRankEqualTo3 = false;
483  svdThreshold *= svdFactorUsedWhenFailure;
484  }
485  }
486 
487  if (!isRankEqualTo3) {
488  std::stringstream errorMsg;
489  errorMsg << "In Dementhon planar, after ";
490  errorMsg << nbMaxIter;
491  errorMsg << " trials multiplying the svd threshold by ";
492  errorMsg << svdFactorUsedWhenFailure;
493  errorMsg << ", rank (";
494  errorMsg << irank;
495  errorMsg << ") is still not 3";
496  throw(vpException(vpException::fatalError, errorMsg.str()));
497  }
498  // calcul de U
499  vpColVector U(4);
500  for (unsigned int i = 0; i < 4; ++i) {
501  U[i] = kAt[0][i];
502  }
503 #if (DEBUG_LEVEL2)
504  {
505  std::cout << "A" << std::endl << A << std::endl;
506  std::cout << "A^+" << std::endl << Ap << std::endl;
507  std::cout << "U^T = " << U.t() << std::endl;
508  }
509 #endif
510 
511  vpColVector xi(npt);
512  vpColVector yi(npt);
513 
514  for (unsigned int i = 0; i < npt; ++i) {
515  xi[i] = c3d[i].get_x();
516  yi[i] = c3d[i].get_y();
517  }
518 
519  vpColVector I04(4), J04(4);
520  I04 = Ap * xi;
521  J04 = Ap * yi;
522 
523  vpHomogeneousMatrix cMo1, cMo2;
524  calculTwoSolutionsDementhonPlan(I04, J04, U, cMo1, cMo2);
525 
526 #if DEBUG_LEVEL3
527  double res = sqrt(computeResidualDementhon(cMo1) / npt);
528  vpThetaUVector erc;
529  cMo1.extract(erc);
530  std::cout << "cMo Start Tree 1 : res " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
531  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
532  res = sqrt(computeResidualDementhon(cMo2) / npt);
533  cMo2.extract(erc);
534  std::cout << "cMo Start Tree 2 : res " << res << " Theta U rotation: " << vpMath::deg(erc[0]) << " "
535  << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
536 #endif
537 
538  int erreur1 = calculArbreDementhon(Ap, U, cMo1);
539  int erreur2 = calculArbreDementhon(Ap, U, cMo2);
540 
541  if ((erreur1 == -1) && (erreur2 == -1)) {
542  throw(
543  vpException(vpException::fatalError, "Error in Dementhon planar: z < 0 with Start Tree 1 and Start Tree 2..."));
544  }
545  if ((erreur1 == 0) && (erreur2 == -1)) {
546  cMo = cMo1;
547  }
548  if ((erreur1 == -1) && (erreur2 == 0)) {
549  cMo = cMo2;
550  }
551  if ((erreur1 == 0) && (erreur2 == 0)) {
552  double s1 = computeResidualDementhon(cMo1);
553  double s2 = computeResidualDementhon(cMo2);
554 
555  if (s1 <= s2) {
556  cMo = cMo1;
557  }
558  else {
559  cMo = cMo2;
560  }
561 
562 #if DEBUG_LEVEL3
563  if (erreur1 == -1)
564  std::cout << "Pb z < 0 with Start Tree 1" << std::endl;
565  if (erreur2 == -1)
566  std::cout << "Pb z < 0 with Start Tree 2" << std::endl;
567  if (s1 <= s2)
568  std::cout << " Tree 1 chosen " << std::endl;
569  else
570  std::cout << " Tree 2 chosen " << std::endl;
571 #endif
572  }
573 
574  cMo[0][3] -= ((cdg[0] * cMo[0][0]) + (cdg[1] * cMo[0][1]) + (cdg[2] * cMo[0][2]));
575  cMo[1][3] -= ((cdg[0] * cMo[1][0]) + (cdg[1] * cMo[1][1]) + (cdg[2] * cMo[1][2]));
576  cMo[2][3] -= ((cdg[0] * cMo[2][0]) + (cdg[1] * cMo[2][1]) + (cdg[2] * cMo[2][2]));
577 
578 #if (DEBUG_LEVEL1)
579  std::cout << "end CCalculPose::PoseDementhonPlan()" << std::endl;
580 #endif
581 }
582 
584 {
585  double squared_error = 0;
586 
587  // Be careful: since c3d has been translated so that point0 is at the cdg,
588  // cMo here corresponds to object frame at that point, i.e, only the one used
589  // internally to Dementhon's method
590 
591  for (unsigned int i = 0; i < npt; ++i) {
592 
593  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];
594  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];
595  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];
596 
597  double x = X / Z;
598  double y = Y / Z;
599 
600  squared_error += vpMath::sqr(x - c3d[i].get_x()) + vpMath::sqr(y - c3d[i].get_y());
601  }
602  return squared_error;
603 }
604 
605 #undef EPS_DEM
606 #undef SEUIL_RESIDUAL
607 #undef ITER_MAX
608 #undef DEBUG_LEVEL1
609 #undef DEBUG_LEVEL2
610 #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.