Skip to content

Commit e703c30

Browse files
committed
Merge pull request opencv#10184 from catree:solvePnP_iterative_guess_3_pts
2 parents a79d0e1 + 2e56a47 commit e703c30

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

modules/calib3d/include/opencv2/calib3d.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ Estimation" (@cite penate2013exhaustive). In this case the function also estimat
563563
assuming that both have the same value. Then the cameraMatrix is updated with the estimated
564564
focal length.
565565
- **SOLVEPNP_AP3P** Method is based on the paper of Tong Ke and Stergios I. Roumeliotis.
566-
"An Efficient Algebraic Solution to the Perspective-Three-Point Problem". In this case the
566+
"An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (@cite Ke17). In this case the
567567
function requires exactly four object and image points.
568568
569569
The function estimates the object pose given a set of object points, their corresponding image
@@ -585,9 +585,12 @@ projections, as well as the camera matrix and the distortion coefficients.
585585
- The methods **SOLVEPNP_DLS** and **SOLVEPNP_UPNP** cannot be used as the current implementations are
586586
unstable and sometimes give completely wrong results. If you pass one of these two
587587
flags, **SOLVEPNP_EPNP** method will be used instead.
588-
- The minimum number of points is 4. In the case of **SOLVEPNP_P3P** and **SOLVEPNP_AP3P**
588+
- The minimum number of points is 4 in the general case. In the case of **SOLVEPNP_P3P** and **SOLVEPNP_AP3P**
589589
methods, it is required to use exactly 4 points (the first 3 points are used to estimate all the solutions
590590
of the P3P problem, the last one is used to retain the best solution that minimizes the reprojection error).
591+
- With **SOLVEPNP_ITERATIVE** method and `useExtrinsicGuess=true`, the minimum number of points is 3 (3 points
592+
are sufficient to compute a pose but there are up to 4 solutions). The initial solution should be close to the
593+
global solution to converge.
591594
*/
592595
CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints,
593596
InputArray cameraMatrix, InputArray distCoeffs,
@@ -658,9 +661,9 @@ the model coordinate system to the camera coordinate system. A P3P problem has u
658661
@param tvecs Output translation vectors.
659662
@param flags Method for solving a P3P problem:
660663
- **SOLVEPNP_P3P** Method is based on the paper of X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang
661-
"Complete Solution Classification for the Perspective-Three-Point Problem".
664+
"Complete Solution Classification for the Perspective-Three-Point Problem" (@cite gao2003complete).
662665
- **SOLVEPNP_AP3P** Method is based on the paper of Tong Ke and Stergios I. Roumeliotis.
663-
"An Efficient Algebraic Solution to the Perspective-Three-Point Problem".
666+
"An Efficient Algebraic Solution to the Perspective-Three-Point Problem" (@cite Ke17).
664667
665668
The function estimates the object pose given 3 object points, their corresponding image
666669
projections, as well as the camera matrix and the distortion coefficients.

modules/calib3d/src/solvepnp.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ bool solvePnP( InputArray _opoints, InputArray _ipoints,
6161

6262
Mat opoints = _opoints.getMat(), ipoints = _ipoints.getMat();
6363
int npoints = std::max(opoints.checkVector(3, CV_32F), opoints.checkVector(3, CV_64F));
64-
CV_Assert( npoints >= 4 && npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F)) );
64+
CV_Assert( ( (npoints >= 4) || (npoints == 3 && flags == SOLVEPNP_ITERATIVE && useExtrinsicGuess) )
65+
&& npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F)) );
6566

6667
Mat rvec, tvec;
6768
if( flags != SOLVEPNP_ITERATIVE )

modules/calib3d/test/test_solvepnp_ransac.cpp

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -302,18 +302,15 @@ class CV_solveP3P_Test : public CV_solvePnPRansac_Test
302302
if (num_of_solutions != (int) rvecs.size() || num_of_solutions != (int) tvecs.size() || num_of_solutions == 0)
303303
return false;
304304

