3

I'm using OpenCV 3.1 on Windows.

A snippet of code:

RNG rng; // random number generator

cv::Mat rVec = (cv::Mat_<double>(3, 1) << 0.08257, -0.6168, 1.4675);
cv::Mat tVec = (cv::Mat_<double>(3, 1) << -0.3806, -0.1605, 0.6087);

for (int i = 0; i < 10000; i++)
{
    rVec.ptr<double>(0)[0] += rng.rand_linear(0.0, 0.5); // mean 0, marin +-0.5
    rVec.ptr<double>(1)[0] += rng.rand_linear(0.0, 0.5);
    rVec.ptr<double>(2)[0] += rng.rand_linear(0.0, 0.5);
    tVec.ptr<double>(0)[0] += rng.rand_linear(0.0, 0.5);
    tVec.ptr<double>(1)[0] += rng.rand_linear(0.0, 0.5);
    tVec.ptr<double>(2)[0] += rng.rand_linear(0.0, 0.5);

    std::cout << rVec.t() << " --> ";
    bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 100, 8.f, 0.99, cv::noArray(), cv::SOLVEPNP_ITERATIVE);
    std::cout << rVec.t() << std::endl;
}

Output is something like:

[-0.2853612945502569, -0.9418475404979531, 1.68440248184304] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[0.1479919034434538, -0.2763278773652259, 1.150822641518221] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[0.0706268803594689, -0.9919233518319074, 1.32315553697224] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[0.3478958481835257, -0.3697621750777457, 1.716206426456824] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.3340069694997688, -0.3675019960516933, 1.51973527339685] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[0.5445069792592954, -0.9075993847234044, 1.259690332649529] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]

So, regardless of the starting assumption, I get precisely the same final result.

Moving on, I reduce the number of iterations from a 100

bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 100, 8.f, 0.99, cv::noArray(), cv::SOLVEPNP_ITERATIVE);

to only 1 iteration

bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 1, 8.f, 0.99, cv::noArray(), cv::SOLVEPNP_ITERATIVE);

Same result:

[0.4316089014435242, -0.3745184350425247, 1.000847428296015] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.06206055466029242, -0.6728777329569552, 1.324249691752971] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.2321970797231366, -0.2713987283075098, 1.36880229898195] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.3178144781006445, -0.5075788347182665, 1.912844335384921] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]

Further on, changing the confidence argument from 0.99

bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 1, 8.f, 0.99, cv::noArray(), cv::SOLVEPNP_ITERATIVE);

down to 0.01

bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 1, 8.f, 0.01, cv::noArray(), cv::SOLVEPNP_ITERATIVE);

Same result:

[-0.1541070262057652, -0.9795359918514136, 0.9881938066838982] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.09741225946638182, -0.2123314354700837, 1.35100669316414] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[0.4136190534016173, -0.5970452204944435, 1.596524650886908] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]
[-0.1438873709732612, -0.6913048753647003, 1.76558963228415] --> [0.0825705957511495, -0.6167564127260689, 1.467542801941067]

Same thing with inlier threshold argument. It seems simply as though these arguments don't make any difference. The result actually looks pretty good, I just want to understand it a little better.

So, my conclusion is that solvePnPRansac() does the same thing regardless of the arguments. What am I doing wrong?

ancajic
  • 4,504
  • 1
  • 41
  • 62

1 Answers1

3

Unfortunately, the current (OpenCV 3.2) solvePnPRansac() method does not conform to the documentation:

  • it is SOLVEPNP_EPNP method that will be used when the number of point is >= 5 for the MSSs (minimal sample sets) step (see here)
  • the final camera pose estimation does not take into account useExtrinsicGuess (see here)

I will try to submit an issue and maybe a pull request (when I will have some time) if the expected behavior according to the doc improves the precision, otherwise the documentation has to be changed.


Not sure to understand your code:

  • you generate a random camera pose rvec and tvec
  • but it seems that you never update your 2D image points (need to use projectPoints())?

Your call is:

bool success = cv::solvePnPRansac(patternPoints3d, imgPoints, camIntrinsics.camMat, camIntrinsics.distCoeffs, rVec, tVec, true, 100, 8.f, 0.99, cv::noArray(), cv::SOLVEPNP_ITERATIVE);.

When you look at the doc, you use the flag SOLVEPNP_ITERATIVE which is a method to estimate the camera pose that uses an iterative optimization scheme and thus needs an initial estimate of the solution.

When providing useExtrinsicGuess = true, it will use directly rvec and tvec in arguments, otherwise it will call internally another method to get a first estimate of rvec and tvec.

Catree
  • 2,124
  • 1
  • 14
  • 19
  • Actually if you look more carefully, I set `rvec` and `tvec` to values that the algorithm converges anyhow for given points. Even if I had set `rvec` and `tvec` both to zeros, algorithm would converge to the same values it always does for these given points. Why do I need to update image points? Image points are the points I observe on the image. What I want to see is that for the same data I should get slightly different results based on the arguments I use. But this is not happening. – ancajic May 23 '17 at 10:41
  • I use `useExtrinsicGuess = true` so that I can explicitly set different starting positions for the iterative algorithm. To make sure it ends up with the same solution regardless of where it started from. – ancajic May 23 '17 at 10:44
  • 1
    I also missed the point of the question in my first answer. Sorry. – Catree May 23 '17 at 13:42