【问题标题】:What's the difference between reprojectImageto3D(OpenCV) and disparity to 3D coordinates?reprojectImageto3D(OpenCV) 和视差到 3D 坐标有什么区别?
【发布时间】:2017-05-21 02:09:29
【问题描述】:

我正在尝试使用立体相机获取 3D 坐标。

第一种方法是直接用这个公式计算。

第二种方法是在opencv中使用reprojectImageTo3D。

但是我不知道这个方法的原理。

结果不是毫米,所以很难匹配大小。

请告诉我这两种方法的区别。

(这些代码中的第一个是匹配后将Point Feature转换为3D坐标。) (第二个代码是使用SGBM计算整个立体图像的视差,使用reprojectImageTo3D计算点特征的3d坐标。)

*第一种方法

cv::Mat depth(m_input.m_leftImg.size(), CV_32FC3, cv::Scalar::all(0));
int size = feOutput.m_leftKp.size();
for (int i = 0; i < size; i++)
{
    cv::Point pt = cv::Point((int)(feOutput.m_leftKp.at(i).pt.x + 0.5f), (int)(feOutput.m_leftKp.at(i).pt.y + 0.5f));

    depth.at<cv::Vec3f>(pt)[2] = fX * baseLine / (feOutput.m_leftKp.at(i).pt.x - feOutput.m_rightKp.at(i).pt.x);        // Z
    depth.at<cv::Vec3f>(pt)[0] = (feOutput.m_leftKp.at(i).pt.x - cX) * depth.at<cv::Vec3f>(pt)[2] / fX;                 // X
    depth.at<cv::Vec3f>(pt)[1] = (feOutput.m_leftKp.at(i).pt.y - cY) * depth.at<cv::Vec3f>(pt)[2] / fY;                 // Y
}
depth /= 1000.f; //milli-meter to meter

*第二种方法

cv::Mat disparity16S(m_input.m_leftImg.size(), CV_16S);
sgbm->compute(m_input.m_leftImg, m_input.m_rightImg, disparity16S);
cv::Mat xyz;
cv::Matx44d Q = cv::Matx44d(    
    1.0, 0.0, 0.0, -cX,
    0.0, 1.0, 0.0, -cY,
    0.0, 0.0, 0.0, fX,
    0.0, 0.0, -1.0 / baseLine, 0/*(CX - CX) / baseLine*/
);
cv::reprojectImageTo3D(disparity16S, xyz, Q, true);

cv::Mat pointXYZ(xyz.size(), xyz.type(), cv::Scalar::all(0));
for (int i = 0; i < size; i++)
{
    cv::Point pt = cv::Point((int)(feOutput.m_leftKp.at(i).pt.x + 0.5f), (int)(feOutput.m_leftKp.at(i).pt.y + 0.5f));
    pointXYZ.at<cv::Vec3f>(pt) = xyz.at<cv::Vec3f>(pt) / 1000.f;
}

添加+ 粉色是reprojectImageTo3D方法缩放到1/100的尺寸,黄色是第一种方法中1/1000(mm 2米)的尺寸。 如果这两种方法是一样的,为什么会有规模差异?

【问题讨论】:

    标签: c++ opencv 3d camera-calibration stereo-3d


    【解决方案1】:

    理论上没有什么区别,只是方法上的区别。 您可以使用 sgbm opencv 方法(不执行任何匹配但解决最小化问题)计算单个匹配点(您的第一种方法)或图像中每个像素的差异。

    一旦有了视差 D,您就可以从三角测量中检索深度 Z 的第一个公式。这应该是与您的参考图像平面(通常:左相机)的“距离”。

    z = f*b/d 
    

    一旦你有了 Z,就知道投影方程说明了主摄像头的情况(伪代码)

           f, 0 , cX, 0
     K =   0 , f, cY, 0 
           0 , 0,  1, 0
    [x y 1] = 1/Z * K * [X Y Z 1]
    

    你可以逆转。

    [X Y Z 1] = inv(K)* [Z*x Z*y Z] /*Z is known from disparity */
    

    找到您的 x,y 喜欢显示在第一张图片的第一列中。 这些在主(左)相机参考系统中,但如果您想在右相机中使用您发布的图像,请进行 2 个假设

    b is all along x
    
    the two camera planes are perfectly parallel
    

    通常对于其他相机,您假设 b 是已知向量。这两个参考系统之间可能发生旋转,因此还必须定义 R 矩阵)。我认为所有这些情况都是从不同的 Q 矩阵表示的(从立体摄像机校准获得,例如 stereoRectify)。

    cv::reprojectImageTo3D 只是“自动方法”。他需要相机参数和连续视差图。它可以处理单个选择点的差异。

    【讨论】:

    • 感谢您的回答。那么,[X Y Z 1] = inv (K) * [Z * x Z * y Z] 和第一个方程一样吗,低公式和reprojectImageTo3D没有区别吗?
    • 我添加了一些细节。为什么这两种方法的规模不同?
    • @user6445248 它们应该是等效的(根据我的 2 假设)。 This is documentation of stereoSGBM operator in openCV 2.4。 sgbm 运算符的值除以 16 了吗(你用的是 CV_16S)?
    • 这似乎是问题。我在互联网上看到我必须除以numberOfDisparity。为什么要分呢?
    • @user6445248 我也不是很清楚“为什么”(我想应该是跟数值计算有关),就试着按照opencv指令看看结果是否正确(并报告这里)。较低的视差值意味着较高的深度值,因此粉红色点应达到深度值的黄色范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 2011-03-07
    相关资源
    最近更新 更多