c++ - 平面三角形的 solvePNP

标签 c++ opencv pose-estimation opencv-solvepnp

我有一个非常简单的任务:获取平面三角形的欧拉角。图案看起来像 this

因此,算法:

1) 从网络摄像头获取图像 -- 完成

2) 转换为灰阶、滤镜等——完成

3) 获取所有连接组件的质量中心,并过滤它们——完成。看起来像 this .红色圆圈表示三角形顶点的质心。

代码很简单,但在这里:

QMap<int, QVector<double> > massCenters(const cv::Mat& image)
{
    cv::Mat output(IMAGE_WIDTH, IMAGE_HEIGHT, CV_32S);
    cv::connectedComponents(image, output, 8);

    QMap<int, QVector<double> > result;

    for (int y = 0; y < IMAGE_HEIGHT; ++y)
    {
        for (int x = 0; x < IMAGE_WIDTH; ++x)
        {
            int label = output.at<int>(y, x);

            if (label)
            {
                QVector<double> vec = result.value(label, QVector<double>());

                if (vec.isEmpty())
                {
                    vec.resize(3);
                    vec.fill(0);
                }

                vec[0] += x;
                vec[1] += y;
                vec[2] += 1;
                result[label] = vec;
            }
         }
    }

    return result;
}

4) 然后我调用 solvePNP 来获取旋转和平移 vector

 cv::solvePnP(m_origin, m_imagePoints, m_cameraMatrix, m_distMatrix, m_rvec, m_tvec);

 //this code is for drawing rvec & tvec on a screen
 std::vector<cv::Point3f> axis;
 vector<cv::Point2f> axis2D;

 axis.push_back(Point3f(0.0f, 0.0f, 0.0f));
 axis.push_back(Point3f(30.0f, 0.0f, 0.0f));
 axis.push_back(Point3f(0.0f, 30.0f, 0.0f));
 axis.push_back(Point3f(0.0f, 0.0f, 30.0f));

 cv::projectPoints(axis, m_rvec, m_tvec, m_cameraMatrix, m_distMatrix, axis2D);

 cv::line(m_orig, axis2D[0], axis2D[1], cv::Scalar(255, 0, 0), 2);
 cv::line(m_orig, axis2D[0], axis2D[2], cv::Scalar(0, 255, 0), 2);
 cv::line(m_orig, axis2D[0], axis2D[3], cv::Scalar(0, 0, 255), 2);

m_origin 声明为 std::vector<cv::Point3f> m_origin;并填充值(以毫米为单位)

m_origin.push_back(cv::Point3f( 0.0f,   51.0f, 0.0f));
m_origin.push_back(cv::Point3f(-56.0f, -26.0f, 0.0f));
m_origin.push_back(cv::Point3f( 56.0f, -26.0f, 0.0f));

m_imagePoints 声明为 std::vector<cv::Point2f> m_imagePoints;并包含质量中心的像素坐标(第二个屏幕上的红色圆圈)。

我得到了很奇怪的结果:来自 thisthat

我尝试过什么但对我没有帮助:

1) 在 m_cameraMatrix、m_distMatrix、m_rvec、m_tvec 中使用了 double 和 float 类型

2) m_origin 中重新排列的点

3) 玩 solvePnPRansac 及其输入参数

4) 使用 pnp 方法:迭代和 epnp

5) useExtrinsicGuess=true——它有帮助,但有时解决方案会“卡住”并给出完全错误的值(旋转 vector 中的千度)

我有几个问题:

1) 原点顺序和图像点重要吗?如前所述 here ,有时确实如此,但那是一年前的事了。

2) 除了使用 solvePnP,我的任务是否可以通过其他方式解决?

谢谢。非常感谢任何帮助!

最佳答案

solvePnPRansac 不适用于您的情况,因为您不必处理异常数据。

我的猜测是您观察到的问题来自您选择的模式:

  • 是3分
  • 然后添加三角形的质心

但在我看来,它或多或少类似于仅使用 3 个点,因为您添加的第 4 个点是三角形的重心,不应在姿势估计问题中提供任何额外信息。

关于 3 点姿态估计问题 (P3P),最多有四种可能的解决方案,可以使用第 4 个点来消除歧义。关于此的一些引用资料:

我的建议是改用 4 点正方形并测试您是否观察到同样的问题(P3P 标志应该没问题)。如果是,则代码或校准存在问题。

我认为这里有一篇论文或多或少与这个问题有关:Why is the Danger Cylinder Dangerous in the P3P Problem? .链接不可用时的图:

Danger cylinder

关于c++ - 平面三角形的 solvePNP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43005415/

相关文章:

c++ - WSL 中 QT 的动态链接不起作用但在 docker 容器中工作

C++11 在公共(public)函数中设置 lambda

c++ - 如何获取视频采集设备信息?

opengl - 使用 2 个摄像头进行头部姿势估计

c++ - 在 OpenGL 中改变焦点时 WIndows 闪烁

c++ - 以不同的方式获取命令行输入

OpenCV 关键点 : information about angle and octave

opencv - EmguCV仅剪切面部和颈部皮肤并保存新图像

c++ - solvePnpRansac GPU断言失败