【问题标题】:OpenCV extrinsic camera from feature points来自特征点的 OpenCV 外部相机
【发布时间】:2011-12-29 18:25:20
【问题描述】:

当我从每个相机的视图中获取对象的图片时,如何使用 OpenCV 检索每个相机的旋转矩阵、平移向量和一些缩放因子?对于每张图片,我都有几个特征点的图像坐标。并非所有特征点在所有图片中都可见。 我想将计算得到的对象特征点的 3D 坐标映射到稍微不同的对象,以将第二个对象的形状与第一个对象对齐。

我听说可以使用cv::calibrateCamera(...),但我无法完全通过它...

有人遇到过这种问题吗?

【问题讨论】:

  • 上面不清楚你是否知道你在不同图像中观察到的点的 3d 世界坐标。如果是这种情况,这是一个 Perspective-n-point-problem,您可以使用此处提供的 EPnP 算法校准每个相机的参数:cvlab.epfl.ch/software/EPnP/index.php。否则,请参阅下面的答案。
  • 被摄物体的3d坐标未知。
  • 如果对象上点的 3d 世界坐标是unknown,我认为 cv::calibrateCamera 不会起作用,因为它似乎假设对象点是已知
  • 您可能还想查看捆绑调整:en.wikipedia.org/wiki/Bundle_adjustment。这假设您对相机姿势有一个初始估计。然后问题是重建所有点和姿势。
  • 这似乎正是我所需要的!感谢您一直以来的关注和时间!

标签: opencv computer-vision camera-calibration perspectivecamera


【解决方案1】:

您是否希望校准这些静态相机以供将来用作立体相机对?在这种情况下,您需要使用 cv::stereoCalibrate() 函数。 OpenCV 包含一些示例代码,其中之一是 stereo_calib.cpp,可能值得研究。

【讨论】:

  • 感谢您的回答,但我对使用立体声对不感兴趣。我有一台相机,用于从不同侧面查看同一物体。然后在每张图片中标记的特征点应该可以帮助我计算要稍微变形的虚拟对象的对应点的新位置。然后,虚拟对象应具有与拍摄的真实对象完全相同的几何形状。 BTW cv::calibrateCamera(...) 在计算过程中使用cv::stereoCalibrate()
  • 好的,你的单相机校准了吗(即你知道内在参数——焦距、像素倾斜、主点、畸变系数)吗?
  • 我可以估计它们,但实际值未知。
【解决方案2】:

在 OpenCV 中,我遇到了与您相同的问题。我有一个立体图像对,我想计算相机的外部参数和所有观察点的世界坐标。此问题已在此处处理:

Berthold K. P. 霍恩。重新审视了相对方向。 Berthold K. P. 霍恩。麻省理工学院人工智能实验室,545科技...

http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.64.4700

但是,我找不到此问题的合适实现(也许您会找到一个)。由于时间限制,我没有时间理解本文中的所有数学并自己实现它,所以我想出了一个适合我的快速而简单的解决方案。我将解释我做了什么来解决它:

假设我们有两个摄像头,其中第一个摄像头有外部参数 RT = Matx::eye()。现在猜测第二个摄像机的旋转 R。对于在两幅图像中观察到的每一对图像点,我们计算它们在世界坐标中对应光线的方向,并将它们存储在二维数组 dirs 中(编辑:假设内部相机参数是已知的)。我们可以这样做,因为我们假设我们知道每个相机的方向。现在我们建立一个超定线性系统AC = 0,其中C是第二个相机的中心。我为你提供了计算 A 的函数:

Mat buildA(Matx<double, 3, 3> &R, Array<Vec3d, 2> dirs)
{
    CV_Assert(dirs.size(0) == 2);
    int pointCount = dirs.size(1);
    Mat A(pointCount, 3, DataType<double>::type);
    Vec3d *a = (Vec3d *)A.data;
    for (int i = 0; i < pointCount; i++)
    {
        a[i] = dirs(0, i).cross(toVec(R*dirs(1, i)));
        double length = norm(a[i]);
        if (length == 0.0)
        {
            CV_Assert(false);
        }
        else
        {
            a[i] *= (1.0/length);
        }
    }
    return A;
}

然后调用 cv::SVD::solveZ(A) 将为您提供该系统的范数 1 的最小二乘解。这样,您可以获得第二个相机的旋转和平移。然而,由于我只是猜测了第二台摄像机的旋转,我对它的旋转做了几个猜测(使用 3x1 向量 omega 进行参数化,我使用 cv::Rodrigues 计算旋转矩阵)然后我通过在具有数值雅可比的 Levenberg-Marquardt 优化器中重复求解系统 AC = 0。它对我有用,但有点脏,所以如果你有时间,我鼓励你实现论文中解释的内容。

编辑:

这是 Levenberg-Marquardt 优化器中用于评估残差向量的例程:

void Stereo::eval(Mat &X, Mat &residues, Mat &weights)
{

        Matx<double, 3, 3> R2Ref = getRot(X); // Map the 3x1 euler angle to a rotation matrix
        Mat A = buildA(R2Ref, _dirs); // Compute the A matrix that measures the distance between ray pairs
        Vec3d c;
        Mat cMat(c, false);
        SVD::solveZ(A, cMat); // Find the optimum camera centre of the second camera at distance 1 from the first camera
        residues = A*cMat; // Compute the  output vector whose length we are minimizing
    weights.setTo(1.0);
}

顺便说一句,我在互联网上搜索了一些其他代码,这些代码可能对计算相机之间的相对方向很有用。我还没有尝试过任何代码,但它似乎很有用:

http://www9.in.tum.de/praktika/ppbv.WS02/doc/html/reference/cpp/toc_tools_stereo.html

http://lear.inrialpes.fr/people/triggs/src/

http://www.maths.lth.se/vision/downloads/

【讨论】:

  • 非常感谢您的回答。我想我了解您编写和编码的内容,这将极大地帮助我为我的问题找到可能的解决方案。但是我相信cv::calibrateCamera(...) 的工作方式与您提出的非常相似。他们将算法描述如下:
  • 1.首先,它计算初始内在参数(该选项仅适用于平面校准模式)或从输入参数中读取它们。失真系数最初都设置为零(除非指定了一些 CV_CALIB_FIX_K?)。 2. 估计初始相机位姿,就好像内在参数已知一样。这是使用 FindExtrinsicCameraParams2 完成的
  • 3.之后,运行全局 Levenberg-Marquardt 优化算法以最小化重投影误差,即观察到的特征点 imagePoints 和投影(使用相机参数和姿势的当前估计)对象点 objectPoints 之间的总平方距离之和;见 ProjectPoints2 。
  • 这是cv::calibrateCamera的文档链接:opencv.willowgarage.com/documentation/cpp/…
  • 上述解决方案假设 3d 世界坐标未知。如果它们是已知的,cv::calibrateCamera 可能会正常工作。
猜你喜欢
  • 2013-01-04
  • 1970-01-01
  • 2013-03-01
  • 2016-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 2018-09-15
相关资源
最近更新 更多