305-
double min_rvecDiff = DBL_MAX, min_tvecDiff = DBL_MAX;
306-
for (unsigned int i = 0; i < rvecs.size(); ++i) {
305+
bool isTestSuccess = false;
306+
double error = DBL_MAX;
307+
for (unsigned int i = 0; i < rvecs.size() && !isTestSuccess; ++i) {
307308
double rvecDiff = norm(rvecs[i]-trueRvec);
308-
min_rvecDiff = std::min(rvecDiff, min_rvecDiff);
309-
}
310-
for (unsigned int i = 0; i < tvecs.size(); ++i) {
311309
double tvecDiff = norm(tvecs[i]-trueTvec);
312-
min_tvecDiff = std::min(tvecDiff, min_tvecDiff);
310+
isTestSuccess = rvecDiff < epsilon[method] && tvecDiff < epsilon[method];
311+
error = std::min(error, std::max(rvecDiff, tvecDiff));
313312
}
314-
bool isTestSuccess = min_rvecDiff < epsilon[method] && min_tvecDiff < epsilon[method];
315313

316-
double error = std::max(min_rvecDiff, min_tvecDiff);
317314
if (error > maxError)
318315
maxError = error;
319316

@@ -324,7 +321,7 @@ class CV_solveP3P_Test : public CV_solvePnPRansac_Test
324321
{
325322
ts->set_failed_test_info(cvtest::TS::OK);
326323

327-
vector<Point3f> points, points_dls;
324+
vector<Point3f> points;
328325
points.resize(pointsCount);
329326
generate3DPointCloud(points);
330327

@@ -529,3 +526,68 @@ TEST(Calib3d_SolvePnP, translation)
529526
EXPECT_TRUE(checkRange(rvec));
530527
EXPECT_TRUE(checkRange(tvec));
531528
}
529+
530+
TEST(Calib3d_SolvePnP, iterativeInitialGuess3pts)
531+
{
532+
{
533+
Matx33d intrinsics(605.4, 0.0, 317.35,
534+
0.0, 601.2, 242.63,
535+
0.0, 0.0, 1.0);
536+
537+
double L = 0.1;
538+
vector<Point3d> p3d;
539+
p3d.push_back(Point3d(-L, -L, 0.0));
540+
p3d.push_back(Point3d(L, -L, 0.0));
541+
p3d.push_back(Point3d(L, L, 0.0));
542+
543+
Mat rvec_ground_truth = (Mat_<double>(3,1) << 0.3, -0.2, 0.75);
544+
Mat tvec_ground_truth = (Mat_<double>(3,1) << 0.15, -0.2, 1.5);
545+
546+
vector<Point2d> p2d;
547+
projectPoints(p3d, rvec_ground_truth, tvec_ground_truth, intrinsics, noArray(), p2d);
548+
549+
Mat rvec_est = (Mat_<double>(3,1) << 0.2, -0.1, 0.6);
550+
Mat tvec_est = (Mat_<double>(3,1) << 0.05, -0.05, 1.0);
551+
552+
solvePnP(p3d, p2d, intrinsics, noArray(), rvec_est, tvec_est, true, SOLVEPNP_ITERATIVE);
553+
554+
std::cout << "rvec_ground_truth: " << rvec_ground_truth.t() << std::endl;
555+
std::cout << "rvec_est: " << rvec_est.t() << std::endl;
556+
std::cout << "tvec_ground_truth: " << tvec_ground_truth.t() << std::endl;
557+
std::cout << "tvec_est: " << tvec_est.t() << std::endl;
558+
559+
EXPECT_LE(norm(rvec_ground_truth, rvec_est, NORM_INF), 1e-6);
560+
EXPECT_LE(norm(tvec_ground_truth, tvec_est, NORM_INF), 1e-6);
561+
}
562+
563+
{
564+
Matx33f intrinsics(605.4f, 0.0f, 317.35f,
565+
0.0f, 601.2f, 242.63f,
566+
0.0f, 0.0f, 1.0f);
567+
568+
float L = 0.1f;
569+
vector<Point3f> p3d;
570+
p3d.push_back(Point3f(-L, -L, 0.0f));
571+
p3d.push_back(Point3f(L, -L, 0.0f));
572+
p3d.push_back(Point3f(L, L, 0.0f));
573+
574+
Mat rvec_ground_truth = (Mat_<float>(3,1) << -0.75f, 0.4f, 0.34f);
575+
Mat tvec_ground_truth = (Mat_<float>(3,1) << -0.15f, 0.35f, 1.58f);
576+
577+
vector<Point2f> p2d;
578+
projectPoints(p3d, rvec_ground_truth, tvec_ground_truth, intrinsics, noArray(), p2d);
579+
580+
Mat rvec_est = (Mat_<float>(3,1) << -0.5f, 0.2f, 0.2f);
581+
Mat tvec_est = (Mat_<float>(3,1) << 0.0f, 0.2f, 1.0f);
582+
583+
solvePnP(p3d, p2d, intrinsics, noArray(), rvec_est, tvec_est, true, SOLVEPNP_ITERATIVE);
584+
585+
std::cout << "rvec_ground_truth: " << rvec_ground_truth.t() << std::endl;
586+
std::cout << "rvec_est: " << rvec_est.t() << std::endl;
587+
std::cout << "tvec_ground_truth: " << tvec_ground_truth.t() << std::endl;
588+
std::cout << "tvec_est: " << tvec_est.t() << std::endl;
589+
590+
EXPECT_LE(norm(rvec_ground_truth, rvec_est, NORM_INF), 1e-6);
591+
EXPECT_LE(norm(tvec_ground_truth, tvec_est, NORM_INF), 1e-6);
592+
}
593+
}

0 commit comments

Comments
 (0)