使用opencv StereoBM

时间:2016-03-09 23:03:06

标签: opencv camera-calibration disparity-mapping

我正在尝试使用StereoBM来获取两个图像的视差图。我尝试了一些示例代码和图像。他们工作正常。然而,当我尝试自己的图像时,我的地图非常糟糕,非常嘈杂。

enter image description here

enter image description here

enter image description here

我的StereoBM参数

sbm.state->SADWindowSize = 25;
sbm.state->numberOfDisparities = 128;
sbm.state->preFilterSize = 5;
sbm.state->preFilterCap = 61;
sbm.state->minDisparity = -39;
sbm.state->textureThreshold = 507;
sbm.state->uniquenessRatio = 0;
sbm.state->speckleWindowSize = 0;
sbm.state->speckleRange = 8;
sbm.state->disp12MaxDiff = 1;

我的问题是

  1. 关于我的图片的任何问题?
  2. 可以在没有相机校准的情况下获得良好的视差图吗?我是否需要在StereoBM
  3. 之前纠正图像

    感谢。

    这是我的整理图片代码

    Mat img_1 = imread( "image1.jpg", CV_LOAD_IMAGE_GRAYSCALE );
    Mat img_2 = imread( "image2.jpg", CV_LOAD_IMAGE_GRAYSCALE );
    
    int minHessian = 430;
    SurfFeatureDetector detector( minHessian );
    std::vector<KeyPoint> keypoints_1, keypoints_2;
    detector.detect( img_1, keypoints_1 );
    detector.detect( img_2, keypoints_2 );
    
    //-- Step 2: Calculate descriptors (feature vectors)
    SurfDescriptorExtractor extractor;
    Mat descriptors_1, descriptors_2;
    extractor.compute( img_1, keypoints_1, descriptors_1 );
    extractor.compute( img_2, keypoints_2, descriptors_2 );
    
    //-- Step 3: Matching descriptor vectors with a brute force matcher
    BFMatcher matcher(NORM_L1, true);   //BFMatcher matcher(NORM_L2);
    
    std::vector< DMatch > matches;
    matcher.match( descriptors_1, descriptors_2, matches );
    
    double max_dist = 0; double min_dist = 100;
    //-- Quick calculation of max and min distances between keypoints
    for( int i = 0; i < matches.size(); i++ )
    { double dist = matches[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }
    
    std::vector< DMatch > good_matches;
    vector<Point2f>imgpts1,imgpts2;
    for( int i = 0; i < matches.size(); i++ )
    {
        if( matches[i].distance <= max(4.5*min_dist, 0.02) ){
            good_matches.push_back( matches[i]);
            imgpts1.push_back(keypoints_1[matches[i].queryIdx].pt);
            imgpts2.push_back(keypoints_2[matches[i].trainIdx].pt);
        }
    
    }
    
    std::vector<uchar> status;
    cv::Mat F = cv::findFundamentalMat(imgpts1, imgpts2, cv::FM_8POINT, 3., 0.99, status);   //FM_RANSAC
    
    Mat H1,H2;
    cv::stereoRectifyUncalibrated(imgpts1, imgpts1, F, img_1.size(), H1, H2);
    
    cv::Mat rectified1(img_1.size(), img_1.type());
    cv::warpPerspective(img_1, rectified1, H1, img_1.size());
    
    cv::Mat rectified2(img_2.size(), img_2.type());
    cv::warpPerspective(img_2, rectified2, H2, img_2.size());
    
    StereoBM sbm;
    sbm.state->SADWindowSize = 25;
    sbm.state->numberOfDisparities = 128;
    sbm.state->preFilterSize = 5;
    sbm.state->preFilterCap = 61;
    sbm.state->minDisparity = -39;
    sbm.state->textureThreshold = 507;
    sbm.state->uniquenessRatio = 0;
    sbm.state->speckleWindowSize = 0;
    sbm.state->speckleRange = 8;
    sbm.state->disp12MaxDiff = 1;
    
    Mat disp,disp8;
    sbm(rectified1, rectified2, disp);
    

    经过校正的图像和视差图在这里

    enter image description here

    enter image description here

    enter image description here

    enter image description here

2 个答案:

答案 0 :(得分:5)

  1. 您的图片没有特别的问题。但是,如果计算时间不重要,我建议您使用更大的分辨率。另外,如果可能的话,最好使用未压缩的图像格式。

  2. 校准立体相机以校正立体声照片。哟确实需要纠正图片,但也可以在没有校准相机的情况下纠正它们。如果您只有很少的图片需要处理,您可以通过移动或旋转图像在Photoshop等中进行,以便匹配点在同一条线上。如果您要处理的图片数量较多,则可以像在代码中尝试一样进行处理。

  3. 我没有仔细检查你的代码,但我想你应该检查匹配点是否在同一行。

    在您的示例图片中实际情况并非如此,使用StereoSGMB代替StereoBM我得到了一些更好但仍然非常嘈杂的结果。

    enter image description here

    在StereoSGMB中获得良好的结果是一些参数调整。另请注意,后面的块的结果比前面的对象好得多,因为块具有纹理表面。

    以下是我使用的参数:

        Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,    //int minDisparity
                                            96,     //int numDisparities
                                            5,      //int SADWindowSize
                                            600,    //int P1 = 0
                                            2400,   //int P2 = 0
                                            20,     //int disp12MaxDiff = 0
                                            16,     //int preFilterCap = 0
                                            1,      //int uniquenessRatio = 0
                                            100,    //int speckleWindowSize = 0
                                            20,     //int speckleRange = 0
                                            true);  //bool fullDP = false
    
    sgbm->compute(left, right, disp);
    

答案 1 :(得分:0)

如果您的相机是平面的,请不要将stereoRectify返回的旋转矩阵传递给initUndistort。整流和非失真过程使极线呈水平。

正确完成后,三维点应位于每个图像的图像的同一行中。它看起来并不像。