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>
52 #if defined(VISP_HAVE_THREADS)
60 #ifndef DOXYGEN_SHOULD_SKIP_THIS
64 struct CompareObjectPointDegenerate
66 bool operator()(
const vpPoint &point1,
const vpPoint &point2)
const
68 const unsigned int index_0 = 0;
69 const unsigned int index_1 = 1;
70 const unsigned int index_2 = 2;
71 const double val3 = 3.;
78 if ((dist1 - dist2) < (-val3 * EPS * EPS)) {
81 if ((dist1 - dist2) > (val3 * EPS * EPS)) {
85 if ((point1.
oP[index_0] - point2.
oP[index_0]) < -EPS) {
88 if ((point1.
oP[index_0] - point2.
oP[index_0]) > EPS) {
92 if ((point1.
oP[index_1] - point2.
oP[index_1]) < -EPS) {
95 if ((point1.
oP[index_1] - point2.
oP[index_1]) > EPS) {
99 if ((point1.
oP[index_2] - point2.
oP[index_2]) < -EPS) {
102 if ((point1.
oP[index_2] - point2.
oP[index_2]) > EPS) {
111 struct CompareImagePointDegenerate
113 bool operator()(
const vpPoint &point1,
const vpPoint &point2)
const
118 const double val2 = 2.;
119 if ((dist1 - dist2) < (-val2 * EPS * EPS)) {
122 if ((dist1 - dist2) > (val2 * EPS * EPS)) {
126 if ((point1.
p[0] - point2.
p[0]) < -EPS) {
129 if ((point1.
p[0] - point2.
p[0]) > EPS) {
133 if ((point1.
p[1] - point2.
p[1]) < -EPS) {
136 if ((point1.
p[1] - point2.
p[1]) > EPS) {
145 struct FindDegeneratePoint
147 explicit FindDegeneratePoint(
const vpPoint &pt) : m_pt(pt) { }
149 bool operator()(
const vpPoint &pt)
151 const unsigned int index_0 = 0;
152 const unsigned int index_1 = 1;
153 const unsigned int index_2 = 2;
154 bool result_cond1 = ((std::fabs(m_pt.oP[index_0] - pt.
oP[index_0]) < EPS) && (std::fabs(m_pt.oP[index_1] - pt.
oP[index_1]) < EPS)
155 && (std::fabs(m_pt.oP[index_2] - pt.
oP[index_2]) < EPS));
156 bool result_cond2 = (std::fabs(m_pt.p[index_0] - pt.
p[index_0]) < EPS) && (std::fabs(m_pt.p[index_1] - pt.
p[index_1]) < EPS);
157 return result_cond1 || result_cond2;
165 bool vpPose::vpRansacFunctor::poseRansacImpl()
167 const unsigned int size =
static_cast<unsigned int>(m_listOfUniquePoints.size());
168 const unsigned int nbMinRandom = 4;
173 bool foundSolution =
false;
174 while ((nbTrials < m_ransacMaxTrials) && (m_nbInliers < m_ransacNbInlierConsensus)) {
176 std::vector<unsigned int> cur_consensus;
178 std::vector<unsigned int> cur_outliers;
180 std::vector<unsigned int> cur_randoms;
183 std::vector<vpPoint> cur_inliers;
193 std::vector<bool> usedPt(size,
false);
197 bool stop_loop =
false;
198 while ((i < nbMinRandom) && (stop_loop ==
false)) {
199 if (
static_cast<size_t>(std::count(usedPt.begin(), usedPt.end(),
true)) == usedPt.size()) {
205 unsigned int r_ = m_uniRand.uniform(0, size);
209 r_ = m_uniRand.uniform(0, size);
213 vpPoint pt = m_listOfUniquePoints[r_];
215 bool degenerate =
false;
216 if (m_checkDegeneratePoints) {
217 if (std::find_if(poseMin.listOfPoints.begin(), poseMin.listOfPoints.end(), FindDegeneratePoint(pt)) !=
218 poseMin.listOfPoints.end()) {
225 cur_randoms.push_back(r_);
232 bool stop_for_loop =
false;
233 if (poseMin.
npt < nbMinRandom) {
235 stop_for_loop =
true;
238 if (!stop_for_loop) {
239 bool is_pose_valid =
false;
240 double r_min = DBL_MAX;
252 is_pose_valid =
false;
257 double r = sqrt(r_min) /
static_cast<double>(nbMinRandom);
260 bool isPoseValid =
true;
261 if (m_func !=
nullptr) {
262 isPoseValid = m_func(cMo_tmp);
272 if (isPoseValid && (r < m_ransacThreshold)) {
273 unsigned int nbInliersCur = 0;
274 unsigned int iter = 0;
275 std::vector<vpPoint>::const_iterator m_listofuniquepoints_end = m_listOfUniquePoints.end();
276 for (std::vector<vpPoint>::const_iterator it = m_listOfUniquePoints.begin(); it != m_listofuniquepoints_end;
282 if (error < m_ransacThreshold) {
283 bool degenerate =
false;
284 if (m_checkDegeneratePoints) {
285 if (std::find_if(cur_inliers.begin(), cur_inliers.end(), FindDegeneratePoint(*it)) != cur_inliers.end()) {
294 cur_consensus.push_back(iter);
295 cur_inliers.push_back(*it);
298 cur_outliers.push_back(iter);
302 cur_outliers.push_back(iter);
306 if (nbInliersCur > m_nbInliers) {
307 foundSolution =
true;
308 m_best_consensus = cur_consensus;
309 m_nbInliers = nbInliersCur;
314 if (nbTrials >= m_ransacMaxTrials) {
315 foundSolution =
true;
328 return foundSolution;
335 if (
listP.size() != listOfPoints.size()) {
336 std::cerr <<
"You should not modify vpPose::listP!" << std::endl;
337 listOfPoints = std::vector<vpPoint>(
listP.begin(),
listP.end());
340 ransacInliers.clear();
341 ransacInlierIndex.clear();
343 std::vector<unsigned int> best_consensus;
344 unsigned int nbInliers = 0;
348 const size_t minNbPoints = 4;
349 if (listOfPoints.size() < minNbPoints) {
353 std::vector<vpPoint> listOfUniquePoints;
354 std::map<size_t, size_t> mapOfUniquePointIndex;
360 if (prefilterDegeneratePoints) {
362 std::map<vpPoint, size_t, CompareObjectPointDegenerate> filterObjectPointMap;
364 std::vector<vpPoint>::const_iterator listofpoints_end = listOfPoints.end();
365 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listofpoints_end;
366 ++it_pt, ++index_pt) {
367 if (filterObjectPointMap.find(*it_pt) == filterObjectPointMap.end()) {
368 filterObjectPointMap[*it_pt] = index_pt;
372 std::map<vpPoint, size_t, CompareImagePointDegenerate> filterImagePointMap;
373 std::map<vpPoint, size_t, CompareObjectPointDegenerate>::const_iterator filterobjectpointmap_end = filterObjectPointMap.end();
374 for (std::map<vpPoint, size_t, CompareObjectPointDegenerate>::const_iterator it = filterObjectPointMap.begin();
375 it != filterobjectpointmap_end; ++it) {
376 if (filterImagePointMap.find(it->first) == filterImagePointMap.end()) {
377 filterImagePointMap[it->first] = it->second;
379 listOfUniquePoints.push_back(it->first);
380 mapOfUniquePointIndex[listOfUniquePoints.size() - 1] = it->second;
386 listOfUniquePoints = listOfPoints;
389 std::vector<vpPoint>::const_iterator listofpoints_end = listOfPoints.end();
390 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listofpoints_end;
391 ++it_pt, ++index_pt) {
392 mapOfUniquePointIndex[index_pt] = index_pt;
396 const unsigned int minNbUniquePts = 4;
397 if (listOfUniquePoints.size() < minNbUniquePts) {
401 #if defined(VISP_HAVE_THREADS)
402 unsigned int nbThreads = 1;
403 bool executeParallelVersion = useParallelRansac;
405 bool executeParallelVersion =
false;
408 if (executeParallelVersion) {
409 #if defined(VISP_HAVE_THREADS)
410 if (nbParallelRansacThreads <= 0) {
412 nbThreads = std::thread::hardware_concurrency();
413 if (nbThreads <= 1) {
415 executeParallelVersion =
false;
419 nbThreads = nbParallelRansacThreads;
424 bool foundSolution =
false;
426 if (executeParallelVersion) {
427 #if defined(VISP_HAVE_THREADS)
428 std::vector<std::thread> threadpool;
429 std::vector<vpRansacFunctor> ransacWorkers;
431 int splitTrials = ransacMaxTrials / nbThreads;
432 for (
size_t i = 0; i < static_cast<size_t>(nbThreads); ++i) {
433 unsigned int initial_seed =
static_cast<unsigned int>(i);
434 if (i <
static_cast<size_t>(nbThreads) - 1) {
435 ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, splitTrials, ransacThreshold, initial_seed,
436 checkDegeneratePoints, listOfUniquePoints, func);
439 int maxTrialsRemainder = ransacMaxTrials - splitTrials * (nbThreads - 1);
440 ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, maxTrialsRemainder, ransacThreshold, initial_seed,
441 checkDegeneratePoints, listOfUniquePoints, func);
445 for (
auto &worker : ransacWorkers) {
446 threadpool.emplace_back(&vpRansacFunctor::operator(), &worker);
449 for (
auto &th : threadpool) {
453 bool successRansac =
false;
454 size_t best_consensus_size = 0;
456 for (
auto &worker : ransacWorkers) {
457 if (worker.getResult()) {
458 successRansac =
true;
460 if (worker.getBestConsensus().size() > best_consensus_size) {
461 nbInliers = worker.getNbInliers();
462 best_consensus = worker.getBestConsensus();
463 best_consensus_size = worker.getBestConsensus().size();
468 foundSolution = successRansac;
473 vpRansacFunctor sequentialRansac(cMo, ransacNbInlierConsensus, ransacMaxTrials, ransacThreshold, 0,
474 checkDegeneratePoints, listOfUniquePoints, func);
476 foundSolution = sequentialRansac.getResult();
479 nbInliers = sequentialRansac.getNbInliers();
480 best_consensus = sequentialRansac.getBestConsensus();
485 const unsigned int nbMinRandom = 4;
496 if (nbInliers >= nbMinRandom)
501 size_t best_consensus_size = best_consensus.size();
502 for (
size_t i = 0; i < best_consensus_size; ++i) {
503 vpPoint pt = listOfUniquePoints[best_consensus[i]];
506 ransacInliers.push_back(pt);
510 std::vector<unsigned int>::const_iterator best_consensus_end = best_consensus.end();
511 for (std::vector<unsigned int>::const_iterator it_index = best_consensus.begin();
512 it_index != best_consensus_end; ++it_index) {
513 ransacInlierIndex.push_back(
static_cast<unsigned int>(mapOfUniquePointIndex[*it_index]));
522 if ((func !=
nullptr) && (!func(cMo))) {
526 if (computeCovariance) {
527 covarianceMatrix = pose.covarianceMatrix;
535 return foundSolution;
540 probability = std::max<double>(probability, 0.0);
541 probability = std::min<double>(probability, 1.0);
542 epsilon = std::max<double>(epsilon, 0.0);
543 epsilon = std::min<double>(epsilon, 1.0);
550 if (maxIterations <= 0) {
551 maxIterations = std::numeric_limits<int>::max();
554 double logarg, logval, N;
555 logarg = -std::pow(1.0 - epsilon, sampleSize);
556 #ifdef VISP_HAVE_FUNC_LOG1P
557 logval = log1p(logarg);
559 logval = log(1.0 + logarg);
561 if (
vpMath::nul(logval, std::numeric_limits<double>::epsilon())) {
562 std::cerr <<
"vpMath::nul(log(1.0 - std::pow(1.0 - epsilon, "
563 "sampleSize)), std::numeric_limits<double>::epsilon())"
568 N = log(std::max<double>(1.0 - probability, std::numeric_limits<double>::epsilon())) / logval;
569 if ((logval < 0.0) && (N < maxIterations)) {
570 return static_cast<int>(ceil(N));
573 return maxIterations;
577 const unsigned int &numberOfInlierToReachAConsensus,
const double &threshold,
579 const int &maxNbTrials,
bool useParallelRansac,
unsigned int nthreads,
580 FuncCheckValidityPose func)
584 size_t p2D_size = p2D.size();
585 size_t p3D_size = p3D.size();
586 for (
size_t i = 0; i < p2D_size; ++i) {
587 for (
size_t j = 0; j < p3D_size; ++j) {
588 vpPoint pt(p3D[j].getWorldCoordinates());
589 pt.
set_x(p2D[i].get_x());
590 pt.
set_y(p2D[i].get_y());
595 const size_t minNbPts = 4;
596 if (pose.
listP.size() < minNbPts) {
void track(const vpHomogeneousMatrix &cMo)
Implementation of an homogeneous matrix and operations on such kind of matrices.
static bool isNaN(double value)
static double sqr(double x)
static bool nul(double x, double threshold=0.001)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
double get_oX() const
Get the point oX coordinate in the object frame.
void set_x(double x)
Set the point x coordinate in the image plane.
double get_y() const
Get the point y coordinate in the image plane.
double get_oZ() const
Get the point oZ coordinate in the object frame.
double get_x() const
Get the point x coordinate in the image plane.
double get_oY() const
Get the point oY coordinate in the object frame.
void setWorldCoordinates(double oX, double oY, double oZ)
void set_y(double y)
Set the point y coordinate in the image plane.
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...
void setRansacMaxTrials(const int &rM)
static int computeRansacIterations(double probability, double epsilon, const int sampleSize=4, int maxIterations=2000)
void addPoint(const vpPoint &P)
void setRansacNbInliersToReachConsensus(const unsigned int &nbC)
@ DEMENTHON_LAGRANGE_VIRTUAL_VS
void setCovarianceComputation(const bool &flag)
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, FuncCheckValidityPose func=nullptr)
unsigned int npt
Number of point used in pose computation.
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, FuncCheckValidityPose func=nullptr)
std::list< vpPoint > listP
Array of point (use here class vpPoint)
double computeResidual(const vpHomogeneousMatrix &cMo) const
Compute and return the sum of squared residuals expressed in meter^2 for the pose matrix cMo.
void setRansacFilterFlag(const RANSAC_FILTER_FLAGS &flag)
@ CHECK_DEGENERATE_POINTS
@ PREFILTER_DEGENERATE_POINTS
unsigned int getRansacNbInliers() const
void setUseParallelRansac(bool use)
std::vector< vpPoint > getRansacInliers() const
void setNbParallelRansacThreads(int nb)
bool poseRansac(vpHomogeneousMatrix &cMo, FuncCheckValidityPose func=nullptr)
void setRansacThreshold(const double &t)