使用opencv StereoBM产生了不良的视差图

6

我正在尝试使用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之前对图像进行校正吗?

谢谢。

这是我用于校正图像的代码:

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


是的,它们需要被纠正,就像你可以在文档中所读到的一样。 - Berriel
@Berriel,没有相机的任何信息,图像能被矫正吗?抱歉,我是新手。我读了stereo_match.cpp。它需要相机的内参参数。 - fnhdx
2个回答

5
  1. 关于您的图像,没有特别的问题。但是如果计算时间不紧要,我建议您使用更高的分辨率。此外,最好使用无压缩的图像格式,如果可能的话。

  2. 您可以对立体相机进行校准,以矫正您的立体图片。您确实需要矫正图片,但也有可能在没有校准的相机的情况下对其进行矫正。如果您只有少数几张照片需要处理,您可以在 Photoshop 或类似软件中通过移动或旋转图片使匹配点在同一行上来完成。如果您有更多的图片需要处理,您可以采用您在代码中尝试的方法来处理。

我没有详细查看您的代码,但我认为您应该检查匹配点是否在同一行上。

在您的样品图片中,这实际上是成立的,使用 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
谢谢你的回答。我认为纹理表面是关键。使用带有纹理的物体效果更好。 - fnhdx

0
如果您的相机是平面的,请不要将从stereoRectify返回的旋转矩阵传递给initUndistort。矫正和去畸变过程使极线水平。
当正确完成时,三维点应在每个图像的图像行中相同。看起来并非如此。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接