Visual Servoing Platform  version 3.6.1 under development (2024-04-24)
vpPoseRansac.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 
39 #include <algorithm> // std::count
40 #include <cmath> // std::fabs
41 #include <float.h> // DBL_MAX
42 #include <iostream>
43 #include <limits> // numeric_limits
44 #include <map>
45 
46 #include <visp3/core/vpColVector.h>
47 #include <visp3/core/vpMath.h>
48 #include <visp3/core/vpRansac.h>
49 #include <visp3/vision/vpPose.h>
50 #include <visp3/vision/vpPoseException.h>
51 
52 #if defined(VISP_HAVE_THREADS)
53 #include <thread>
54 #endif
55 
56 #define EPS 1e-6
57 
58 namespace
59 {
60 // For std::map<vpPoint>
61 struct CompareObjectPointDegenerate
62 {
63  bool operator()(const vpPoint &point1, const vpPoint &point2) const
64  {
65  bool rc = false;
66  const double dist1 =
67  (point1.get_oX() * point1.get_oX()) + (point1.get_oY() * point1.get_oY()) + (point1.get_oZ() * point1.get_oZ());
68  const double dist2 =
69  (point2.get_oX() * point2.get_oX()) + (point2.get_oY() * point2.get_oY()) + (point2.get_oZ() * point2.get_oZ());
70 
71  if ((dist1 - dist2) < (-3 * EPS * EPS)) {
72  return true;
73  }
74  if ((dist1 - dist2) > (3 * EPS * EPS)) {
75  return false;
76  }
77 
78  if ((point1.oP[0] - point2.oP[0]) < -EPS) {
79  return true;
80  }
81  if ((point1.oP[0] - point2.oP[0]) > EPS) {
82  return false;
83  }
84 
85  if ((point1.oP[1] - point2.oP[1]) < -EPS) {
86  return true;
87  }
88  if ((point1.oP[1] - point2.oP[1]) > EPS) {
89  return false;
90  }
91 
92  if ((point1.oP[2] - point2.oP[2]) < -EPS) {
93  return true;
94  }
95  if ((point1.oP[2] - point2.oP[2]) > EPS) {
96  return false;
97  }
98 
99  return rc;
100  }
101 };
102 
103 // For std::map<vpPoint>
104 struct CompareImagePointDegenerate
105 {
106  bool operator()(const vpPoint &point1, const vpPoint &point2) const
107  {
108  bool rc = false;
109  const double dist1 = (point1.get_x() * point1.get_x()) + (point1.get_y() * point1.get_y());
110  const double dist2 = (point2.get_x() * point2.get_x()) + (point2.get_y() * point2.get_y());
111  if ((dist1 - dist2) < (-2 * EPS * EPS)) {
112  return true;
113  }
114  if ((dist1 - dist2) > (2 * EPS * EPS)) {
115  return false;
116  }
117 
118  if ((point1.p[0] - point2.p[0]) < -EPS) {
119  return true;
120  }
121  if ((point1.p[0] - point2.p[0]) > EPS) {
122  return false;
123  }
124 
125  if ((point1.p[1] - point2.p[1]) < -EPS) {
126  return true;
127  }
128  if ((point1.p[1] - point2.p[1]) > EPS) {
129  return false;
130  }
131 
132  return rc;
133  }
134 };
135 
136 // std::find_if
137 struct FindDegeneratePoint
138 {
139  explicit FindDegeneratePoint(const vpPoint &pt) : m_pt(pt) { }
140 
141  bool operator()(const vpPoint &pt)
142  {
143  bool result_cond1 = ((std::fabs(m_pt.oP[0] - pt.oP[0]) < EPS) && (std::fabs(m_pt.oP[1] - pt.oP[1]) < EPS)
144  && (std::fabs(m_pt.oP[2] - pt.oP[2]) < EPS));
145  bool result_cond2 = (std::fabs(m_pt.p[0] - pt.p[0]) < EPS) && (std::fabs(m_pt.p[1] - pt.p[1]) < EPS);
146  return result_cond1 || result_cond2;
147  }
148 
149  vpPoint m_pt;
150 };
151 } // namespace
152 
153 bool vpPose::vpRansacFunctor::poseRansacImpl()
154 {
155  const unsigned int size = static_cast<unsigned int>(m_listOfUniquePoints.size());
156  unsigned int nbMinRandom = 4;
157  int nbTrials = 0;
158 
159  vpPoint p; // Point used to project using the estimated pose
160 
161  bool foundSolution = false;
162  while ((nbTrials < m_ransacMaxTrials) && (m_nbInliers < m_ransacNbInlierConsensus)) {
163  // Hold the list of the index of the inliers (points in the consensus set)
164  std::vector<unsigned int> cur_consensus;
165  // Hold the list of the index of the outliers
166  std::vector<unsigned int> cur_outliers;
167  // Hold the list of the index of the points randomly picked
168  std::vector<unsigned int> cur_randoms;
169  // Hold the list of the current inliers points to avoid to add a
170  // degenerate point if the flag is set
171  std::vector<vpPoint> cur_inliers;
172 
173  // Use a temporary variable because if not, the cMo passed in parameters
174  // will be modified when
175  // we compute the pose for the minimal sample sets but if the pose is not
176  // correct when we pass a function pointer we do not want to modify the
177  // cMo passed in parameters
178  vpHomogeneousMatrix cMo_tmp;
179 
180  // Vector of used points, initialized at false for all points
181  std::vector<bool> usedPt(size, false);
182 
183  vpPose poseMin;
184  for (unsigned int i = 0; i < nbMinRandom;) {
185  if (static_cast<size_t>(std::count(usedPt.begin(), usedPt.end(), true)) == usedPt.size()) {
186  // All points was picked once, break otherwise we stay in an infinite loop
187  break;
188  }
189 
190  // Pick a point randomly
191  unsigned int r_ = m_uniRand.uniform(0, size);
192 
193  while (usedPt[r_]) {
194  // If already picked, pick another point randomly
195  r_ = m_uniRand.uniform(0, size);
196  }
197  // Mark this point as already picked
198  usedPt[r_] = true;
199  vpPoint pt = m_listOfUniquePoints[r_];
200 
201  bool degenerate = false;
202  if (m_checkDegeneratePoints) {
203  if (std::find_if(poseMin.listOfPoints.begin(), poseMin.listOfPoints.end(), FindDegeneratePoint(pt)) !=
204  poseMin.listOfPoints.end()) {
205  degenerate = true;
206  }
207  }
208 
209  if (!degenerate) {
210  poseMin.addPoint(pt);
211  cur_randoms.push_back(r_);
212  // Increment the number of points picked
213  ++i;
214  }
215  }
216 
217  if (poseMin.npt < nbMinRandom) {
218  ++nbTrials;
219  continue;
220  }
221 
222  bool is_pose_valid = false;
223  double r_min = DBL_MAX;
224 
225  try {
226  is_pose_valid = poseMin.computePose(vpPose::DEMENTHON_LAGRANGE_VIRTUAL_VS, cMo_tmp);
227  r_min = poseMin.computeResidual(cMo_tmp);
228  }
229  catch (...) {
230  // no need to take action
231  }
232 
233  // If residual returned is not a number (NAN), set valid to false
234  if (vpMath::isNaN(r_min)) {
235  is_pose_valid = false;
236  }
237 
238  // If at pose computation is OK we can continue, otherwise pick another random set
239  if (is_pose_valid) {
240  double r = sqrt(r_min) / static_cast<double>(nbMinRandom); // FS should be r = sqrt(r_min / (double)nbMinRandom);
241  // Filter the pose using some criterion (orientation angles,
242  // translations, etc.)
243  bool isPoseValid = true;
244  if (m_func != nullptr) {
245  isPoseValid = m_func(cMo_tmp);
246  if (isPoseValid) {
247  m_cMo = cMo_tmp;
248  }
249  }
250  else {
251  // No post filtering on pose, so copy cMo_temp to cMo
252  m_cMo = cMo_tmp;
253  }
254 
255  if (isPoseValid && (r < m_ransacThreshold)) {
256  unsigned int nbInliersCur = 0;
257  unsigned int iter = 0;
258  std::vector<vpPoint>::const_iterator m_listofuniquepoints_end = m_listOfUniquePoints.end();
259  for (std::vector<vpPoint>::const_iterator it = m_listOfUniquePoints.begin(); it != m_listofuniquepoints_end;
260  ++it, ++iter) {
261  p.setWorldCoordinates(it->get_oX(), it->get_oY(), it->get_oZ());
262  p.track(m_cMo);
263 
264  double error = sqrt(vpMath::sqr(p.get_x() - it->get_x()) + vpMath::sqr(p.get_y() - it->get_y()));
265  if (error < m_ransacThreshold) {
266  bool degenerate = false;
267  if (m_checkDegeneratePoints) {
268  if (std::find_if(cur_inliers.begin(), cur_inliers.end(), FindDegeneratePoint(*it)) != cur_inliers.end()) {
269  degenerate = true;
270  }
271  }
272 
273  if (!degenerate) {
274  // the point is considered as inlier if the error is below the
275  // threshold
276  ++nbInliersCur;
277  cur_consensus.push_back(iter);
278  cur_inliers.push_back(*it);
279  }
280  else {
281  cur_outliers.push_back(iter);
282  }
283  }
284  else {
285  cur_outliers.push_back(iter);
286  }
287  }
288 
289  if (nbInliersCur > m_nbInliers) {
290  foundSolution = true;
291  m_best_consensus = cur_consensus;
292  m_nbInliers = nbInliersCur;
293  }
294 
295  ++nbTrials;
296 
297  if (nbTrials >= m_ransacMaxTrials) {
298  foundSolution = true;
299  }
300  }
301  else {
302  ++nbTrials;
303  }
304  }
305  else {
306  ++nbTrials;
307  }
308  }
309 
310  return foundSolution;
311 }
312 
314 {
315  // Check only for adding / removing problem
316  // Do not take into account problem with element modification here
317  if (listP.size() != listOfPoints.size()) {
318  std::cerr << "You should not modify vpPose::listP!" << std::endl;
319  listOfPoints = std::vector<vpPoint>(listP.begin(), listP.end());
320  }
321 
322  ransacInliers.clear();
323  ransacInlierIndex.clear();
324 
325  std::vector<unsigned int> best_consensus;
326  unsigned int nbInliers = 0;
327 
328  vpHomogeneousMatrix cMo_lagrange, cMo_dementhon;
329 
330  if (listOfPoints.size() < 4) {
331  throw(vpPoseException(vpPoseException::notInitializedError, "Not enough point to compute the pose"));
332  }
333 
334  std::vector<vpPoint> listOfUniquePoints;
335  std::map<size_t, size_t> mapOfUniquePointIndex;
336 
337  // Get RANSAC flags
338  bool prefilterDegeneratePoints = ransacFlag == PREFILTER_DEGENERATE_POINTS;
339  bool checkDegeneratePoints = ransacFlag == CHECK_DEGENERATE_POINTS;
340 
341  if (prefilterDegeneratePoints) {
342  // Remove degenerate object points
343  std::map<vpPoint, size_t, CompareObjectPointDegenerate> filterObjectPointMap;
344  size_t index_pt = 0;
345  std::vector<vpPoint>::const_iterator listofpoints_end = listOfPoints.end();
346  for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listofpoints_end;
347  ++it_pt, ++index_pt) {
348  if (filterObjectPointMap.find(*it_pt) == filterObjectPointMap.end()) {
349  filterObjectPointMap[*it_pt] = index_pt;
350  }
351  }
352 
353  std::map<vpPoint, size_t, CompareImagePointDegenerate> filterImagePointMap;
354  std::map<vpPoint, size_t, CompareObjectPointDegenerate>::const_iterator filterobjectpointmap_end = filterObjectPointMap.end();
355  for (std::map<vpPoint, size_t, CompareObjectPointDegenerate>::const_iterator it = filterObjectPointMap.begin();
356  it != filterobjectpointmap_end; ++it) {
357  if (filterImagePointMap.find(it->first) == filterImagePointMap.end()) {
358  filterImagePointMap[it->first] = it->second;
359 
360  listOfUniquePoints.push_back(it->first);
361  mapOfUniquePointIndex[listOfUniquePoints.size() - 1] = it->second;
362  }
363  }
364  }
365  else {
366  // No prefiltering
367  listOfUniquePoints = listOfPoints;
368 
369  size_t index_pt = 0;
370  std::vector<vpPoint>::const_iterator listofpoints_end = listOfPoints.end();
371  for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listofpoints_end;
372  ++it_pt, ++index_pt) {
373  mapOfUniquePointIndex[index_pt] = index_pt;
374  }
375  }
376 
377  if (listOfUniquePoints.size() < 4) {
378  throw(vpPoseException(vpPoseException::notInitializedError, "Not enough point to compute the pose"));
379  }
380 
381 #if defined(VISP_HAVE_THREADS)
382  unsigned int nbThreads = 1;
383  bool executeParallelVersion = useParallelRansac;
384 #else
385  bool executeParallelVersion = false;
386 #endif
387 
388  if (executeParallelVersion) {
389 #if defined(VISP_HAVE_THREADS)
390  if (nbParallelRansacThreads <= 0) {
391  // Get number of CPU threads
392  nbThreads = std::thread::hardware_concurrency();
393  if (nbThreads <= 1) {
394  nbThreads = 1;
395  executeParallelVersion = false;
396  }
397  }
398  else {
399  nbThreads = nbParallelRansacThreads;
400  }
401 #endif
402  }
403 
404  bool foundSolution = false;
405 
406  if (executeParallelVersion) {
407 #if defined(VISP_HAVE_THREADS)
408  std::vector<std::thread> threadpool;
409  std::vector<vpRansacFunctor> ransacWorkers;
410 
411  int splitTrials = ransacMaxTrials / nbThreads;
412  for (size_t i = 0; i < static_cast<size_t>(nbThreads); ++i) {
413  unsigned int initial_seed = static_cast<unsigned int>(i); //((unsigned int) time(nullptr) ^ i);
414  if (i < static_cast<size_t>(nbThreads) - 1) {
415  ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, splitTrials, ransacThreshold, initial_seed,
416  checkDegeneratePoints, listOfUniquePoints, func);
417  }
418  else {
419  int maxTrialsRemainder = ransacMaxTrials - splitTrials * (nbThreads - 1);
420  ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, maxTrialsRemainder, ransacThreshold, initial_seed,
421  checkDegeneratePoints, listOfUniquePoints, func);
422  }
423  }
424 
425  for (auto &worker : ransacWorkers) {
426  threadpool.emplace_back(&vpRansacFunctor::operator(), &worker);
427  }
428 
429  for (auto &th : threadpool) {
430  th.join();
431  }
432 
433  bool successRansac = false;
434  size_t best_consensus_size = 0;
435 
436  for (auto &worker : ransacWorkers) {
437  if (worker.getResult()) {
438  successRansac = true;
439 
440  if (worker.getBestConsensus().size() > best_consensus_size) {
441  nbInliers = worker.getNbInliers();
442  best_consensus = worker.getBestConsensus();
443  best_consensus_size = worker.getBestConsensus().size();
444  }
445  }
446  }
447 
448  foundSolution = successRansac;
449 #endif
450  }
451  else {
452  // Sequential RANSAC
453  vpRansacFunctor sequentialRansac(cMo, ransacNbInlierConsensus, ransacMaxTrials, ransacThreshold, 0,
454  checkDegeneratePoints, listOfUniquePoints, func);
455  sequentialRansac();
456  foundSolution = sequentialRansac.getResult();
457 
458  if (foundSolution) {
459  nbInliers = sequentialRansac.getNbInliers();
460  best_consensus = sequentialRansac.getBestConsensus();
461  }
462  }
463 
464  if (foundSolution) {
465  unsigned int nbMinRandom = 4;
466 
467  // --comment: print the nbInliers
468  // Display the random picked points (cur_randoms)
469  // Display the outliers (cur_outliers)
470 
471  // Even if the cardinality of the best consensus set is inferior to
472  // ransacNbInlierConsensus, we want to refine the solution with data in
473  // best_consensus and return this pose. This is an approach used for
474  // example in p118 in Multiple View Geometry in Computer Vision, Hartley,
475  // R.~I. and Zisserman, A.
476  if (nbInliers >= nbMinRandom) // if(nbInliers >= (unsigned)ransacNbInlierConsensus)
477  {
478  // Refine the solution using all the points in the consensus set and
479  // with VVS pose estimation
480  vpPose pose;
481  size_t best_consensus_size = best_consensus.size();
482  for (size_t i = 0; i < best_consensus_size; ++i) {
483  vpPoint pt = listOfUniquePoints[best_consensus[i]];
484 
485  pose.addPoint(pt);
486  ransacInliers.push_back(pt);
487  }
488 
489  // Update the list of inlier index
490  std::vector<unsigned int>::const_iterator best_consensus_end = best_consensus.end();
491  for (std::vector<unsigned int>::const_iterator it_index = best_consensus.begin();
492  it_index != best_consensus_end; ++it_index) {
493  ransacInlierIndex.push_back(static_cast<unsigned int>(mapOfUniquePointIndex[*it_index]));
494  }
495 
496  pose.setCovarianceComputation(computeCovariance);
498 
499  // In some rare cases, the final pose could not respect the pose
500  // criterion even if the 4 minimal points picked respect the pose
501  // criterion.
502  if ((func != nullptr) && (!func(cMo))) {
503  return false;
504  }
505 
506  if (computeCovariance) {
507  covarianceMatrix = pose.covarianceMatrix;
508  }
509  }
510  else {
511  return false;
512  }
513  }
514 
515  return foundSolution;
516 }
517 
518 int vpPose::computeRansacIterations(double probability, double epsilon, const int sampleSize, int maxIterations)
519 {
520  probability = std::max<double>(probability, 0.0);
521  probability = std::min<double>(probability, 1.0);
522  epsilon = std::max<double>(epsilon, 0.0);
523  epsilon = std::min<double>(epsilon, 1.0);
524 
525  if (vpMath::nul(epsilon)) {
526  // no outliers
527  return 1;
528  }
529 
530  if (maxIterations <= 0) {
531  maxIterations = std::numeric_limits<int>::max();
532  }
533 
534  double logarg, logval, N;
535  logarg = -std::pow(1.0 - epsilon, sampleSize);
536 #ifdef VISP_HAVE_FUNC_LOG1P
537  logval = log1p(logarg);
538 #else
539  logval = log(1.0 + logarg);
540 #endif
541  if (vpMath::nul(logval, std::numeric_limits<double>::epsilon())) {
542  std::cerr << "vpMath::nul(log(1.0 - std::pow(1.0 - epsilon, "
543  "sampleSize)), std::numeric_limits<double>::epsilon())"
544  << std::endl;
545  return 0;
546  }
547 
548  N = log(std::max<double>(1.0 - probability, std::numeric_limits<double>::epsilon())) / logval;
549  if ((logval < 0.0) && (N < maxIterations)) {
550  return static_cast<int>(ceil(N));
551  }
552 
553  return maxIterations;
554 }
555 
556 void vpPose::findMatch(std::vector<vpPoint> &p2D, std::vector<vpPoint> &p3D,
557  const unsigned int &numberOfInlierToReachAConsensus, const double &threshold,
558  unsigned int &ninliers, std::vector<vpPoint> &listInliers, vpHomogeneousMatrix &cMo,
559  const int &maxNbTrials, bool useParallelRansac, unsigned int nthreads,
560  bool (*func)(const vpHomogeneousMatrix &))
561 {
562  vpPose pose;
563 
564  unsigned int p2D_size = p2D.size();
565  unsigned int p3D_size = p3D.size();
566  for (unsigned int i = 0; i < p2D_size; ++i) {
567  for (unsigned int j = 0; j < p3D_size; ++j) {
568  vpPoint pt(p3D[j].getWorldCoordinates());
569  pt.set_x(p2D[i].get_x());
570  pt.set_y(p2D[i].get_y());
571  pose.addPoint(pt);
572  }
573  }
574 
575  if (pose.listP.size() < 4) {
576  vpERROR_TRACE("Ransac method cannot be used in that case ");
577  vpERROR_TRACE("(at least 4 points are required)");
578  vpERROR_TRACE("Not enough point (%d) to compute the pose ", pose.listP.size());
579  throw(vpPoseException(vpPoseException::notEnoughPointError, "Not enough point (%d) to compute the pose by ransac",
580  pose.listP.size()));
581  }
582  else {
583  pose.setUseParallelRansac(useParallelRansac);
584  pose.setNbParallelRansacThreads(nthreads);
585  // Since we add duplicate points, we need to check for degenerate configuration
587  pose.setRansacMaxTrials(maxNbTrials);
588  pose.setRansacNbInliersToReachConsensus(numberOfInlierToReachAConsensus);
589  pose.setRansacThreshold(threshold);
590  pose.computePose(vpPose::RANSAC, cMo, func);
591  ninliers = pose.getRansacNbInliers();
592  listInliers = pose.getRansacInliers();
593  }
594 }
void track(const vpHomogeneousMatrix &cMo)
Implementation of an homogeneous matrix and operations on such kind of matrices.
static bool isNaN(double value)
Definition: vpMath.cpp:93
static double sqr(double x)
Definition: vpMath.h:201
static bool nul(double x, double threshold=0.001)
Definition: vpMath.h:440
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
void set_x(double x)
Set the point x coordinate in the image plane.
Definition: vpPoint.cpp:504
double get_y() const
Get the point y coordinate in the image plane.
Definition: vpPoint.cpp:465
double get_oZ() const
Get the point oZ coordinate in the object frame.
Definition: vpPoint.cpp:458
double get_x() const
Get the point x coordinate in the image plane.
Definition: vpPoint.cpp:463
double get_oY() const
Get the point oY coordinate in the object frame.
Definition: vpPoint.cpp:456
void setWorldCoordinates(double oX, double oY, double oZ)
Definition: vpPoint.cpp:110
void set_y(double y)
Set the point y coordinate in the image plane.
Definition: vpPoint.cpp:506
Error that can be emitted by the vpPose class and its derivatives.
@ notEnoughPointError
Not enough points to compute the pose.
@ notInitializedError
Something is not initialized.
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
Definition: vpPose.h:78
void setRansacMaxTrials(const int &rM)
Definition: vpPose.h:404
static int computeRansacIterations(double probability, double epsilon, const int sampleSize=4, int maxIterations=2000)
void addPoint(const vpPoint &P)
Definition: vpPose.cpp:93
void setRansacNbInliersToReachConsensus(const unsigned int &nbC)
Definition: vpPose.h:385
bool poseRansac(vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=nullptr)
@ RANSAC
Definition: vpPose.h:88
@ DEMENTHON_LAGRANGE_VIRTUAL_VS
Definition: vpPose.h:99
void setCovarianceComputation(const bool &flag)
Definition: vpPose.h:427
static void findMatch(std::vector< vpPoint > &p2D, std::vector< vpPoint > &p3D, const unsigned int &numberOfInlierToReachAConsensus, const double &threshold, unsigned int &ninliers, std::vector< vpPoint > &listInliers, vpHomogeneousMatrix &cMo, const int &maxNbTrials=10000, bool useParallelRansac=true, unsigned int nthreads=0, bool(*func)(const vpHomogeneousMatrix &)=nullptr)
unsigned int npt
Number of point used in pose computation.
Definition: vpPose.h:114
std::list< vpPoint > listP
Array of point (use here class vpPoint)
Definition: vpPose.h:115
double computeResidual(const vpHomogeneousMatrix &cMo) const
Compute and return the sum of squared residuals expressed in meter^2 for the pose matrix cMo.
Definition: vpPose.cpp:289
void setRansacFilterFlag(const RANSAC_FILTER_FLAGS &flag)
Definition: vpPose.h:458
@ CHECK_DEGENERATE_POINTS
Definition: vpPose.h:111
@ PREFILTER_DEGENERATE_POINTS
Definition: vpPose.h:110
unsigned int getRansacNbInliers() const
Definition: vpPose.h:409
void setUseParallelRansac(bool use)
Definition: vpPose.h:489
std::vector< vpPoint > getRansacInliers() const
Definition: vpPose.h:419
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=nullptr)
Definition: vpPose.cpp:339
void setNbParallelRansacThreads(int nb)
Definition: vpPose.h:475
void setRansacThreshold(const double &t)
Definition: vpPose.h:390
vpColVector p
Definition: vpTracker.h:67
#define vpERROR_TRACE
Definition: vpDebug.h:382