OpenCV - 计算与视差图的实际距离

big*_*cle 5 c++ opencv

我在 OpenCV 3.1 中使用 StereoSGBM 算法计算了视差图。我已经校准了具有小 RMS 误差的立体相机。现在我想计算视差图中某些点的实际距离(以毫米为单位)。

这似乎是一个比较容易的问题。据我了解,我可以简单地使用公式

distance = (baseline * focal length) / disparity
Run Code Online (Sandbox Code Playgroud)

我可以在这里使用矩阵 Q(从stereoRectify 输出)。Q[2][3] = 焦距,1/Q[3][2] = 基线。

计算出的 Q 矩阵为:

Q: !!opencv-matrix
   rows: 4
   cols: 4
   dt: d
   data: [ 
    1., 0., 0., -1.5668458938598633e+02, 
    0., 1., 0., -1.1948609733581543e+02, 
    0., 0., 0., 2.3598119491957863e+02, 
    0., 0., 1.6254073321947445e-02, 0. ]
Run Code Online (Sandbox Code Playgroud)

问题是结果与现实不符。例如,对于瞄准房间天花板的相机,距离约为 2.5 米(视差正确计算为 12),实际距离计算为 1.3 m。对于非常近的物体(例如 30 厘米),它似乎是正确的,但远物体则非常不正确。在校准过程中,我以毫米为单位指定了棋盘格的确切尺寸。

我完全做到以下几点:

// compute rectification transforms from calibration data
stereoRectify(M1, D1, M2, D2, Size(FRAME_WIDTH, FRAME_HEIGHT), R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, 0.0, Size(FRAME_WIDTH, FRAME_HEIGHT), &roi1, &roi2);

// compute the undistortion and rectification transformation maps for each camera
initUndistortRectifyMap(M1, D1, R1, P1, Size(FRAME_WIDTH, FRAME_HEIGHT), CV_16SC2, map11, map12);
initUndistortRectifyMap(M2, D2, R2, P2, Size(FRAME_WIDTH, FRAME_HEIGHT), CV_16SC2, map21, map22);

...

// get images from camera (VideoCapture)
camLeft.read(_frameLeft);
camRight.read(_frameRight);

// remap images using the calibration data
remap(_frameLeft, frameLeft, map11, map12, INTER_LINEAR);
remap(_frameRight, frameRight, map21, map22, INTER_LINEAR);

// compute disparity from undistorted images
stereo->compute(frameLeft, frameRight, disparityMap);

...

// compute the real-world distance [mm]
float fMaxDistance = static_cast<float>((1. / Q.at<double>(3, 2)) * Q.at<double>(2, 3));

// outputDisparityValue is single 16-bit value from disparityMap
// DISP_SCALE = 16
float fDisparity = outputDisparityValue / (float)StereoMatcher::DISP_SCALE;
float fDistance = fMaxDistance / fDisparity;
Run Code Online (Sandbox Code Playgroud)

有什么我做错了吗?提前致谢。

mar*_*esk 1

我知道 OpenCV 2.4 中用于视差的立体算法(stereoBM、stereoSGBM)给出的视差值是实际值的 16 倍,如文档中所述。我没有使用C++,openCv3,并且我没有找到您的代码中指定的视差方法SGBM,但我认为这可能是同一件事。尝试将每个视差值除以 16(同样,这对于 OpenCV 2.4 来说肯定是正确的,我不知道 3.0 版本)