Opencv 获取深度图

Opencv 获取深度图,opencv,stereo-3d,3d-reconstruction,stereoscopy,disparity-mapping,Opencv,Stereo 3d,3d Reconstruction,Stereoscopy,Disparity Mapping,我无法从视差中获得正常深度贴图。 这是我的密码: #include "opencv2/core/core.hpp" #include "opencv2/calib3d/calib3d.hpp" #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include "opencv2/contrib/contrib.hpp" #include <cstdio>

我无法从视差中获得正常深度贴图。 这是我的密码:

#include "opencv2/core/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/contrib/contrib.hpp"
#include <cstdio>
#include <iostream>
#include <fstream>

using namespace cv;
using namespace std;

ofstream out("points.txt");

int main()
{
    Mat img1, img2;
    img1 = imread("images/im7rect.bmp");
    img2 = imread("images/im8rect.bmp");

    //resize(img1, img1, Size(320, 280));
    //resize(img2, img2, Size(320, 280));

    Mat g1,g2, disp, disp8;
    cvtColor(img1, g1, CV_BGR2GRAY);
    cvtColor(img2, g2, CV_BGR2GRAY);

    int sadSize = 3;
    StereoSGBM sbm;
    sbm.SADWindowSize = sadSize;
    sbm.numberOfDisparities = 144;//144; 128
    sbm.preFilterCap = 10; //63
    sbm.minDisparity = 0; //-39; 0
    sbm.uniquenessRatio = 10;
    sbm.speckleWindowSize = 100;
    sbm.speckleRange = 32;
    sbm.disp12MaxDiff = 1;
    sbm.fullDP = true;
    sbm.P1 = sadSize*sadSize*4;
    sbm.P2 = sadSize*sadSize*32;
    sbm(g1, g2, disp);

    normalize(disp, disp8, 0, 255, CV_MINMAX, CV_8U);

    Mat dispSGBMscale; 
    disp.convertTo(dispSGBMscale,CV_32F, 1./16); 

    imshow("image", img1);

    imshow("disparity", disp8);

    Mat Q;
    FileStorage fs("Q.txt", FileStorage::READ);
    fs["Q"] >> Q;
    fs.release();

    Mat points, points1;
    //reprojectImageTo3D(disp, points, Q, true);
    reprojectImageTo3D(disp, points, Q, false, CV_32F);
    imshow("points", points);

    ofstream point_cloud_file;
    point_cloud_file.open ("point_cloud.xyz");
    for(int i = 0; i < points.rows; i++) {
        for(int j = 0; j < points.cols; j++) {
            Vec3f point = points.at<Vec3f>(i,j);
            if(point[2] < 10) {
                point_cloud_file << point[0] << " " << point[1] << " " << point[2]
                    << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << " " << static_cast<unsigned>(img1.at<uchar>(i,j)) << endl;
            }
        }
    }
    point_cloud_file.close(); 

    waitKey(0);

    return 0;
}
我使用cv::minMaxIdx(…)行得到这个结果:

当我评论这一行时:


另外,请你告诉我如何计算深度,只知道基线和焦距(像素)

我对OpenCV和我自己的做了一个简单的比较(见下文),并对正确的差异和
Q
矩阵进行了测试

