使用opencv StereoBM的坏视差图
Posted
技术标签:
【中文标题】使用opencv StereoBM的坏视差图【英文标题】:bad Disparity map using opencv StereoBM 【发布时间】:2016-06-24 14:03:57 【问题描述】:我正在尝试使用 StereoBM 来获取两个图像的视差图。我尝试了一些示例代码和图像。他们工作正常。但是,当我尝试自己的图像时,我得到的地图非常糟糕,非常嘈杂。
我的 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;
我的问题是
-
我的图片有什么问题吗?
是否可以在不校准相机的情况下获得良好的视差图?在 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);
校正后的图像和视差图在这里
【问题讨论】:
是的,他们需要纠正,你可以在docs阅读 @Berriel 可以在没有任何相机信息的情况下纠正图像吗?对不起,我是新手。我读了stereo_match.cpp。它需要相机的内在参数。 【参考方案1】:您的图像没有特别的问题。但是,如果计算时间并不重要,我建议您使用更大的分辨率。另外,如果可能的话,最好使用未压缩的图像格式。
您校准立体摄像头以校正立体图像。哟确实需要纠正图片,但也可以在没有校准相机的情况下纠正它们。如果您只有几张图片要处理,您可以在 Photoshop 等中通过移动或旋转图像以使匹配点在同一条线上来完成。如果您要处理的图片数量较多,您可以像在代码中尝试的那样进行处理。
我没有详细查看您的代码,但我想您应该检查匹配点是否在同一行。
在您的示例图片中,情况确实如此,使用 StereoSGMB 代替 StereoBM 我得到了一些更好但仍然非常嘈杂的结果。
在 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);
【讨论】:
感谢您的回答。我认为纹理表面是关键。通过使用纹理对象,我得到了更好的结果。【参考方案2】:如果您的相机是平面的,请不要将 stereoRectify 返回的旋转矩阵传递给 initUndistort。校正和不失真过程使核线水平。
正确完成后,三维点应位于每个图像的图像的同一行中。看起来不像。
【讨论】:
以上是关于使用opencv StereoBM的坏视差图的主要内容,如果未能解决你的问题,请参考以下文章
OpenCV立体匹配算法 StereoBM/StereoSGBM/StereoVar
在 opencv3 上进行视差映射的 cv2.StereoSGBM_create() 和 cv2.StereoBM_create() 函数有啥区别?