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 (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
61 struct CompareObjectPointDegenerate {
62 bool operator()(
const vpPoint &point1,
const vpPoint &point2)
const
68 if (dist1 - dist2 < -3 * eps * eps)
70 if (dist1 - dist2 > 3 * eps * eps)
73 if (point1.
oP[0] - point2.
oP[0] < -eps)
75 if (point1.
oP[0] - point2.
oP[0] > eps)
78 if (point1.
oP[1] - point2.
oP[1] < -eps)
80 if (point1.
oP[1] - point2.
oP[1] > eps)
83 if (point1.
oP[2] - point2.
oP[2] < -eps)
85 if (point1.
oP[2] - point2.
oP[2] > eps)
93 struct CompareImagePointDegenerate {
94 bool operator()(
const vpPoint &point1,
const vpPoint &point2)
const
98 if (dist1 - dist2 < -2 * eps * eps)
100 if (dist1 - dist2 > 2 * eps * eps)
103 if (point1.
p[0] - point2.
p[0] < -eps)
105 if (point1.
p[0] - point2.
p[0] > eps)
108 if (point1.
p[1] - point2.
p[1] < -eps)
110 if (point1.
p[1] - point2.
p[1] > eps)
118 struct FindDegeneratePoint {
119 explicit FindDegeneratePoint(
const vpPoint &pt) : m_pt(pt) {}
121 bool operator()(
const vpPoint &pt)
123 return ((std::fabs(m_pt.oP[0] - pt.
oP[0]) < eps && std::fabs(m_pt.oP[1] - pt.
oP[1]) < eps &&
124 std::fabs(m_pt.oP[2] - pt.
oP[2]) < eps) ||
125 (std::fabs(m_pt.p[0] - pt.
p[0]) < eps && std::fabs(m_pt.p[1] - pt.
p[1]) < eps));
132 bool vpPose::RansacFunctor::poseRansacImpl()
134 const unsigned int size = (
unsigned int)m_listOfUniquePoints.size();
135 unsigned int nbMinRandom = 4;
140 bool foundSolution =
false;
141 while (nbTrials < m_ransacMaxTrials && m_nbInliers < m_ransacNbInlierConsensus) {
143 std::vector<unsigned int> cur_consensus;
145 std::vector<unsigned int> cur_outliers;
147 std::vector<unsigned int> cur_randoms;
150 std::vector<vpPoint> cur_inliers;
160 std::vector<bool> usedPt(size,
false);
163 for (
unsigned int i = 0; i < nbMinRandom;) {
164 if ((
size_t)std::count(usedPt.begin(), usedPt.end(),
true) == usedPt.size()) {
170 unsigned int r_ = m_uniRand.uniform(0, size);
174 r_ = m_uniRand.uniform(0, size);
178 vpPoint pt = m_listOfUniquePoints[r_];
180 bool degenerate =
false;
181 if (m_checkDegeneratePoints) {
182 if (std::find_if(poseMin.listOfPoints.begin(), poseMin.listOfPoints.end(), FindDegeneratePoint(pt)) !=
183 poseMin.listOfPoints.end()) {
190 cur_randoms.push_back(r_);
196 if (poseMin.
npt < nbMinRandom) {
201 bool is_pose_valid =
false;
202 double r_min = DBL_MAX;
212 is_pose_valid =
false;
217 double r = sqrt(r_min) / (double)nbMinRandom;
220 bool isPoseValid =
true;
221 if (m_func != NULL) {
222 isPoseValid = m_func(cMo_tmp);
231 if (isPoseValid && r < m_ransacThreshold) {
232 unsigned int nbInliersCur = 0;
233 unsigned int iter = 0;
234 for (std::vector<vpPoint>::const_iterator it = m_listOfUniquePoints.begin(); it != m_listOfUniquePoints.end();
240 if (error < m_ransacThreshold) {
241 bool degenerate =
false;
242 if (m_checkDegeneratePoints) {
243 if (std::find_if(cur_inliers.begin(), cur_inliers.end(), FindDegeneratePoint(*it)) != cur_inliers.end()) {
252 cur_consensus.push_back(iter);
253 cur_inliers.push_back(*it);
255 cur_outliers.push_back(iter);
258 cur_outliers.push_back(iter);
262 if (nbInliersCur > m_nbInliers) {
263 foundSolution =
true;
264 m_best_consensus = cur_consensus;
265 m_nbInliers = nbInliersCur;
270 if (nbTrials >= m_ransacMaxTrials) {
271 foundSolution =
true;
281 return foundSolution;
301 if (
listP.size() != listOfPoints.size()) {
302 std::cerr <<
"You should not modify vpPose::listP!" << std::endl;
303 listOfPoints = std::vector<vpPoint>(
listP.begin(),
listP.end());
306 ransacInliers.clear();
307 ransacInlierIndex.clear();
309 std::vector<unsigned int> best_consensus;
310 unsigned int nbInliers = 0;
314 if (listOfPoints.size() < 4) {
318 std::vector<vpPoint> listOfUniquePoints;
319 std::map<size_t, size_t> mapOfUniquePointIndex;
325 if (prefilterDegeneratePoints) {
327 std::map<vpPoint, size_t, CompareObjectPointDegenerate> filterObjectPointMap;
329 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end();
330 ++it_pt, index_pt++) {
331 if (filterObjectPointMap.find(*it_pt) == filterObjectPointMap.end()) {
332 filterObjectPointMap[*it_pt] = index_pt;
336 std::map<vpPoint, size_t, CompareImagePointDegenerate> filterImagePointMap;
337 for (std::map<vpPoint, size_t, CompareObjectPointDegenerate>::const_iterator it = filterObjectPointMap.begin();
338 it != filterObjectPointMap.end(); ++it) {
339 if (filterImagePointMap.find(it->first) == filterImagePointMap.end()) {
340 filterImagePointMap[it->first] = it->second;
342 listOfUniquePoints.push_back(it->first);
343 mapOfUniquePointIndex[listOfUniquePoints.size() - 1] = it->second;
348 listOfUniquePoints = listOfPoints;
351 for (std::vector<vpPoint>::const_iterator it_pt = listOfPoints.begin(); it_pt != listOfPoints.end();
352 ++it_pt, index_pt++) {
353 mapOfUniquePointIndex[index_pt] = index_pt;
357 if (listOfUniquePoints.size() < 4) {
361 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
362 unsigned int nbThreads = 1;
363 bool executeParallelVersion = useParallelRansac;
365 bool executeParallelVersion =
false;
368 if (executeParallelVersion) {
369 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
370 if (nbParallelRansacThreads <= 0) {
372 nbThreads = std::thread::hardware_concurrency();
373 if (nbThreads <= 1) {
375 executeParallelVersion =
false;
378 nbThreads = nbParallelRansacThreads;
383 bool foundSolution =
false;
385 if (executeParallelVersion) {
386 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
387 std::vector<std::thread> threadpool;
388 std::vector<RansacFunctor> ransacWorkers;
390 int splitTrials = ransacMaxTrials / nbThreads;
391 for (
size_t i = 0; i < (size_t)nbThreads; i++) {
392 unsigned int initial_seed = (
unsigned int)i;
393 if (i < (
size_t)nbThreads - 1) {
394 ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, splitTrials, ransacThreshold, initial_seed,
395 checkDegeneratePoints, listOfUniquePoints, func);
397 int maxTrialsRemainder = ransacMaxTrials - splitTrials * (nbThreads - 1);
398 ransacWorkers.emplace_back(cMo, ransacNbInlierConsensus, maxTrialsRemainder, ransacThreshold, initial_seed,
399 checkDegeneratePoints, listOfUniquePoints, func);
403 for (
auto &worker : ransacWorkers) {
404 threadpool.emplace_back(&RansacFunctor::operator(), &worker);
407 for (
auto &th : threadpool) {
411 bool successRansac =
false;
412 size_t best_consensus_size = 0;
413 for (
auto &worker : ransacWorkers) {
414 if (worker.getResult()) {
415 successRansac =
true;
417 if (worker.getBestConsensus().size() > best_consensus_size) {
418 nbInliers = worker.getNbInliers();
419 best_consensus = worker.getBestConsensus();
420 best_consensus_size = worker.getBestConsensus().size();
425 foundSolution = successRansac;
429 RansacFunctor sequentialRansac(cMo, ransacNbInlierConsensus, ransacMaxTrials, ransacThreshold, 0,
430 checkDegeneratePoints, listOfUniquePoints, func);
432 foundSolution = sequentialRansac.getResult();
435 nbInliers = sequentialRansac.getNbInliers();
436 best_consensus = sequentialRansac.getBestConsensus();
441 unsigned int nbMinRandom = 4;
465 if (nbInliers >= nbMinRandom)
470 for (
size_t i = 0; i < best_consensus.size(); i++) {
471 vpPoint pt = listOfUniquePoints[best_consensus[i]];
474 ransacInliers.push_back(pt);
478 for (std::vector<unsigned int>::const_iterator it_index = best_consensus.begin();
479 it_index != best_consensus.end(); ++it_index) {
480 ransacInlierIndex.push_back((
unsigned int)mapOfUniquePointIndex[*it_index]);
489 if (func != NULL && !func(cMo)) {
493 if (computeCovariance) {
494 covarianceMatrix = pose.covarianceMatrix;
501 return foundSolution;
525 probability = (std::max)(probability, 0.0);
526 probability = (std::min)(probability, 1.0);
527 epsilon = (std::max)(epsilon, 0.0);
528 epsilon = (std::min)(epsilon, 1.0);
535 if (maxIterations <= 0) {
536 maxIterations = std::numeric_limits<int>::max();
539 double logarg, logval, N;
540 logarg = -std::pow(1.0 - epsilon, sampleSize);
541 #ifdef VISP_HAVE_FUNC_LOG1P
542 logval = log1p(logarg);
544 logval = log(1.0 + logarg);
546 if (
vpMath::nul(logval, std::numeric_limits<double>::epsilon())) {
547 std::cerr <<
"vpMath::nul(log(1.0 - std::pow(1.0 - epsilon, "
548 "sampleSize)), std::numeric_limits<double>::epsilon())"
553 N = log((std::max)(1.0 - probability, std::numeric_limits<double>::epsilon())) / logval;
554 if (logval < 0.0 && N < maxIterations) {
558 return maxIterations;
592 const unsigned int &numberOfInlierToReachAConsensus,
const double &threshold,
594 const int &maxNbTrials,
bool useParallelRansac,
unsigned int nthreads,
599 for (
unsigned int i = 0; i < p2D.size(); i++) {
600 for (
unsigned int j = 0; j < p3D.size(); j++) {
601 vpPoint pt(p3D[j].getWorldCoordinates());
602 pt.
set_x(p2D[i].get_x());
603 pt.
set_y(p2D[i].get_y());
608 if (pose.
listP.size() < 4) {
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)
unsigned int npt
Number of point used in pose computation.
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)
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=NULL)
@ CHECK_DEGENERATE_POINTS
@ PREFILTER_DEGENERATE_POINTS
unsigned int getRansacNbInliers() const
void setUseParallelRansac(bool use)
std::vector< vpPoint > getRansacInliers() const
bool poseRansac(vpHomogeneousMatrix &cMo, bool(*func)(const vpHomogeneousMatrix &)=NULL)
void setNbParallelRansacThreads(int nb)
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 &)=NULL)
void setRansacThreshold(const double &t)