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。版本 –