Opencv,计算距深度垫的像素点距离

时间:2019-12-16 11:34:35

标签: opencv computer-vision

我有一个用校准的立体摄像机对和opencv创建的视差图像。看起来不错,我的校准数据也不错。

我需要计算一个像素的真实距离。

从关于stackoverflow的其他问题来看,我认为该方法是:

depth = baseline * focal / disparity

使用功能:

setMouseCallback("disparity", onMouse, &disp); 

static void onMouse(int event, int x, int y, int flags, void* param)
{
    cv::Mat &xyz = *((cv::Mat*)param); //cast and deref the param
    if (event == cv::EVENT_LBUTTONDOWN)
    {
        unsigned int val = xyz.at<uchar>(y, x);

        double depth = (camera_matrixL.at<float>(0, 0)*T.at<float>(0, 0)) / val;

        cout << "x= " << x << " y= " << y << " val= " << val << " distance: " << depth<< endl;
    }
}

我单击一个测得距立体相机3米的点。 我得到的是:

val = 31距离:0.590693

深度垫的值在0到255之间,深度垫的类型为0CV_8UC1。 立体声基准为0.0643654(以米为单位)。 焦距为284.493

我也尝试过: (来自OpenCV - compute real distance from disparity map

float fMaxDistance = static_cast<float>((1. / T.at<float>(0, 0) * camera_matrixL.at<float>(0, 0)));
//outputDisparityValue is single 16-bit value from disparityMap
float fDisparity = val / (float)cv::StereoMatcher::DISP_SCALE;
float fDistance = fMaxDistance / fDisparity;

这给了我val= 31 distance: 2281.27的距离(更接近真相,如果我们以毫米为单位) 但是仍然不正确。

以下哪种方法是正确的?而且我要去哪里错了?

左,右,深度图。 (编辑:此深度图来自另一对图像) enter image description here

编辑:基于一个答案,我正在尝试:

`std :: vector pointcloud;

float fx = 284.492615;
float fy = 285.683197;
float cx = 424;// 425.807709;
float cy = 400;// 395.494293;

cv::Mat Q = cv::Mat(4,4, CV_32F);
Q.at<float>(0, 0) = 1.0;
Q.at<float>(0, 1) = 0.0;
Q.at<float>(0, 2) = 0.0;
Q.at<float>(0, 3) = -cx; //cx
Q.at<float>(1, 0) = 0.0;
Q.at<float>(1, 1) = 1.0;
Q.at<float>(1, 2) = 0.0;
Q.at<float>(1, 3) = -cy;  //cy
Q.at<float>(2, 0) = 0.0;
Q.at<float>(2, 1) = 0.0;
Q.at<float>(2, 2) = 0.0;
Q.at<float>(2, 3) = -fx;  //Focal
Q.at<float>(3, 0) = 0.0;
Q.at<float>(3, 1) = 0.0;
Q.at<float>(3, 2) = -1.0 / 6;    //1.0/BaseLine
Q.at<float>(3, 3) = 0.0;    //cx - cx'

//
cv::Mat XYZcv(depth_image.size(), CV_32FC3);
reprojectImageTo3D(depth_image, XYZcv, Q, false, CV_32F);

for (int y = 0; y < XYZcv.rows; y++)
{
    for (int x = 0; x < XYZcv.cols; x++)
    {
        cv::Point3f pointOcv = XYZcv.at<cv::Point3f>(y, x);

        Eigen::Vector4d pointEigen(0, 0, 0, left.at<uchar>(y, x) / 255.0);
        pointEigen[0] = pointOcv.x;
        pointEigen[1] = pointOcv.y;
        pointEigen[2] = pointOcv.z;

        pointcloud.push_back(pointEigen);

    }
}`

那给了我一片乌云。

2 个答案:

答案 0 :(得分:1)

我建议使用OpenCV的reprojectImageTo3D来重建视差距离。请注意,使用此功能时,确实必须将StereoSGBM的输出除以16。您应该已经具有所有参数fcxcyTx。注意将f和Tx设置为相同的单位。 cx,cy以像素为单位。 由于问题在于您需要Q矩阵,因此我认为this linkthis one应该可以帮助您构建它。如果您不想使用reprojectImageTo3D,则强烈建议您使用第一个链接!

我希望这会有所帮助!

答案 1 :(得分:0)

要从相机中查找对象的基于点的深度,请使用下面的相机。

深度=(基线x焦距)/视差

我希望您根据自己的问题正确使用它。

尝试使用下面的神经计算器计算理论误差。

https://nerian.com/support/resources/calculator/

此外,在代码中使用亚像素插值。

确保要识别的深度对象具有良好的质感。

主要两个项目的深度错误:

  1. 未纹理的对象(透视对象)
  2. 校准结果不好。

您的校准,相机分辨率和镜头类型(焦距)的RMS值是多少 长度)。为程序提供更好的数据。

相关问题