54 #include <visp3/vision/vpPose.h>
55 #include <visp3/core/vpColVector.h>
56 #include <visp3/core/vpRansac.h>
57 #include <visp3/vision/vpPoseException.h>
58 #include <visp3/core/vpMath.h>
60 #if defined (VISP_HAVE_CPP11_COMPATIBILITY)
61 # include <unordered_map>
64 #if defined(VISP_HAVE_OPENMP)
73 struct ComparePointDuplicate {
74 bool operator()(
const vpPoint &point1,
const vpPoint &point2 )
const {
75 if (point1.
oP[0] < point2.
oP[0])
return true;
76 if (point1.
oP[0] > point2.
oP[0])
return false;
78 if (point1.
oP[1] < point2.
oP[1])
return true;
79 if (point1.
oP[1] > point2.
oP[1])
return false;
81 if (point1.
oP[2] < point2.
oP[2])
return true;
82 if (point1.
oP[2] > point2.
oP[2])
return false;
84 if (point1.
p[0] < point2.
p[0])
return true;
85 if (point1.
p[0] > point2.
p[0])
return false;
87 if (point1.
p[1] < point2.
p[1])
return true;
88 if (point1.
p[1] > point2.
p[1])
return false;
95 struct ComparePointAlmostDuplicate {
96 bool operator()(
const vpPoint &point1,
const vpPoint &point2 )
const {
97 if (point1.
oP[0] - point2.
oP[0] < -eps)
return true;
98 if (point1.
oP[0] - point2.
oP[0] > eps)
return false;
100 if (point1.
oP[1] - point2.
oP[1] < -eps)
return true;
101 if (point1.
oP[1] - point2.
oP[1] > eps)
return false;
103 if (point1.
oP[2] - point2.
oP[2] < -eps)
return true;
104 if (point1.
oP[2] - point2.
oP[2] > eps)
return false;
106 if (point1.
p[0] - point2.
p[0] < -eps)
return true;
107 if (point1.
p[0] - point2.
p[0] > eps)
return false;
109 if (point1.
p[1] - point2.
p[1] < -eps)
return true;
110 if (point1.
p[1] - point2.
p[1] > eps)
return false;
117 struct CompareObjectPointDegenerate {
118 bool operator()(
const vpPoint &point1,
const vpPoint &point2 )
const {
119 if (point1.
oP[0] - point2.
oP[0] < -eps)
return true;
120 if (point1.
oP[0] - point2.
oP[0] > eps)
return false;
122 if (point1.
oP[1] - point2.
oP[1] < -eps)
return true;
123 if (point1.
oP[1] - point2.
oP[1] > eps)
return false;
125 if (point1.
oP[2] - point2.
oP[2] < -eps)
return true;
126 if (point1.
oP[2] - point2.
oP[2] > eps)
return false;
133 struct CompareImagePointDegenerate {
134 bool operator()(
const vpPoint &point1,
const vpPoint &point2 )
const {
135 if (point1.
p[0] - point2.
p[0] < -eps)
return true;
136 if (point1.
p[0] - point2.
p[0] > eps)
return false;
138 if (point1.
p[1] - point2.
p[1] < -eps)
return true;
139 if (point1.
p[1] - point2.
p[1] > eps)
return false;
146 struct FindDegeneratePoint {
147 FindDegeneratePoint(
const vpPoint &pt ) : m_pt(pt) { }
149 bool operator() (
const vpPoint &pt) {
150 return ( (std::fabs(m_pt.oP[0] - pt.
oP[0]) < eps &&
151 std::fabs(m_pt.oP[1] - pt.
oP[1]) < eps &&
152 std::fabs(m_pt.oP[2] - pt.
oP[2]) < eps) ||
153 (std::fabs(m_pt.p[0] - pt.
p[0]) < eps &&
154 std::fabs(m_pt.p[1] - pt.
p[1]) < eps) );
160 #if defined (VISP_HAVE_CPP11_COMPATIBILITY)
162 struct HashDuplicate {
163 std::size_t operator()(
const vpPoint &point)
const {
168 res = res * 31 + hash<double>()( point.
oP[0] );
169 res = res * 31 + hash<double>()( point.
oP[1] );
170 res = res * 31 + hash<double>()( point.
oP[2] );
171 res = res * 31 + hash<double>()( point.
p[0] );
172 res = res * 31 + hash<double>()( point.
p[1] );
179 struct ComparePointDuplicateUnorderedMap {
180 bool operator()(
const vpPoint &point1,
const vpPoint &point2 )
const {
182 std::fabs(point1.
oP[0] - point2.
oP[0]) < std::numeric_limits<double>::epsilon() &&
183 std::fabs(point1.
oP[1] - point2.
oP[1]) < std::numeric_limits<double>::epsilon() &&
184 std::fabs(point1.
oP[2] - point2.
oP[2]) < std::numeric_limits<double>::epsilon() &&
185 std::fabs(point1.
p[0] - point2.
p[0]) < std::numeric_limits<double>::epsilon() &&
186 std::fabs(point1.
p[1] - point2.
p[1]) < std::numeric_limits<double>::epsilon()
193 bool vpPose::RansacFunctor::poseRansacImpl() {
194 unsigned int size = (
unsigned int) m_listOfUniquePoints.size();
196 unsigned int nbMinRandom = 4;
198 #if defined(_WIN32) && defined(_MSC_VER)
199 srand(m_initial_seed);
202 bool foundSolution =
false;
203 while (nbTrials < m_ransacMaxTrials && m_nbInliers < (
unsigned int) m_ransacNbInlierConsensus)
206 std::vector<unsigned int> cur_consensus;
208 std::vector<unsigned int> cur_outliers;
210 std::vector<unsigned int> cur_randoms;
212 std::vector<vpPoint> cur_inliers;
221 std::vector<bool> usedPt(size,
false);
224 for(
unsigned int i = 0; i < nbMinRandom;)
226 if((
size_t) std::count(usedPt.begin(), usedPt.end(),
true) == usedPt.size()) {
232 #if defined(_WIN32) && defined(_MSC_VER)
233 unsigned int r_ = (
unsigned int) rand() % size;
235 unsigned int r_ = (
unsigned int) rand_r(&m_initial_seed) % size;
240 #if defined(_WIN32) && defined(_MSC_VER)
241 r_ = (
unsigned int) rand() % size;
243 r_ = (
unsigned int) rand_r(&m_initial_seed) % size;
248 vpPoint pt = m_listOfUniquePoints[r_];
250 bool degenerate =
false;
251 if (m_checkDegeneratePoints) {
252 if ( std::find_if(poseMin.listOfPoints.begin(), poseMin.listOfPoints.end(), FindDegeneratePoint(pt)) != poseMin.listOfPoints.end()) {
259 cur_randoms.push_back(r_);
265 if(poseMin.
npt < nbMinRandom) {
271 bool is_valid_lagrange =
false;
272 bool is_valid_dementhon =
false;
275 double r_lagrange = DBL_MAX;
276 double r_dementhon = DBL_MAX;
281 is_valid_lagrange =
true;
287 is_valid_dementhon =
true;
292 is_valid_lagrange =
false;
293 r_lagrange = DBL_MAX;
297 is_valid_dementhon =
false;
298 r_dementhon = DBL_MAX;
303 if(is_valid_lagrange || is_valid_dementhon) {
305 if (r_lagrange < r_dementhon) {
307 cMo_tmp = cMo_lagrange;
311 cMo_tmp = cMo_dementhon;
313 r = sqrt(r) / (double) nbMinRandom;
316 bool isPoseValid =
true;
318 isPoseValid = m_func(&cMo_tmp);
327 if (isPoseValid && r < m_ransacThreshold)
329 unsigned int nbInliersCur = 0;
330 unsigned int iter = 0;
331 for (std::vector<vpPoint>::const_iterator it = m_listOfUniquePoints.begin(); it != m_listOfUniquePoints.end(); ++it, iter++)
338 double error = sqrt(d);
339 if(error < m_ransacThreshold) {
340 bool degenerate =
false;
341 if (m_checkDegeneratePoints) {
342 if ( std::find_if(cur_inliers.begin(), cur_inliers.end(), FindDegeneratePoint(pt)) != cur_inliers.end() ) {
350 cur_consensus.push_back(iter);
351 cur_inliers.push_back(*it);
353 cur_outliers.push_back(iter);
357 cur_outliers.push_back(iter);
361 if(nbInliersCur > m_nbInliers)
363 foundSolution =
true;
364 m_best_consensus = cur_consensus;
365 m_nbInliers = nbInliersCur;
370 if(nbTrials >= m_ransacMaxTrials) {
371 foundSolution =
true;
382 return foundSolution;
385 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
387 vpPose::RansacFunctor* f =
reinterpret_cast<vpPose::RansacFunctor*
>(arg);
405 if (
listP.size() != listOfPoints.size()) {
406 std::cerr <<
"You should not modify vpPose::listP!" << std::endl;
407 listOfPoints = std::vector<vpPoint>(
listP.begin(),
listP.end());
410 ransacInliers.clear();
411 ransacInlierIndex.clear();
413 std::vector<unsigned int> best_consensus;
414 unsigned int nbInliers = 0;
418 if (listOfPoints.size() < 4) {
421 "Not enough point to compute the pose")) ;
424 std::vector<vpPoint> listOfUniquePoints;
425 std::map<size_t, size_t> mapOfUniquePointIndex;
433 if (prefilterDuplicatePoints || prefilterAlmostDuplicatePoints || prefilterDegeneratePoints) {
435 if (prefilterDuplicatePoints) {
436 #if defined (VISP_HAVE_CPP11_COMPATIBILITY)
437 std::unordered_map<vpPoint, size_t, HashDuplicate, ComparePointDuplicateUnorderedMap> filterMap;
439 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end(); ++it_pt, index_pt++) {
440 if (filterMap.find(*it_pt) == filterMap.end()) {
441 filterMap[*it_pt] = index_pt;
443 listOfUniquePoints.push_back(*it_pt);
444 mapOfUniquePointIndex[listOfUniquePoints.size()-1] = index_pt;
448 std::map<vpPoint, size_t, ComparePointDuplicate> filterMap;
450 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end(); ++it_pt, index_pt++) {
451 if (filterMap.find(*it_pt) == filterMap.end()) {
452 filterMap[*it_pt] = index_pt;
454 listOfUniquePoints.push_back(*it_pt);
455 mapOfUniquePointIndex[listOfUniquePoints.size()-1] = index_pt;
459 }
else if (prefilterAlmostDuplicatePoints) {
460 std::map<vpPoint, size_t, ComparePointAlmostDuplicate> filterMap;
462 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end(); ++it_pt, index_pt++) {
463 if (filterMap.find(*it_pt) == filterMap.end()) {
464 filterMap[*it_pt] = index_pt;
466 listOfUniquePoints.push_back(*it_pt);
467 mapOfUniquePointIndex[listOfUniquePoints.size()-1] = index_pt;
472 std::map<vpPoint, size_t, CompareObjectPointDegenerate> filterObjectPointMap;
474 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end(); ++it_pt, index_pt++) {
475 if (filterObjectPointMap.find(*it_pt) == filterObjectPointMap.end()) {
476 filterObjectPointMap[*it_pt] = index_pt;
480 std::map<vpPoint, size_t, CompareImagePointDegenerate> filterImagePointMap;
481 for (std::map<vpPoint, size_t>::const_iterator it = filterObjectPointMap.begin(); it != filterObjectPointMap.end(); ++it) {
482 if (filterImagePointMap.find(it->first) == filterImagePointMap.end()) {
483 filterImagePointMap[it->first] = it->second;
485 listOfUniquePoints.push_back(it->first);
486 mapOfUniquePointIndex[listOfUniquePoints.size()-1] = it->second;
492 listOfUniquePoints = listOfPoints;
495 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end(); ++it_pt, index_pt++) {
496 mapOfUniquePointIndex[index_pt] = index_pt;
500 unsigned int size = (
unsigned int) listOfUniquePoints.size();
506 bool executeParallelVersion = useParallelRansac;
508 #if defined (VISP_HAVE_PTHREAD) || (defined (_WIN32) && !defined(WINRT_8_0))
509 # define VP_THREAD_OK
513 if (executeParallelVersion) {
514 #if !defined (VP_THREAD_OK) && !defined (VISP_HAVE_OPENMP)
515 executeParallelVersion =
false;
516 std::cerr <<
"Pthread or WIN32 API or OpenMP is needed to use the parallel RANSAC version." << std::endl;
517 #elif !defined (VP_THREAD_OK)
519 #define PARALLEL_RANSAC_OPEN_MP
520 #elif !defined (VISP_HAVE_OPENMP)
521 if(nbParallelRansacThreads <= 0) {
523 executeParallelVersion =
false;
524 std::cerr <<
"OpenMP is needed to get the number of CPU threads so use the sequential mode instead." << std::endl;
526 nbThreads = nbParallelRansacThreads;
527 if (nbThreads == 1) {
528 executeParallelVersion =
false;
531 #elif defined (VP_THREAD_OK) && defined (VISP_HAVE_OPENMP)
532 if (nbParallelRansacThreads <= 0) {
534 nbThreads = omp_get_max_threads();
537 executeParallelVersion =
false;
543 bool foundSolution =
false;
545 if(executeParallelVersion) {
546 #if defined (PARALLEL_RANSAC_OPEN_MP)
555 #if defined(VISP_HAVE_OPENMP)
557 unsigned int initial_seed = (
unsigned int) omp_get_thread_num();
559 if(omp_get_num_threads() == 1) {
563 unsigned int initial_seed = 0;
566 #if defined(_WIN32) && defined(_MSC_VER)
570 unsigned int nbMinRandom = 4;
573 unsigned int nb_best_inliers = 0;
576 bool foundSolutionWithConsensus =
false;
579 for(
int nbTrials = 0; nbTrials < ransacMaxTrials; nbTrials++) {
581 if(!foundSolutionWithConsensus) {
583 std::vector<unsigned int> cur_consensus;
585 std::vector<unsigned int> cur_outliers;
587 std::vector<unsigned int> cur_randoms;
589 std::vector<vpPoint> cur_inliers;
595 std::vector<bool> usedPt(size,
false);
599 for(
unsigned int i = 0; i < nbMinRandom;) {
600 if((
size_t) std::count(usedPt.begin(), usedPt.end(),
true) == usedPt.size()) {
606 #if defined(_WIN32) && defined(_MSC_VER)
607 unsigned int r_ = (
unsigned int) rand() % size;
609 unsigned int r_ = (
unsigned int) rand_r(&initial_seed) % size;
614 #if defined(_WIN32) && defined(_MSC_VER)
615 r_ = (
unsigned int) rand() % size;
617 r_ = (
unsigned int) rand_r(&initial_seed) % size;
622 vpPoint pt = listOfUniquePoints[r_];
624 bool degenerate =
false;
625 if (checkDegeneratePoints) {
626 if ( std::find_if(poseMin.listOfPoints.begin(), poseMin.listOfPoints.end(), FindDegeneratePoint(pt)) != poseMin.listOfPoints.end()) {
633 cur_randoms.push_back(r_);
639 if(poseMin.
npt >= nbMinRandom) {
641 bool is_valid_lagrange =
false;
642 bool is_valid_dementhon =
false;
646 double r_lagrange = DBL_MAX;
647 double r_dementhon = DBL_MAX;
652 is_valid_lagrange =
true;
658 is_valid_dementhon =
true;
663 is_valid_lagrange =
false;
664 r_lagrange = DBL_MAX;
668 is_valid_dementhon =
false;
669 r_dementhon = DBL_MAX;
674 if(is_valid_lagrange || is_valid_dementhon) {
675 if (r_lagrange < r_dementhon) {
677 cMo_tmp = cMo_lagrange;
681 cMo_tmp = cMo_dementhon;
683 r = sqrt(r) / (double) nbMinRandom;
686 bool isPoseValid =
true;
688 isPoseValid = func(&cMo_tmp);
691 if (isPoseValid && r < ransacThreshold) {
692 unsigned int nbInliersCur = 0;
693 unsigned int iter = 0;
694 for (std::vector<vpPoint>::const_iterator it = listOfUniquePoints.begin(); it != listOfUniquePoints.end(); ++it, iter++) {
700 double error = sqrt(d) ;
701 if(error < ransacThreshold) {
702 bool degenerate =
false;
703 if (checkDegeneratePoints) {
704 if ( std::find_if(cur_inliers.begin(), cur_inliers.end(), FindDegeneratePoint(pt)) != cur_inliers.end() ) {
712 cur_consensus.push_back(iter);
713 cur_inliers.push_back(*it);
715 cur_outliers.push_back(iter);
718 cur_outliers.push_back(iter);
722 #pragma omp critical (update_best_consensus_set)
724 if(nbInliersCur > nb_best_inliers) {
725 foundSolution =
true;
726 best_consensus = cur_consensus;
728 nb_best_inliers = nbInliersCur;
730 if(nbInliersCur >= ransacNbInlierConsensus) {
731 foundSolutionWithConsensus =
true;
741 nbInliers = best_consensus.size();
743 #elif defined(VP_THREAD_OK)
744 std::vector<vpThread *> threads((
size_t) nbThreads);
745 std::vector<RansacFunctor> ransac_func((
size_t) nbThreads);
747 int splitTrials = ransacMaxTrials / nbThreads;
748 for(
size_t i = 0; i < (size_t) nbThreads; i++) {
749 unsigned int initial_seed = (
unsigned int) i;
750 if(i < (
size_t) nbThreads-1) {
751 ransac_func[i] = RansacFunctor(cMo, ransacNbInlierConsensus, splitTrials, ransacThreshold,
752 initial_seed, checkDegeneratePoints, listOfUniquePoints, func);
754 int maxTrialsRemainder = ransacMaxTrials - splitTrials * (nbThreads-1);
755 ransac_func[i] = RansacFunctor(cMo, ransacNbInlierConsensus, maxTrialsRemainder, ransacThreshold,
756 initial_seed, checkDegeneratePoints, listOfUniquePoints, func);
764 for(std::vector<vpPoint>::const_iterator it = listOfPoints.begin(); it != listOfPoints.end(); ++it) {
768 for(
size_t i = 0; i < (size_t) nbThreads; i++) {
773 bool successRansac =
false;
774 size_t best_consensus_size = 0;
775 for(
size_t i = 0; i < (size_t) nbThreads; i++) {
776 if(ransac_func[i].getResult()) {
777 successRansac =
true;
779 if(ransac_func[i].getBestConsensus().size() > best_consensus_size) {
780 nbInliers = ransac_func[i].getNbInliers();
781 best_consensus = ransac_func[i].getBestConsensus();
782 best_consensus_size = ransac_func[i].getBestConsensus().size();
787 foundSolution = successRansac;
791 RansacFunctor sequentialRansac(cMo, ransacNbInlierConsensus, ransacMaxTrials, ransacThreshold,
792 0, checkDegeneratePoints, listOfUniquePoints, func);
794 foundSolution = sequentialRansac.getResult();
797 nbInliers = sequentialRansac.getNbInliers();
798 best_consensus = sequentialRansac.getBestConsensus();
803 unsigned int nbMinRandom = 4;
825 if(nbInliers >= nbMinRandom)
829 for(
size_t i = 0 ; i < best_consensus.size(); i++)
831 vpPoint pt = listOfUniquePoints[best_consensus[i]];
834 ransacInliers.push_back(pt);
838 for(std::vector<unsigned int>::const_iterator it_index = best_consensus.begin();
839 it_index != best_consensus.end(); ++it_index) {
840 ransacInlierIndex.push_back((
unsigned int) mapOfUniquePointIndex[*it_index]);
844 bool is_valid_lagrange =
false;
845 bool is_valid_dementhon =
false;
848 double r_lagrange = DBL_MAX;
849 double r_dementhon = DBL_MAX;
854 is_valid_lagrange =
true;
860 is_valid_dementhon =
true;
865 is_valid_lagrange =
false;
866 r_lagrange = DBL_MAX;
870 is_valid_dementhon =
false;
871 r_dementhon = DBL_MAX;
874 if(is_valid_lagrange || is_valid_dementhon) {
875 if (r_lagrange < r_dementhon) {
887 if(func != NULL && !func(&cMo)) {
891 if(computeCovariance) {
892 covarianceMatrix = pose.covarianceMatrix;
900 return foundSolution;
917 probability = std::max(probability, 0.0);
918 probability = std::min(probability, 1.0);
919 epsilon = std::max(epsilon, 0.0);
920 epsilon = std::min(epsilon, 1.0);
927 if (maxIterations <= 0) {
928 maxIterations = std::numeric_limits<int>::max();
931 double logarg, logval, N;
932 logarg = -std::pow(1.0 - epsilon, sampleSize);
933 logval = log(1.0 + logarg);
934 if (
vpMath::nul(logval, std::numeric_limits<double>::epsilon())) {
935 std::cerr <<
"vpMath::nul(log(1.0 - std::pow(1.0 - epsilon, sampleSize)), std::numeric_limits<double>::epsilon())"
940 N = log(std::max(1.0 - probability, std::numeric_limits<double>::epsilon())) / logval;
941 if (logval < 0.0 && N < maxIterations) {
942 return (
int) ceil(N);
945 return maxIterations;
973 std::vector<vpPoint> &p3D,
974 const unsigned int &numberOfInlierToReachAConsensus,
975 const double &threshold,
976 unsigned int &ninliers,
977 std::vector<vpPoint> &listInliers,
979 const int &maxNbTrials )
984 for(
unsigned int i = 0 ; i < p2D.size() ; i++)
986 for(
unsigned int j = 0 ; j < p3D.size() ; j++)
988 vpPoint pt(p3D[j].getWorldCoordinates());
989 pt.
set_x(p2D[i].get_x());
990 pt.
set_y(p2D[i].get_y());
996 if (pose.
listP.size() < 4)
998 vpERROR_TRACE(
"Ransac method cannot be used in that case ") ;
1002 "Not enough point (%d) to compute the pose by ransac",pose.
listP.size())) ;
Implementation of an homogeneous matrix and operations on such kind of matrices.
static bool isNaN(const double value)
void setRansacThreshold(const double &t)
void set_x(const double x)
Set the point x coordinate in the image plane.
void track(const vpHomogeneousMatrix &cMo)
something is not initialized
double get_y() const
Get the point y coordinate in the image plane.
std::list< vpPoint > listP
Array of point (use here class vpPoint)
Class that defines what is a point.
bool poseRansac(vpHomogeneousMatrix &cMo, bool(*func)(vpHomogeneousMatrix *)=NULL)
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)
unsigned int getRansacNbInliers() const
static bool nul(double x, double s=0.001)
static double sqr(double x)
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
void set_y(const double y)
Set the point y coordinate in the image plane.
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, bool(*func)(vpHomogeneousMatrix *)=NULL)
double get_x() const
Get the point x coordinate in the image plane.
unsigned int npt
Number of point used in pose computation.
void setRansacMaxTrials(const int &rM)
void setRansacNbInliersToReachConsensus(const unsigned int &nbC)
Error that can be emited by the vpPose class and its derivates.
void addPoint(const vpPoint &P)
static int computeRansacIterations(double probability, double epsilon, const int sampleSize=4, int maxIterations=2000)
std::vector< vpPoint > getRansacInliers() const
void setCovarianceComputation(const bool &flag)
double computeResidual(const vpHomogeneousMatrix &cMo) const
Compute and return the residual expressed in meter for the pose matrix 'cMo'.