c++ - OpenCV 求解 PnPRansac

标签 c++ opencv opencv-solvepnp

我在 Windows 上使用 OpenCV 3.1。

一段代码:

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;
}

输出是这样的:

[-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]

因此,不管开始假设如何,我得到的最终结果完全相同。

继续,我将迭代次数从 100 次减少

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

1次迭代

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

同样的结果:

[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]

进一步,将置信度参数从 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);

降至 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);

同样的结果:

[-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]

与内点阈值参数相同。这些论点似乎没有任何区别。结果实际上看起来还不错,我只是想更好地理解它。

因此,我的结论是,无论参数如何,solvePnPRansac() 都会做同样的事情。我做错了什么?

最佳答案

不幸的是,当前 (OpenCV 3.2) solvePnPRansac() 方法不符合文档:

  • 当 MSS(最小样本集)步骤的点数为 >= 5 时,将使用 SOLVEPNP_EPNP 方法(参见 here )
  • 最终的相机姿势估计没有考虑 useExtrinsicGuess(参见 here)

如果根据文档的预期行为提高了精度,我将尝试提交一个问题,也许还有一个拉取请求(当我有时间的时候),否则必须更改文档。


不确定是否理解您的代码:

  • 你生成一个随机相机姿势 rvectvec
  • 但您似乎从未更新过 2D 图像点(需要使用 projectPoints())?

您的电话是:

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

当您查看 doc ,您使用标志 SOLVEPNP_ITERATIVE,这是一种使用迭代优化方案估计相机姿态的方法,因此需要对解决方案进行初始估计。

当提供useExtrinsicGuess = true时,参数中会直接使用rvectvec,否则会在内部调用另一种方法以获得 rvectvec 的初步估计。

关于c++ - OpenCV 求解 PnPRansac,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44131349/

相关文章:

c++ - 没有匹配的函数来调用 ‘normalize(cv::Point3f&)’ 错误

c++ - 如何让 std::list <std::string>::iterator 输出错误值?

c++ - C++中的模板化全局结构

c# - 转义字符 - 有什么用

使用 CMake 和 MinGW 的 OpenCV 2.4.2 库文件 - 目标 IDE 代码块

javascript - 在哪里可以找到带有solvePnP的opencv.js或者如何构建它?

c++ - MATLAB 在执行半色调 mex 包装函数时崩溃?

android - opencv 2.4.4 for android 不工作

opencv - 为什么直接线性变换 (DLT) 不能给出最佳的相机外部参数?

opencv - 理解 solvePnP 算法