有人容易把视差图跟深度图搞混,一切还是要从这个公式说起:Z=f*B/d
Z是深度,B是双目相机的光心间距(基线长度),f是相机焦距,d就是视差(左右相机对应特征像素坐标差值)。
而我们说的视差图就是灰度图的灰度值为d的时候,想转化为Z就变成了深度图,所以这是个并不复杂的问题。
代码里fx是内参的值,x方向的焦距,baseline是基线长。
这里要注意深度图的类型,不同图像类型的尺度范围是不一样的,那么如果直接用于距离测量得到的只是一个相对深度,而不是精确的距离。如果图像的类型是CV_8UC1,那么对应的标识符要变成uchar ,CV_8S对应的是char, CV_16U对应的标识符应该是ushort.也就是说标识符要和图像数据类型相对应。short d = img.ptr<uchar>(row)[col]; 下面三个图就是在不同数据类型下产生的效果,坑也挺多的,这里生成的深度图的数值还不是真实的距离,因为在进行数据类型变换的时候数值尺度变了,OpenCV里面reprojectImageTo3D(disp, xyz, Q, true)这个函数得到的才是真实的三坐标值它计算出来的结果CV_16S或者CV_32S类型的, sgbm立体匹配算法出来的结果是CV_16S 类型的,在转换的过程中要确保前后尺度一致,可以简单的思考一下,d是视差值,大小不可能超过图像的分辨率,如果视差图的像素值超过了说明在类型变换的时候尺度变了。

关于这些细节我懂的也不多,欢迎补充。

python通过深度图像求目标距离 图像深度图计算_深度图


python通过深度图像求目标距离 图像深度图计算_opencv_02


python通过深度图像求目标距离 图像深度图计算_python通过深度图像求目标距离_03


根据Mat.type()输出的值判断图像的类型

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

const double fx = 4152.073;
const double baseline = 176.252;


int main(int argc, char** argv)
{
        Mat img = imread("E:\\intern\\depth\\disp0.png",0);
    cout << img.type();

   // Mat img = imread("E:\\intern\\depth\\disp0.png");
    Mat depth(img.rows, img.cols, CV_16S);  //深度图
    cout<< depth.type()<<endl;//   查看图像类型,输出的数值去网站查表
    //视差图转深度图
    for (int row = 0; row < depth.rows; row++)
    {
        for (int col = 0; col < depth.cols; col++)
        {
            short d = img.ptr<uchar>(row)[col];


            if (d == 0)
                continue;

            depth.ptr<short>(row)[col] = fx * baseline / d;
        }
    }
    namedWindow("img", 0);
    namedWindow("depth", 0);
    imshow("img", img);
    imshow("depth", depth);
    waitKey(0);
}

python通过深度图像求目标距离 图像深度图计算_深度图_04


python通过深度图像求目标距离 图像深度图计算_#include_05


python通过深度图像求目标距离 图像深度图计算_数据类型_06

毕竟是灰度图看起来不舒服,可以参考我的另外一篇文章转为伪彩色深度图

python通过深度图像求目标距离 图像深度图计算_数据类型_07