双目立体匹配算法:SGBM

目录

什么是SGBM

SGBM的原理

SGBM的参数

SGBM的参数变化

OpenCV中的SGBM

代码实现

效果图

总结


什么是SGBM

SGBM(Semi-Global Block Matching)是一种用于计算双目视觉中视差(disparity)的半全局匹配算法,在OpenCV中的实现为semi-global block matching(SGBM)。它是基于全局匹配算法和局部匹配算法的优缺点,提出了一种折中的方法,既能保证视差图的质量,又能降低计算复杂度。

SGBM的原理

SGBM的原理可以分为以下几个步骤:

  1. 预处理:使用水平Sobel算子对左右图像进行边缘检测,得到梯度图像。

  2. 匹配代价计算:对于每个像素,计算其在不同视差下与对应像素的匹配代价,通常使用绝对差或平方差作为代价函数。

  3. 能量函数最小化:对于每个像素,定义一个能量函数,包括数据项和平滑项。数据项表示匹配代价,平滑项表示相邻像素的视差连续性。使用动态规划的方法,沿着多个方向(通常为8个或16个)计算累积代价,并求取最小值作为最终代价。

  4. 视差图生成:对于每个像素,根据最终代价选择最佳视差,并生成视差图。

  5. 视差图后处理:对于视差图中的异常值或空洞,使用一些后处理方法进行修复或填充,例如中值滤波、WLS滤波等。

SGBM的参数

SGBM的参数有以下几个:

  • minDisparity:最小视差值,默认为0。

  • numDisparities:视差范围,默认为16。必须是16的整数倍。

  • blockSize:匹配块大小,默认为3。必须是奇数且大于1。

  • P1:控制视差平滑度的第一个参数,默认为8blockSizeblockSize。P1越大,越倾向于生成连续的视差图。

  • P2:控制视差平滑度的第二个参数,默认为32blockSizeblockSize。P2越大,越倾向于消除小的视差变化。P2必须大于P1。

  • disp12MaxDiff:左右一致性检查时允许的最大视差差异,默认为-1,表示不进行检查。

  • preFilterCap:预处理时截断梯度值的上限,默认为63。

  • uniquenessRatio:唯一性检查时的阈值,默认为10。表示最佳视差值与次佳视差值之间的比例要大于该阈值才被认为是有效的。

  • speckleWindowSize:消除噪声斑点时考虑的窗口大小,默认为0,表示不进行消除。

  • speckleRange:消除噪声斑点时考虑的最大视差变化,默认为0,表示不进行消除。

  • mode:SGBM算法选择模式,默认为StereoSGBM::MODE_SGBM。可选值有StereoSGBM::MODE_SGBM_3WAY(速度快)、StereoSGBM::MODE_HH4(速度慢)、StereoSGBM::MODE_SGBM(速度中等)、StereoSGBM::MODE_HH(速度慢)。

SGBM的参数变化

下面通过调整每个参数来观察其影响效果:初始值设置:

minDisparity = 0
numDisparities = 16
blockSize = 3
P1 = 8*blockSize*blockSize
P2 = 32*blockSize*blockSize
disp12MaxDiff = -1
preFilterCap = 63
uniquenessRatio = 10
speckleWindowSiz
以下是双目立体匹配算法SGM的实时代码: ``` #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; const int max_image_size = 960; const int max_disparity = 64; const int P1 = 5; const int P2 = 70; const int penalty_scale = 10; const int uniqueness_ratio = 15; const int speckle_window_size = 100; const int speckle_range = 32; int main(int argc, char** argv) { if(argc != 3) { cout << "Usage: ./sgm_stereo left_image right_image" << endl; return -1; } Mat imgL = imread(argv[1], IMREAD_GRAYSCALE); Mat imgR = imread(argv[2], IMREAD_GRAYSCALE); if(imgL.empty() || imgR.empty()) { cout << "Error: Could not open or find the images" << endl; return -1; } int width = imgL.cols; int height = imgL.rows; if(width > max_image_size || height > max_image_size) { cout << "Error: Image size too large" << endl; return -1; } int min_disparity = 0; int max_disparity = 64; Mat disparity_map = Mat::zeros(height, width, CV_8UC1); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { int min_cost = INT_MAX; int best_disparity = min_disparity; for(int d = min_disparity; d < max_disparity; d++) { int sum = 0; int count = 0; for(int dy = -1; dy <= 1; dy++) { for(int dx = -1; dx <= 1; dx++) { int xl = x + dx; int xr = x + dx - d; if(xl < 0 || xl >= width || xr < 0 || xr >= width) { continue; } int diff = abs((int)imgL.at<uchar>(y+dy, x+dx) - (int)imgR.at<uchar>(y+dy, xr)); sum += diff; count++; } } int cost = sum / count; if(d > min_disparity) { int diff = abs(d - best_disparity); cost += (diff == 1) ? P1 : (P1 + (diff - 1) * P2); } if(cost < min_cost) { min_cost = cost; best_disparity = d; } } disparity_map.at<uchar>(y, x) = best_disparity; } } Ptr<StereoSGBM> stereo = StereoSGBM::create(min_disparity, max_disparity, penalty_scale, 8 * imgL.channels() * speckle_window_size * speckle_window_size, 32 * speckle_range, uniqueness_ratio, StereoSGBM::MODE_SGBM_3WAY); stereo->compute(imgL, imgR, disparity_map); namedWindow("Disparity Map", WINDOW_NORMAL); imshow("Disparity Map", disparity_map); waitKey(0); return 0; } ``` 需要注意的是,此代码只是SGM算法的实现之一,针对不同的场景和需求,实现方式可能会有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈子迩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值