双目立体匹配算法:SGM

本文详细介绍了双目立体匹配中的SGM(半全局匹配)算法,包括匹配代价计算、动态规划、代价聚合、视差计算、后处理等步骤。SGM通过一维动态规划近似全局优化,具有较高的匹配精度和速度。OpenCV中的SGBM算法进行了预处理、代价计算、聚合和后处理等优化,适用于实际应用。
摘要由CSDN通过智能技术生成

一、简介

  立体匹配旨在为校正后的左右视图提供稠密的匹配对,这种问题称为"stereo correspondence problem"。有大量的算法用于求解立体匹配问题,根据Scharstein和 Szeliski的研究,所有这些算法的计算流程基本上都可以分为四个步骤:A.匹配代价计算;B.代价聚合; C.视差计算/优化; D.视差细化。其中匹配代价用来度量像素或者像素块之间的相似性,计算匹配代价的方法有AD、SAD、BT、NCC、Census-Hamming、HMI、Daisy以及基于深度学习方法的匹配代价等等。代价聚合的目的是将每个像素的匹配代价和它周围的像素关联起来,常用的方法是将一个固定尺寸的窗口中的相同视差下的匹配代价简单求和、加权求和,或者在利用图像中的梯度或颜色进行分割后的区域中进行聚合,还有一些方法使用引导滤波等进行代价聚合。
  在上述框架下,立体匹配算法基本被分类为两种:(1)局部算法:A => B => C => D(2)全局算法:A => C => D。局部算法一般在代价聚合之后,通过选择最低匹配代价来得到对应的视差,即winner takes all。全局算法没有进行代价聚合,而是定义了一个包含数据项和平滑项的能量函数并通过最小化能量函数来求得视差,数据项一般为所有像素的代价和,平滑项一般为对邻域像素视差差异的惩罚,部分方法还添加更多的项,比如对遮挡区域的惩罚、左右一致性或对称性约束,或者根据分割区域对平滑项进行加权等。根据所使用的优化方法,全局算法主要有Dynamic programming、Graph Cut、Belief Propogation等。

​  全局算法由于非常高的运算量或内存消耗,在大多数场合都无法应用,而局部算法虽然速度很快,但是鲁棒性差,匹配质量比较低。2005年,Heiko Hirschmuller提出了一种半全局的立体匹配算法,叫做SGM,该算法建议采用单像素互信息(HMI)作为匹配代价,沿着多个方向进行一维能量最小化来近似替代二维全局能量最小化,因此被称为半全局算法。SGM的运算速度远远快于大多数全局算法,同时精度也比较高,除了深度学习的方法外,SGM在各种公开数据集的双目匹配任务的排行榜上一直都位列前排,证明了SGM算法的强大。在OpenCV中高度优化的SGBM算法对于1920*1080分辨率的图像,其运行时间可以低至300ms以内(当然这还取决于机器性能)。

二、SGM

1.pixelwise匹配代价计算:HMI

​  互信息(Mutual Information)用于表征两幅图像共有信息量的大小,可作为两幅图像相似性的度量,然而MI是针对整张图像而言的,Junhwan Kim通过对MI进行泰勒展开得到单像素的互信息HMI的计算方法,该方法作为像素相似性度量对光照变化较为鲁棒,是一种优秀的代价函数。关于如何求解单像素互信息,限于篇幅这里就不叙述了,详情可以查看作者论文。

2.动态规划
2.1一些基本概念

  动态规划(dynamic programming)是一种求解多阶段决策过程(decision process)最优化的数学方法,即利用各阶段之间的关系,逐个求解。下面介绍一些动态规划算法的基本概念。
(1)阶段:阶段是整个过程的自然划分,通常按时间顺序或空间特征划分阶段,表示阶段序号的变量称为阶段变量,一般用字母 k k k表示。
(2)状态:在整个过程中,每个阶段开始所处的自然状况或客观条件称为状态,是不可控因素。状态变量常用 s k s_{k} sk表示。
(3)决策:一个阶段的状态确定后,可以作出不同的选择,从而演变到下一阶段的某个状态,这种选择叫做决策,常用 u k u_{k} uk表示。
(4)策略:由决策组成的序列称为策略。
(5)状态转移方程:给定第k阶段的状态和决策,则第 k + 1 k+1 k+1阶段的状态由状态转移方程决定。
(6)指标函数:指标函数是衡量过程优劣的数量指标,它是定义在全过程和所有后部子过程上的数量函数,对于给定的状态,指标函数值 随策略改变,采用不同的策略可以得出不同的指标函数值。
(7)最优策略和最优轨线:使指标函数达到最优值(最大值或最小值)的策略称为最优策略,按最优策略和状态转移方程得出的状态序列为最优轨线。

2.2基于动态规划的立体匹配

  动态规划立体匹配是建立在极线约束的基础上的,其大致思想就是在每条对极线上寻找一条最优的匹配路径,使得全局能量函数在每条对极线上达到最低。在经过立体校正以后,对极线则转变为左右视图每一对应的水平行。

在沿着对极线进行动态规划时通常要遵循以下几个约束:
 (1) 视差范围约束:即视差的搜索范围是有限的,不能在一个无限大的区间内去搜索视差;
 (2) 唯一性约束:给定左图中的一个像素点,它在右图中最多只能有一个对应点;
 (3) 可见性约束:当某点处于遮挡区域时,它在另一幅图中将无法找到对应点,遮挡区域一般出现在由背景进入前景或者由前景进入背景的边界地带;
 (4) 顺序性约束:即假设在左图中的两个点的横坐标为 x l 1 , x l 2 x^{1}_{l}, x^{2}_{l} xl1,xl2,在右图中的对应点横坐标为 x r 1 , x r 2 x^{1}_{r}, x^{2}_{r} xr1,xr2,若 x l 1 < x l 2 x^{1}_{l}<x^{2}_{l}

以下是双目立体匹配算法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算法的实现之一,针对不同的场景和需求,实现方式可能会有所不同。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值