// Reproject image to 3D
void customReproject(const cv::Mat& disparity, const cv::Mat& Q, cv::Mat& out3D)
{
    CV_Assert(disparity.type() == CV_32F && !disparity.empty());
    CV_Assert(Q.type() == CV_32F && Q.cols == 4 && Q.rows == 4);

    // 3-channel matrix for containing the reprojected 3D world coordinates
    out3D = cv::Mat::zeros(disparity.size(), CV_32FC3);

    // Getting the interesting parameters from Q, everything else is zero or one
    float Q03 = Q.at<float>(0, 3);
    float Q13 = Q.at<float>(1, 3);
    float Q23 = Q.at<float>(2, 3);
    float Q32 = Q.at<float>(3, 2);
    float Q33 = Q.at<float>(3, 3);

    // Transforming a single-channel disparity map to a 3-channel image representing a 3D surface
    for (int i = 0; i < disparity.rows; i++)
    {
        const float* disp_ptr = disparity.ptr<float>(i);
        cv::Vec3f* out3D_ptr = out3D.ptr<cv::Vec3f>(i);

        for (int j = 0; j < disparity.cols; j++)
        {
            const float pw = 1.0f / (disp_ptr[j] * Q32 + Q33);

            cv::Vec3f& point = out3D_ptr[j];
            point[0] = (static_cast<float>(j)+Q03) * pw;
            point[1] = (static_cast<float>(i)+Q13) * pw;
            point[2] = Q23 * pw;
        }
    }
}
//将图像重新投影到3D
void customReproject(常数cv::Mat&Distance、常数cv::Mat&Q、cv::Mat&out3D)
{
CV_Assert(disparation.type()==CV_32F&&!disparation.empty());
CV_Assert(Q.type()==CV_32F&&Q.cols==4&&Q.rows==4);
//包含重新投影的三维世界坐标的3通道矩阵
out3D=cv::Mat::zeros(disparsion.size(),cv_32FC3);
//从Q得到有趣的参数,其他的都是0或1
浮点数Q03=Q.at(0,3);
浮点数Q13=Q.at(1,3);
浮点数Q23=Q.at(2,3);
浮点数Q32=Q.at(3,2);
浮点数Q33=Q.at(3,3);
//将单通道视差贴图转换为表示3D曲面的3通道图像
对于(int i=0;i
这两种方法产生的结果几乎相同,在我看来它们都是正确的。请在您的视差图和
Q
matrix上试一试好吗?您可以在我的计算机上使用我的测试环境

注1:也要注意不要将视差缩放两倍(注释掉
disparsion.convertTo(disparence,CV_32F,1.0/16.0);
如果您的
视差也被缩放过。)


注2:它是用OpenCV 3.0构建的,您可能需要更改包含项。

这一切取决于您的校准。如果你的重投影错误超过0.5,你会得到一个坏的Qmatrix@berak:我知道,因为我无法获得良好的校准,所以我在互联网上的数据集()上尝试了它,我认为它是正常的Q矩阵。如何从middleburry数据集中获取深度图?因此,
XYZ
是一个与视差大小相同的3通道浮点图像。
XYZ
的每个元素都包含根据视差图计算的点(x,y)的三维坐标。你的类型和我的类型之间存在误用,我修改了代码,在任何地方都使用
double
。谢谢,我编辑了这个问题。我使用Opencv 2.4.9。版本如果您注释掉行
cv::minMaxIdx(…)
,会发生什么?很难说您有一个具有正确差异和
Q
矩阵的示例代码,您能在代码中加载并尝试它吗?我做了最后的测试,结果对我来说似乎是正确的,请查看我更新的答案
// Reproject image to 3D
void customReproject(const cv::Mat& disparity, const cv::Mat& Q, cv::Mat& out3D)
{
    CV_Assert(disparity.type() == CV_32F && !disparity.empty());
    CV_Assert(Q.type() == CV_32F && Q.cols == 4 && Q.rows == 4);

    // 3-channel matrix for containing the reprojected 3D world coordinates
    out3D = cv::Mat::zeros(disparity.size(), CV_32FC3);

    // Getting the interesting parameters from Q, everything else is zero or one
    float Q03 = Q.at<float>(0, 3);
    float Q13 = Q.at<float>(1, 3);
    float Q23 = Q.at<float>(2, 3);
    float Q32 = Q.at<float>(3, 2);
    float Q33 = Q.at<float>(3, 3);

    // Transforming a single-channel disparity map to a 3-channel image representing a 3D surface
    for (int i = 0; i < disparity.rows; i++)
    {
        const float* disp_ptr = disparity.ptr<float>(i);
        cv::Vec3f* out3D_ptr = out3D.ptr<cv::Vec3f>(i);

        for (int j = 0; j < disparity.cols; j++)
        {
            const float pw = 1.0f / (disp_ptr[j] * Q32 + Q33);

            cv::Vec3f& point = out3D_ptr[j];
            point[0] = (static_cast<float>(j)+Q03) * pw;
            point[1] = (static_cast<float>(i)+Q13) * pw;
            point[2] = Q23 * pw;
        }
    }
}