Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
testPoseRansac2.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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  * Test RANSAC 3D pose estimation method.
33  *
34  *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 
38 #ifdef VISP_HAVE_CATCH2
39 #define CATCH_CONFIG_RUNNER
40 #include <catch.hpp>
41 
42 #include <algorithm>
43 #include <iomanip>
44 #include <map>
45 #include <visp3/core/vpGaussRand.h>
46 #include <visp3/core/vpHomogeneousMatrix.h>
47 #include <visp3/core/vpIoTools.h>
48 #include <visp3/core/vpMath.h>
49 #include <visp3/core/vpPoint.h>
50 #include <visp3/vision/vpPose.h>
51 
52 namespace
53 {
54 
55 bool samePoints(const vpPoint &pt1, const vpPoint &pt2)
56 {
57  return vpMath::equal(pt1.get_oX(), pt2.get_oX(), std::numeric_limits<double>::epsilon()) &&
58  vpMath::equal(pt1.get_oY(), pt2.get_oY(), std::numeric_limits<double>::epsilon()) &&
59  vpMath::equal(pt1.get_oZ(), pt2.get_oZ(), std::numeric_limits<double>::epsilon()) &&
60  vpMath::equal(pt1.get_x(), pt2.get_x(), std::numeric_limits<double>::epsilon()) &&
61  vpMath::equal(pt1.get_y(), pt2.get_y(), std::numeric_limits<double>::epsilon());
62 }
63 
64 int checkInlierIndex(const std::vector<unsigned int> &vectorOfFoundInlierIndex,
65  const std::vector<bool> &vectorOfOutlierFlags)
66 {
67  int nbInlierIndexOk = 0;
68 
69  for (std::vector<unsigned int>::const_iterator it = vectorOfFoundInlierIndex.begin();
70  it != vectorOfFoundInlierIndex.end(); ++it) {
71  if (!vectorOfOutlierFlags[*it]) {
72  nbInlierIndexOk++;
73  }
74  }
75 
76  return nbInlierIndexOk;
77 }
78 
79 bool checkInlierPoints(const std::vector<vpPoint> &vectorOfFoundInlierPoints,
80  const std::vector<unsigned int> &vectorOfFoundInlierIndex,
81  const std::vector<vpPoint> &bunnyModelPoints_noisy)
82 {
83  for (size_t i = 0; i < vectorOfFoundInlierPoints.size(); i++) {
84  if (!samePoints(vectorOfFoundInlierPoints[i], bunnyModelPoints_noisy[vectorOfFoundInlierIndex[i]])) {
85  std::cerr << "Problem with the inlier index and the corresponding "
86  "inlier point!"
87  << std::endl;
88  std::cerr << "Returned inliers: oX=" << std::setprecision(std::numeric_limits<double>::max_digits10)
89  << vectorOfFoundInlierPoints[i].get_oX()
90  << ", oY=" << vectorOfFoundInlierPoints[i].get_oY()
91  << ", oZ=" << vectorOfFoundInlierPoints[i].get_oZ()
92  << " ; x=" << vectorOfFoundInlierPoints[i].get_x()
93  << ", y=" << vectorOfFoundInlierPoints[i].get_y()
94  << std::endl;
95  const vpPoint& pt = bunnyModelPoints_noisy[vectorOfFoundInlierIndex[i]];
96  std::cerr << "Object points: oX=" << std::setprecision(std::numeric_limits<double>::max_digits10)
97  << pt.get_oX()
98  << ", oY=" << pt.get_oY()
99  << ", oZ=" << pt.get_oZ()
100  << " ; x=" << pt.get_x()
101  << ", y=" << pt.get_y()
102  << std::endl;
103  return false;
104  }
105  }
106 
107  return true;
108 }
109 
110 void readBunnyModelPoints(const std::string &filename, std::vector<vpPoint> &bunnyModelPoints,
111  std::vector<vpPoint> &bunnyModelPoints_noisy)
112 {
113  // Read the model
114  std::ifstream file(filename);
115  if (!file.is_open()) {
116  return;
117  }
118 
119  // ground truth cMo
120  const vpTranslationVector translation(-0.14568, 0.154567, 1.4462);
121  const vpRzyxVector zyxVector(vpMath::rad(12.4146f), vpMath::rad(-75.5478f), vpMath::rad(138.5607f));
122  vpHomogeneousMatrix cMo_groundTruth(translation, vpThetaUVector(zyxVector));
123 
124  vpGaussRand gaussian_noise(0.0002, 0.0);
125  double oX = 0, oY = 0, oZ = 0;
126 
127  while (file >> oX >> oY >> oZ) {
128  vpPoint pt(oX, oY, oZ);
129  pt.project(cMo_groundTruth);
130  bunnyModelPoints.push_back(pt);
131 
132  // Add a small gaussian noise to the data
133  pt.set_x(pt.get_x() + gaussian_noise());
134  pt.set_y(pt.get_y() + gaussian_noise());
135  bunnyModelPoints_noisy.push_back(pt);
136  }
137 
138  // Print the number of model points
139  std::cout << "The raw model contains " << bunnyModelPoints.size() << " points." << std::endl;
140  std::cout << "cMo_groundTruth=\n" << cMo_groundTruth << std::endl << std::endl;
141 }
142 
143 bool testRansac(const std::vector<vpPoint> &bunnyModelPoints_original,
144  const std::vector<vpPoint> &bunnyModelPoints_noisy_original,
145  size_t nb_model_points, bool test_duplicate, bool test_degenerate)
146 {
147  std::vector<vpPoint> bunnyModelPoints = bunnyModelPoints_original;
148  std::vector<vpPoint> bunnyModelPoints_noisy = bunnyModelPoints_noisy_original;
149  // Resize
150  if (nb_model_points > 0) {
151  bunnyModelPoints.resize(nb_model_points);
152  bunnyModelPoints_noisy.resize(nb_model_points);
153  }
154 
155  vpPose ground_truth_pose, real_pose;
156  ground_truth_pose.addPoints(bunnyModelPoints);
157  real_pose.addPoints(bunnyModelPoints_noisy);
158 
159  vpHomogeneousMatrix cMo_dementhon, cMo_lagrange;
160  real_pose.computePose(vpPose::DEMENTHON, cMo_dementhon);
161  real_pose.computePose(vpPose::LAGRANGE, cMo_lagrange);
162  double r_dementhon = real_pose.computeResidual(cMo_dementhon);
163  double r_lagrange = real_pose.computeResidual(cMo_lagrange);
164 
165  vpHomogeneousMatrix cMo_estimated;
166  if (r_lagrange < r_dementhon) {
167  cMo_estimated = cMo_lagrange;
168  } else {
169  cMo_estimated = cMo_dementhon;
170  }
171  real_pose.computePose(vpPose::VIRTUAL_VS, cMo_estimated);
172  double r_vvs = ground_truth_pose.computeResidual(cMo_estimated);
173 
174  std::cout << "\ncMo estimated using VVS on data with small gaussian noise:\n" << cMo_estimated << std::endl;
175  std::cout << "Corresponding residual: " << r_vvs << std::endl;
176 
177  size_t nbOutliers = (size_t)(0.35 * bunnyModelPoints_noisy.size());
178  vpGaussRand noise(0.01, 0.008);
179  // Vector that indicates if the point is an outlier or not
180  std::vector<bool> vectorOfOutlierFlags(bunnyModelPoints_noisy.size(), false);
181  // Generate outliers points
182  for (size_t i = 0; i < nbOutliers; i++) {
183  bunnyModelPoints_noisy[i].set_x(bunnyModelPoints_noisy[i].get_x() + noise());
184  bunnyModelPoints_noisy[i].set_y(bunnyModelPoints_noisy[i].get_y() + noise());
185  vectorOfOutlierFlags[i] = true;
186  }
187 
188  if (test_duplicate) {
189  // Add some duplicate points
190  size_t nbDuplicatePoints = 100;
191  for (size_t i = 0; i < nbDuplicatePoints; i++) {
192  size_t index = (size_t)rand() % bunnyModelPoints_noisy.size();
193  vpPoint duplicatePoint = bunnyModelPoints_noisy[index];
194  bunnyModelPoints_noisy.push_back(duplicatePoint);
195  vectorOfOutlierFlags.push_back(true);
196  }
197  }
198 
199  if (test_degenerate) {
200  // Add some degenerate points
201  size_t nbDegeneratePoints = 100;
202  double degenerate_tolerence = 9.999e-7; // 1e-6 is used in the code to
203  // detect if a point is degenerate
204  // or not
205  std::vector<vpPoint> listOfDegeneratePoints;
206  for (size_t i = 0; i < nbDegeneratePoints; i++) {
207  size_t index = (size_t)rand() % bunnyModelPoints_noisy.size();
208  vpPoint degeneratePoint = bunnyModelPoints_noisy[index];
209 
210  // Object point is degenerate
211  degeneratePoint.set_oX(degeneratePoint.get_oX() + degenerate_tolerence);
212  degeneratePoint.set_oY(degeneratePoint.get_oY() + degenerate_tolerence);
213  degeneratePoint.set_oZ(degeneratePoint.get_oZ() - degenerate_tolerence);
214 
215  // Add duplicate 3D points
216  listOfDegeneratePoints.push_back(degeneratePoint);
217 
218  // Image point is degenerate
219  index = (size_t)rand() % bunnyModelPoints_noisy.size();
220  degeneratePoint = bunnyModelPoints_noisy[index];
221 
222  degeneratePoint.set_x(degeneratePoint.get_x() + degenerate_tolerence);
223  degeneratePoint.set_y(degeneratePoint.get_y() - degenerate_tolerence);
224 
225  // Add duplicate 2D points
226  listOfDegeneratePoints.push_back(degeneratePoint);
227  }
228 
229  for (std::vector<vpPoint>::const_iterator it_degenerate = listOfDegeneratePoints.begin();
230  it_degenerate != listOfDegeneratePoints.end(); ++it_degenerate) {
231  bunnyModelPoints_noisy.push_back(*it_degenerate);
232  vectorOfOutlierFlags.push_back(true);
233  }
234  }
235 
236  // Shuffle the data vector
237  std::vector<size_t> vectorOfIndex(bunnyModelPoints_noisy.size());
238  for (size_t i = 0; i < vectorOfIndex.size(); i++) {
239  vectorOfIndex[i] = i;
240  }
241  std::random_shuffle(vectorOfIndex.begin(), vectorOfIndex.end());
242 
243  std::vector<vpPoint> bunnyModelPoints_noisy_tmp = bunnyModelPoints_noisy;
244  bunnyModelPoints_noisy.clear();
245  std::vector<bool> vectorOfOutlierFlags_tmp = vectorOfOutlierFlags;
246  vectorOfOutlierFlags.clear();
247  for (std::vector<size_t>::const_iterator it = vectorOfIndex.begin(); it != vectorOfIndex.end(); ++it) {
248  bunnyModelPoints_noisy.push_back(bunnyModelPoints_noisy_tmp[*it]);
249  vectorOfOutlierFlags.push_back(vectorOfOutlierFlags_tmp[*it]);
250  }
251 
252  // Add data to vpPose
253  vpPose pose;
254  vpPose pose_ransac, pose_ransac2;
255 
256  vpPose pose_ransac_parallel, pose_ransac_parallel2;
257  pose_ransac_parallel.setUseParallelRansac(true);
258  pose_ransac_parallel2.setUseParallelRansac(true);
259 
264  for (std::vector<vpPoint>::const_iterator it = bunnyModelPoints_noisy.begin(); it != bunnyModelPoints_noisy.end(); ++it) {
265  pose.addPoint(*it);
266  }
267  // Test addPoints
268  pose_ransac.addPoints(bunnyModelPoints_noisy);
269  pose_ransac2.addPoints(bunnyModelPoints_noisy);
270  pose_ransac_parallel.addPoints(bunnyModelPoints_noisy);
271  pose_ransac_parallel2.addPoints(bunnyModelPoints_noisy);
272 
273  // Print the number of points in the final data vector
274  std::cout << "\nNumber of model points in the noisy data vector: " << bunnyModelPoints_noisy.size() << " points."
275  << std::endl
276  << std::endl;
277 
278  unsigned int nbInlierToReachConsensus = (unsigned int)(60.0 * (double)(bunnyModelPoints_noisy.size()) / 100.0);
279  double threshold = 0.001;
280 
281  // RANSAC with 1000 iterations
282  pose_ransac.setRansacNbInliersToReachConsensus(nbInlierToReachConsensus);
283  pose_ransac.setRansacThreshold(threshold);
284  pose_ransac.setRansacMaxTrials(1000);
285  pose_ransac_parallel.setRansacNbInliersToReachConsensus(nbInlierToReachConsensus);
286  pose_ransac_parallel.setRansacThreshold(threshold);
287  pose_ransac_parallel.setRansacMaxTrials(1000);
288 
289  pose_ransac_parallel2.setRansacNbInliersToReachConsensus(nbInlierToReachConsensus);
290  pose_ransac_parallel2.setRansacThreshold(threshold);
291  pose_ransac_parallel2.setRansacMaxTrials(vpPose::computeRansacIterations(0.99, 0.4, 4, -1));
292 
293  // RANSAC with p=0.99, epsilon=0.4
294  pose_ransac2.setRansacNbInliersToReachConsensus(nbInlierToReachConsensus);
295  pose_ransac2.setRansacThreshold(threshold);
296  int ransac_iterations = vpPose::computeRansacIterations(0.99, 0.4, 4, -1);
297  pose_ransac2.setRansacMaxTrials(ransac_iterations);
298  std::cout << "Number of RANSAC iterations to ensure p=0.99 and epsilon=0.4: " << ransac_iterations << std::endl;
299 
300  vpHomogeneousMatrix cMo_estimated_RANSAC;
301  vpChrono chrono_RANSAC;
302  chrono_RANSAC.start();
303  pose_ransac.computePose(vpPose::RANSAC, cMo_estimated_RANSAC);
304  chrono_RANSAC.stop();
305 
306  std::cout << "\ncMo estimated with RANSAC (1000 iterations) on noisy data:\n" << cMo_estimated_RANSAC << std::endl;
307  std::cout << "Computation time: " << chrono_RANSAC.getDurationMs() << " ms" << std::endl;
308 
309  double r_RANSAC_estimated = ground_truth_pose.computeResidual(cMo_estimated_RANSAC);
310  std::cout << "Corresponding residual (1000 iterations): " << r_RANSAC_estimated << std::endl;
311 
312  vpHomogeneousMatrix cMo_estimated_RANSAC_2;
313  chrono_RANSAC.start();
314  pose_ransac2.computePose(vpPose::RANSAC, cMo_estimated_RANSAC_2);
315  chrono_RANSAC.stop();
316 
317  std::cout << "\ncMo estimated with RANSAC (" << ransac_iterations << " iterations) on noisy data:\n"
318  << cMo_estimated_RANSAC_2 << std::endl;
319  std::cout << "Computation time: " << chrono_RANSAC.getDurationMs() << " ms" << std::endl;
320 
321  double r_RANSAC_estimated_2 = ground_truth_pose.computeResidual(cMo_estimated_RANSAC_2);
322  std::cout << "Corresponding residual (" << ransac_iterations << " iterations): " << r_RANSAC_estimated_2 << std::endl;
323 
324  pose.computePose(vpPose::DEMENTHON, cMo_dementhon);
325  pose.computePose(vpPose::LAGRANGE, cMo_lagrange);
326  r_dementhon = pose.computeResidual(cMo_dementhon);
327  r_lagrange = pose.computeResidual(cMo_lagrange);
328 
329  if (r_lagrange < r_dementhon) {
330  cMo_estimated = cMo_lagrange;
331  } else {
332  cMo_estimated = cMo_dementhon;
333  }
334 
335  pose.computePose(vpPose::VIRTUAL_VS, cMo_estimated);
336  std::cout << "\ncMo estimated with only VVS on noisy data:\n" << cMo_estimated << std::endl;
337 
338  double r_estimated = ground_truth_pose.computeResidual(cMo_estimated);
339  std::cout << "Corresponding residual: " << r_estimated << std::endl;
340 
341  vpHomogeneousMatrix cMo_estimated_RANSAC_parallel;
342  vpChrono chrono_RANSAC_parallel;
343  chrono_RANSAC_parallel.start();
344  pose_ransac_parallel.computePose(vpPose::RANSAC, cMo_estimated_RANSAC_parallel);
345  chrono_RANSAC_parallel.stop();
346 
347  std::cout << "\ncMo estimated with parallel RANSAC (1000 iterations) on "
348  "noisy data:\n"
349  << cMo_estimated_RANSAC_parallel << std::endl;
350  std::cout << "Computation time: " << chrono_RANSAC_parallel.getDurationMs() << " ms" << std::endl;
351 
352  double r_RANSAC_estimated_parallel = ground_truth_pose.computeResidual(cMo_estimated_RANSAC_parallel);
353  std::cout << "Corresponding residual (1000 iterations): " << r_RANSAC_estimated_parallel << std::endl;
354 
355  vpHomogeneousMatrix cMo_estimated_RANSAC_parallel2;
356  vpChrono chrono_RANSAC_parallel2;
357  chrono_RANSAC_parallel2.start();
358  pose_ransac_parallel2.computePose(vpPose::RANSAC, cMo_estimated_RANSAC_parallel2);
359  chrono_RANSAC_parallel2.stop();
360 
361  std::cout << "\ncMo estimated with parallel RANSAC (" << ransac_iterations << " iterations) on noisy data:\n"
362  << cMo_estimated_RANSAC_parallel2 << std::endl;
363  std::cout << "Computation time: " << chrono_RANSAC_parallel2.getDurationMs() << " ms" << std::endl;
364 
365  double r_RANSAC_estimated_parallel2 = ground_truth_pose.computeResidual(cMo_estimated_RANSAC_parallel2);
366  std::cout << "Corresponding residual (" << ransac_iterations << " iterations): " << r_RANSAC_estimated_parallel2
367  << std::endl;
368 
369  // Check inlier index
370  std::vector<unsigned int> vectorOfFoundInlierIndex = pose_ransac.getRansacInlierIndex();
371  int nbInlierIndexOk = checkInlierIndex(vectorOfFoundInlierIndex, vectorOfOutlierFlags);
372 
373  int nbTrueInlierIndex = (int)std::count(vectorOfOutlierFlags.begin(), vectorOfOutlierFlags.end(), false);
374  std::cout << "\nThere are " << nbInlierIndexOk << " true inliers found, " << vectorOfFoundInlierIndex.size()
375  << " inliers returned and " << nbTrueInlierIndex << " true inliers." << std::endl;
376 
377  // Check inlier points returned
378  std::vector<vpPoint> vectorOfFoundInlierPoints = pose_ransac.getRansacInliers();
379 
380  if (vectorOfFoundInlierPoints.size() != vectorOfFoundInlierIndex.size()) {
381  std::cerr << "The number of inlier index is different from the number of "
382  "inlier points!"
383  << std::endl;
384  return false;
385  }
386  if (!checkInlierPoints(vectorOfFoundInlierPoints, vectorOfFoundInlierIndex, bunnyModelPoints_noisy)) {
387  return false;
388  }
389 
390  // Check for RANSAC with p=0.99, epsilon=0.4
391  // Check inlier index
392  std::cout << "\nCheck for RANSAC iterations: " << ransac_iterations << std::endl;
393  std::vector<unsigned int> vectorOfFoundInlierIndex_2 = pose_ransac2.getRansacInlierIndex();
394  nbInlierIndexOk = checkInlierIndex(vectorOfFoundInlierIndex_2, vectorOfOutlierFlags);
395 
396  std::cout << "There are " << nbInlierIndexOk << " true inliers found, " << vectorOfFoundInlierIndex_2.size()
397  << " inliers returned and " << nbTrueInlierIndex << " true inliers." << std::endl;
398 
399  // Check inlier points returned
400  std::vector<vpPoint> vectorOfFoundInlierPoints_2 = pose_ransac2.getRansacInliers();
401  if (vectorOfFoundInlierPoints_2.size() != vectorOfFoundInlierIndex_2.size()) {
402  std::cerr << "The number of inlier index is different from the number of "
403  "inlier points!"
404  << std::endl;
405  return false;
406  }
407  if (!checkInlierPoints(vectorOfFoundInlierPoints_2, vectorOfFoundInlierIndex_2, bunnyModelPoints_noisy)) {
408  return false;
409  }
410 
411  // Check for parallel RANSAC
412  // Check inlier index
413  std::cout << "\nCheck for parallel RANSAC (1000 iterations)" << std::endl;
414  std::vector<unsigned int> vectorOfFoundInlierIndex_parallel = pose_ransac_parallel.getRansacInlierIndex();
415  nbInlierIndexOk = checkInlierIndex(vectorOfFoundInlierIndex_parallel, vectorOfOutlierFlags);
416 
417  std::cout << "There are " << nbInlierIndexOk << " true inliers found, " << vectorOfFoundInlierIndex_parallel.size()
418  << " inliers returned and " << nbTrueInlierIndex << " true inliers." << std::endl;
419 
420  // Check inlier points returned
421  std::vector<vpPoint> vectorOfFoundInlierPoints_parallel = pose_ransac_parallel.getRansacInliers();
422  if (vectorOfFoundInlierPoints_parallel.size() != vectorOfFoundInlierIndex_parallel.size()) {
423  std::cerr << "The number of inlier index is different from the number "
424  "of inlier points!"
425  << std::endl;
426  return false;
427  }
428  if (!checkInlierPoints(vectorOfFoundInlierPoints_parallel, vectorOfFoundInlierIndex_parallel,
429  bunnyModelPoints_noisy)) {
430  return false;
431  }
432 
433  // Check for parallel RANSAC 2
434  // Check inlier index
435  std::cout << "\nCheck for parallel RANSAC (" << ransac_iterations << " iterations)" << std::endl;
436  std::vector<unsigned int> vectorOfFoundInlierIndex_parallel2 = pose_ransac_parallel2.getRansacInlierIndex();
437  nbInlierIndexOk = checkInlierIndex(vectorOfFoundInlierIndex_parallel2, vectorOfOutlierFlags);
438 
439  std::cout << "There are " << nbInlierIndexOk << " true inliers found, " << vectorOfFoundInlierIndex_parallel2.size()
440  << " inliers returned and " << nbTrueInlierIndex << " true inliers." << std::endl;
441 
442  // Check inlier points returned
443  std::vector<vpPoint> vectorOfFoundInlierPoints_parallel2 = pose_ransac_parallel2.getRansacInliers();
444  if (vectorOfFoundInlierPoints_parallel2.size() != vectorOfFoundInlierIndex_parallel2.size()) {
445  std::cerr << "The number of inlier index is different from the number "
446  "of inlier points!"
447  << std::endl;
448  return false;
449  }
450  if (!checkInlierPoints(vectorOfFoundInlierPoints_parallel2, vectorOfFoundInlierIndex_parallel2,
451  bunnyModelPoints_noisy)) {
452  return false;
453  }
454 
455  if (r_RANSAC_estimated > threshold /*|| r_RANSAC_estimated_2 > threshold*/) {
456  std::cerr << "The pose estimated with the RANSAC method is badly estimated!" << std::endl;
457  std::cerr << "r_RANSAC_estimated=" << r_RANSAC_estimated << std::endl;
458  std::cerr << "threshold=" << threshold << std::endl;
459  return false;
460  } else {
461  if (r_RANSAC_estimated_parallel > threshold) {
462  std::cerr << "The pose estimated with the parallel RANSAC method is "
463  "badly estimated!"
464  << std::endl;
465  std::cerr << "r_RANSAC_estimated_parallel=" << r_RANSAC_estimated_parallel << std::endl;
466  std::cerr << "threshold=" << threshold << std::endl;
467  return false;
468  }
469  std::cout << "The pose estimated with the RANSAC method is well estimated!" << std::endl;
470  }
471 
472  return true;
473 }
474 } //namespace
475 
476 TEST_CASE("Print RANSAC number of iterations", "[ransac_pose]") {
477  const int sample_sizes[] = {2, 3, 4, 5, 6, 7, 8};
478  const double epsilon[] = {0.05, 0.1, 0.2, 0.25, 0.3, 0.4, 0.5};
479 
480  // Format output
481  const std::string spacing = " ";
482 
483  std::cout << spacing << " outliers percentage\n" << "nb pts\\";
484  for (int cpt2 = 0; cpt2 < 7; cpt2++) {
485  std::cout << std::setfill(' ') << std::setw(5) << epsilon[cpt2] << " ";
486  }
487  std::cout << std::endl;
488 
489  std::cout << std::setfill(' ') << std::setw(7) << "+";
490  for (int cpt2 = 0; cpt2 < 6; cpt2++) {
491  std::cout << std::setw(7) << "-------";
492  }
493  std::cout << std::endl;
494 
495  for (int cpt1 = 0; cpt1 < 7; cpt1++) {
496  std::cout << std::setfill(' ') << std::setw(6) << sample_sizes[cpt1] << "|";
497 
498  for (int cpt2 = 0; cpt2 < 7; cpt2++) {
499  int ransac_iters = vpPose::computeRansacIterations(0.99, epsilon[cpt2], sample_sizes[cpt1], -1);
500  std::cout << std::setfill(' ') << std::setw(6) << ransac_iters;
501  }
502  std::cout << std::endl;
503  }
504  std::cout << std::endl;
505 }
506 
507 TEST_CASE("RANSAC pose estimation tests", "[ransac_pose]") {
508  const std::vector<size_t> model_sizes = {10, 20, 50, 100, 200, 500, 1000, 0, 0};
509  const std::vector<bool> duplicates = {false, false, false, false, false, false, false, false, true};
510  const std::vector<bool> degenerates = {false, false, false, false, false, false, true, true, true};
511 
512  std::string visp_input_images = vpIoTools::getViSPImagesDataPath();
513  std::string model_filename = vpIoTools::createFilePath(visp_input_images, "3dmodel/bunny/bunny.xyz");
514  CHECK(vpIoTools::checkFilename(model_filename));
515 
516  std::vector<vpPoint> bunnyModelPoints, bunnyModelPoints_noisy_original;
517  readBunnyModelPoints(model_filename, bunnyModelPoints, bunnyModelPoints_noisy_original);
518  CHECK(bunnyModelPoints.size() == bunnyModelPoints_noisy_original.size());
519 
520  for (size_t i = 0; i < model_sizes.size(); i++) {
521  std::cout << "\n\n==============================================================================="
522  << std::endl;
523  if (model_sizes[i] == 0) {
524  std::cout << "Test on " << bunnyModelPoints_noisy_original.size() << " model points." << std::endl;
525  } else {
526  std::cout << "Test on " << model_sizes[i] << " model points." << std::endl;
527  }
528  std::cout << "Test duplicate: " << duplicates[i] << " ; Test degenerate: " << degenerates[i] << std::endl;
529 
530  CHECK(testRansac(bunnyModelPoints, bunnyModelPoints_noisy_original, model_sizes[i], duplicates[i], degenerates[i]));
531  }
532 }
533 
534 int main(int argc, char* argv[])
535 {
536 #if defined(__mips__) || defined(__mips) || defined(mips) || defined(__MIPS__)
537  // To avoid Debian test timeout
538  return EXIT_SUCCESS;
539 #endif
540 
541  Catch::Session session; // There must be exactly one instance
542 
543  // Let Catch (using Clara) parse the command line
544  session.applyCommandLine(argc, argv);
545 
546  int numFailed = session.run();
547 
548  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
549  // This clamping has already been applied, so just return it here
550  // You can also do any post run clean-up here
551  return numFailed;
552 }
553 #else
554 int main()
555 {
556  return 0;
557 }
558 #endif
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=NULL)
Definition: vpPose.cpp:374
double getDurationMs()
Definition: vpTime.cpp:392
double get_oY() const
Get the point Y coordinate in the object frame.
Definition: vpPoint.cpp:424
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1292
std::vector< unsigned int > getRansacInlierIndex() const
Definition: vpPose.h:259
Implementation of an homogeneous matrix and operations on such kind of matrices.
static bool equal(double x, double y, double s=0.001)
Definition: vpMath.h:296
void addPoints(const std::vector< vpPoint > &lP)
Definition: vpPose.cpp:164
void setRansacThreshold(const double &t)
Definition: vpPose.h:248
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRzyxVector.h:185
std::vector< vpPoint > getRansacInliers() const
Definition: vpPose.h:260
double get_oX() const
Get the point X coordinate in the object frame.
Definition: vpPoint.cpp:422
Class that defines what is a point.
Definition: vpPoint.h:58
void set_x(double x)
Set the point x coordinate in the image plane.
Definition: vpPoint.cpp:472
void start(bool reset=true)
Definition: vpTime.cpp:409
void set_y(double y)
Set the point y coordinate in the image plane.
Definition: vpPoint.cpp:474
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1537
void set_oY(double oY)
Set the point Y coordinate in the object frame.
Definition: vpPoint.cpp:465
void stop()
Definition: vpTime.cpp:424
void setUseParallelRansac(bool use)
Definition: vpPose.h:330
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
Definition: vpPose.h:80
double get_oZ() const
Get the point Z coordinate in the object frame.
Definition: vpPoint.cpp:426
static double rad(double deg)
Definition: vpMath.h:108
void setRansacMaxTrials(const int &rM)
Definition: vpPose.h:257
void setRansacNbInliersToReachConsensus(const unsigned int &nbC)
Definition: vpPose.h:247
void set_oZ(double oZ)
Set the point Z coordinate in the object frame.
Definition: vpPoint.cpp:467
Class for generating random number with normal probability density.
Definition: vpGaussRand.h:120
void set_oX(double oX)
Set the point X coordinate in the object frame.
Definition: vpPoint.cpp:463
double get_x() const
Get the point x coordinate in the image plane.
Definition: vpPoint.cpp:431
void setRansacFilterFlag(const RANSAC_FILTER_FLAGS &flag)
Definition: vpPose.h:299
double get_y() const
Get the point y coordinate in the image plane.
Definition: vpPoint.cpp:433
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:730
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:336
void addPoint(const vpPoint &P)
Definition: vpPose.cpp:149
Class that consider the case of a translation vector.
Implementation of a rotation vector as axis-angle minimal representation.
static int computeRansacIterations(double probability, double epsilon, const int sampleSize=4, int maxIterations=2000)