有关双目稠密匹配算法,OpenCV提供了BM和SGBM的实现。本文主要介绍其代码实现。
首先,需要定义相关变量。
cv::Mat imL, imR, disparity;
其次,在当前路径下存放双目的左视图和右视图,或者在其他路径下存放也可以,不过需要用到绝对路径。此处使用相对路径。
imL = cv::imread("imL.png", 0);
imR = cv::imread("imR.png", 0);
值得注意的是,默认状态下,OpenCV中的imread会将flag设置为1,也就是读入图像均为BGR三通道图像(包括灰度图像)。如果flag设为0,则转为灰度图像。
(1)BM的代码实现
int num_disp = 16;
int bsize = 9;
cv::Ptr<cv::StereoBM> bm = cv::StereoBM::create(num_disp, bsize);
// 设置参数
bm->setPreFilterType(CV_STEREO_BM_NORMALIZED_RESPONSE);
bm->setPreFilterSize(9);
bm->setPreFilterCap(31);
bm->setBlockSize(9);
bm->setMinDisparity(0);
bm->setNumDisparities(16);
bm->setTextureThreshold(10);
bm->setUniquenessRatio(5);
bm->setSpeckleWindowSize(100);
bm->setSpeckleRange(32);
// 计算视差
bm->compute(imL, imR, disparity);
// 将视差图的值除以16,同时转换为32为float型
disparity.convertTo(disparity, CV_32F, 1.0 / 16);
代码中变量num_disp表示自行设置的最大视差值,bsize为匹配块的大小。这两个为必须设置的参数,其他参数可以使用默认值,如有需要可以设置(在设置参数部分)。视差图的值除以16,得到真实视差。此时disparity中最大值为15。
(2)SGBM的代码实现
int min_disp = 0;
int num_disp = 16;
int bsize = 3;
// 设置参数
cv::Ptr<cv::StereoSGBM> left_matcher = cv::StereoSGBM::create(min_disp, num_disp, bsize);
left_matcher->setP1(24 * bsize * bsize);
left_matcher->setP2(96 * bsize * bsize);
left_matcher->setPreFilterCap(63);
left_matcher->setMode(cv::StereoSGBM::MODE_SGBM_3WAY);
// 计算视差
left_matcher->compute(imL, imR, disparity);
// 转换视差
disparity.convertTo(disparity, CV_32F, 1.0 / 16);
SGBM和BM的参数设置类似,只不过必要的参数需要增加一个min_disp,即最小视差。此外,SGBM的效果也更好。