3

我无法从视差中获取正常的深度图。 这里是我的代码:获取深度图

#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; 
} 

我的图片:

enter image description here enter image description here

视差图:

enter image description here

我得到水木清华这样的点云: enter image description here

Q等于: [1,0,0,-3.2883545303344727e + 02,0,1,0, -2.3697290992736816e + 02,0.1,0.1,0.1, 5.4497170185417110e + 02,0.0,0.,-1.4446083962336606e-02,0]

我尝试了很多其他的东西。我尝试了不同的图像,但没有人能够获得正常的深度图。

我在做什么错?我应该使用reprojectImageTo3D还是使用其他方法来代替它?什么是深度图的最佳方式? (我试过了point_cloud库) 或者你能否给我提供数据集和校准信息的工作示例,我可以运行它并获取深度图。或者如何从Middlebury立体声数据库(http://vision.middlebury.edu/stereo/data/)获得depth_map,我认为没有足够的校准信息。

编辑: 现在,我得到水木清华这样的: enter image description here

这当然是好,但仍不正常。

Edited2: 我想你说的话:

Mat disp; 
disp = imread("disparity-image.pgm", CV_LOAD_IMAGE_GRAYSCALE); 

Mat disp64; 
disp.convertTo(disp64,CV_64F, 1.0/16.0); 
imshow("disp", disp); 

我得到这个结果与线CV :: minMaxIdx(...): enter image description here

这时候我评论这行: enter image description here

ps:也请你能告诉我怎么才能计算深度只知道基准线和焦距以像素为单位。

+0

这一切都取决于您的校准。如果你有超过0.5的重投影错误,你会得到一个不好的Q矩阵 – berak

+0

@berak:我知道它,并且因为我无法获得良好的校准,所以我尝试使用来自Internet(https:// code)的数据集。 google.com/p/tjpstereovision/source/browse/),我认为这是正常的Q矩阵。如何从middleburry数据集获取深度图? –

回答

2

我已经做了OpenCV的reprojectImageTo3D()和我自己的(见下文)之间的简单比较,并且还对正确的差异和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; 
     } 
    } 
} 

几乎相同的结果都产生了两种方法,他们都似乎对我是正确的。你可以试试你的视差图和Q矩阵吗?您可以在我的GitHub上使用我的测试环境。

注1:也照顾到不扩大两倍的差距(注释掉该行disparity.convertTo(disparity, CV_32F, 1.0/16.0);如果您disparity也缩放。)

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

+0

我编辑了我的queistion,请看 –

+0

因此'XYZ'是一个与视差大小相同的3通道浮点图像。 “XYZ”的每个元素都包含从视差图计算出的点(x,y)的三维坐标。在你的类型和我的类型之间存在误用,我修改了代码以在任何地方使用“double”。 – Kornel

+0

谢谢,我编辑提问。我使用Opencv 2.4.9。版本 –