来自特征点的 OpenCV 外部相机

标签 opencv computer-vision camera-calibration perspectivecamera

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

我听说使用 cv::calibrateCamera(...) 是可能的,但我无法完全理解...

有人遇到过这类问题吗?

最佳答案

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

Berthold K. P. Horn。重新审视相对方向。 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/

关于来自特征点的 OpenCV 外部相机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8140924/

相关文章:

在 Windows 上使用 CUDA 9.1 构建 OpenCV 3.4 - traincascade 不使用 GPU

matlab - 在对打印文本进行行分割时将行分组

opencv - 裁剪图像如何影响相机校准的内在特性?

opencv - 在RealSense库中将红外图像映射为彩色图像

python - 如何检测给定图像中的所有矩形框

ios - 编辑 HSL 转换失败的 RGB 色彩空间图像

python - 模块对象没有属性 'VideoCapture'

c++ - (OpenCV/DNN) 面部识别不起作用 - 欧氏距离始终为 0

python - opencv python在存在间隙的表中添加网格线

matlab - 什么是最好的相机校准方法?