立体匹配算法推理 - SGBM算法(二)

一、SGM算法

SGM算法的全称为Semi-Global Matching,网上关于它的介绍有很多不细讲,它的论文出处详见文末参考文献,但是这里也要为作者赞一把,很牛逼。

SGM其实本质上还是一种代价聚合算法,和局部立体匹配算法中的代价聚合很像,不然也不会叫Semi-Global了(当然也不全是哈,重点在后面~),而Global又是从何而来呢?为了达到和全局立体匹配算法一样全局能量函数最小化的效果,就需要更多或者全图所有的像素参与到当前像素的约束当中。但是刚刚也说了,SGM类似代价聚合,也就是一定范围内的邻域操作(邻域求和,加权平均等),那如何与整张图像上的像素扯上关系而不提高太多性能呢(重点是远距离像素也能扯上关系),于是作者想出了多路径约束聚合的思路,简单说就是让当前像素的代价聚合过程受多个方向(或路径)上所有像素的影响,方向越多参与影响当前像素的邻域像素就越多(原文说一般来讲8-16方向就比较不错了),这样既保证了全局像素的约束,又不用建立全局最小能量函数,避免了复杂运算符,降低了性能,所以才叫半全局算法(纯属个人理解哈),是不是很厉害呢?示意图如图1所示。不知道我这样讲解,有没有让你明白一点半全局的意思呢?

那么讲到这里,大家是不是会有一个疑问,对于每个像素点P都进行多个路径像素代价的聚合,是不是太夸张了,鲁棒性怎么解决?错误的或不正确的代价要怎么解决?和全局能量最小化差远了吧?还有就是数据越界了怎么办?写代码可是硬伤啊!

所以接下来就要说到作者提出的聚合公式,如下。说实话一看到公式我就浑身发抖,但是我们大致可以看出来,有多个最小值的比较,包括有点像惩罚参数P1和P2。what? 惩罚参数?这不是和全局立体匹配算法很像嘛,哈哈。如果把 r 看做是方向的话,那么下面两个公式看起来就像是多方向某个变量的求和(聚合)对吧?

这里必须给出公式的解释(很重要):
第一项表示视差为D时所有像素匹配代价之和。第二项表示对像素点p的邻域Np中的所有像素q增加一个惩罚常数P1(仅在视差差值为1个像素时起作用)。第三项表示对视差差值大于1的像素使用更大的惩罚常数P2。P1是为了适应倾斜或弯曲的表面。P2则是为了保留不连续性。同时作者也对P2阈值设定给出了方法:因为不连续性通常与梯度变化是对应的,因此,可以使用一下的计算公式:

简单讲P1与视差图的平滑有关,P2与视差图的边缘有关,这里给出两组不同P1和P2的效果图,给大家更清晰的认识。先看P1的结果,可以看出在P2不变的情况下,P1越大,图像越平滑。

0.1 * P1

P1

3*P1

再看P2,P2越大图像边缘越差:

P2 = 0.8 * P1

P2 = 1.6 * P1

P2 = 2.4 * P1

但是这里需要强调的是,P1和P2的变化规律并不是线性的,而是非线性的,意思就是达到某一个值以后,可能效果就不会再改变。

如果不容易理解的话,我们可以这样想,SGM的本质是想像素P的聚合过程有多个方向上的全局像素参数,那么我们可以先看单一方向的全局像素是如何参与聚合的。公式如下:

那么完成单一方向聚合约束,再把所有方向上的聚合约束加起来,是不是就是我们前面所说的多方向代价聚合约束了呢?公式如下:

我们这里先不管这个公式,先看opencv里面的代码是如何描述这个公式的。

简单说明一下:

L0 - L3 表示三个不同方向上的聚合值,一般来讲是左上角顺时针计算方向。类似下面这个样子:
1 2 3
0 p 4
7 6 5
Lr_p0 - Lr_p3 表示不同方向上的邻域像素的代价值。
这样我们大致就能看出来,这个公式和代码还是很对应的,无非就是求多个方向的最小值之和并约束一下嘛,我们以L0的计算为例:

假设
T0 = 像素p在0方向上的像素Lr_p0在视差值为d时的代价

T1 = 像素p在0方向上的像素Lr_p0在视差为d-1时的代价 + P1

T2 = 像素p在0方向上的像素Lr_p0在视差为d+1是的代价 + P1

T3 = 像素p在0方向上的像素Lr_p0在非d-1和d+1时的代价最小值 + P2

L0 = 当前代价 + min(T0, T1, T2, T3)- delta(防止聚合结果过大)

因此,我们只要将多个方向的代价求和,就完成了当前像素P的聚合过程。可以看出P1和P2惩罚的代价值所在位置是有区别的,较近的用P1,而较远的用P2,同时P2>P1,所以他们的作用也就比较明显,通过两个惩罚项来保证视差图的平滑和边缘,简单说如果P1或P2任意一个拦住了你,那么此处应该是平滑的(或者存在异常值)要好好保护起来,如果P1和P2都没能拦住你,那此处或者附近就真的是边缘,也要好好保护。

等到代价立方体所有代价值完成聚合,也就完成了代价的SGM优化。

完成SGM优化以后,SGBM算法剩下的就是视差计算和视差后处理步骤。视差计算相信大家都比较了解,这里采用的是胜者为王(WTA)算法,不过多介绍。

二、 后处理

重点介绍一下后处理算法。SGBM算法的后处理流程包括:置信度检测、亚像素插值和左右一致性检测。

置信度检测是利用代价立方体本身进行错误视差值的剔除。简单来讲就是最佳视差值要与一定范围内的视差值在代价值上面保持一定的全局最优关系,这样可以避免算法中经常遇到的局部最优解问题。置信度代码如下:

亚像素插值的目的简单说就是让物体表面视差更加的平滑,因为我们在立体匹配的时候是将双目视角所在空间粗略的分为了maxDisparity个平面,但是真实场景却又是连续且渐变的,其计算公式如下:

左右一致性检测的目的则是为了消除左右遮挡带来的视差错误,代码如下。这里要特别说明一下,左右一致性检测是需要用到左右视差图的,但是SGBM算法中并没有重新计算右视差图,而是采用左视差图推断出右视差图的。

最后给出WTA的结果和后处理完以后的结果,可以看出,后处理的效果还是非常明显的,是一个必不可少的部分。

参考文献:

Hirschm? H . Stereo Processing by Semiglobal Matching and Mutual Information[J]. IEEE Transactions on Pattern Analysis and Machine Intelligence, 2007, 30(2):328-341.

[双目视差] 立体匹配算法推理 - SGBM算法(二)的更多相关文章

  1. opencvSGBM半全局立体匹配算法的研究(1)

    转载请说明出处:http://blog.csdn.net/zhubaohua_bupt/article/details/51866567 这段时间对opencvSGBM半全局立体匹配算法进行了比較仔细 ...

  2. OpenCV3.4两种立体匹配算法效果对比

    以OpenCV自带的Aloe图像对为例:     1.BM算法(Block Matching) 参数设置如下: ) + ) & -; cv::Ptr<cv::StereoBM> b ...

  3. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  4. 字符串匹配算法之BM算法

    BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...

  5. TensorFlow 入门之手写识别(MNIST) softmax算法 二

    TensorFlow 入门之手写识别(MNIST) softmax算法 二 MNIST Fly softmax回归 softmax回归算法 TensorFlow实现softmax softmax回归算 ...

  6. 分布式共识算法 (二) Paxos算法

    系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.背景 1.1 命名 Paxos,最早是Le ...

  7. 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!

    前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...

  8. 字符串匹配算法之Sunday算法(转)

    字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...

  9. python+openCV实现双目视差图及测距

    通过matlab标定得到相机参数放到stereoconfig.py import numpy as np import cv2 #双目相机参数 class stereoCameral(object): ...

  10. 字符串匹配算法(三)-KMP算法

    今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...

随机推荐

  1. python 猜数字

    方法一 import randomif __name__ == '__main__':    yourname = input("你好! 你的名字是什么?\n");    prin ...

  2. Java学习文档

    数在计算机中是以二进制形式表示的,分为有符号数和无符号数,原码.反码.补码都是有符号定点数的表示方法.一个有符号定点数的最高位为符号位,0是正,1是负(以8位整数为例),例如0000001 就是+1, ...

  3. SEGGER_RTT_printf()函数添加打印浮点数功能

    SEGGER 的实时传输 (RTT) 是一种用于嵌入式应用程序中交互式用户 I/O 的技术.它以非常高的性能结合了 SWO 和半主机的优势.但是在笔者使用时(RTT v758版本),其暂时不支持浮点数 ...

  4. Windows Oracle 启动OracleDBConsoleorcl 服务时报 Window不能在 本地计算机启动 OracleDBConsoleorcl 。有关更多信息,查阅系统事件日志。如果这是非Microsoft服务,请与服务厂商联系,并参考特定服务错误代码 2 。

    一.报错信息如图 二.原因分析: 计算机主机名或IP地址有变化 三.解决方法 依次输入命令: Microsoft Windows [版本 10.0.22000.795](c) Microsoft Co ...

  5. SAP BADI总结

    SAP里标准拼法是BAdI,区分大小写.太麻烦,文章里全用大写. BADI技术的底层是接口,类等面向对象开发的内容. Classic BADI是一个BADI包了一个接口.实现它的话,需要一个接口的实现 ...

  6. 1 关于win10原生系统下 OCRmyPDF安装使用

    win10原生系统下 OCRmyPDF安装使用长期以来一直在代替freepic2pdf的工具,因为在图片转化PDF时,如果没有勾选该软件 添加OCR层 选项,印象中事后无法挂OCR层上去.福昕风腾,A ...

  7. Java8 lambda常用操作

    参考博客:https://www.cnblogs.com/hmy-1365/p/12923435.html

  8. MybatisPlus------代码生成器

    快速开发: 代码生成器: (1)模版:MyBatisPlus提供 (2)数据库相关配置:读取数据库获取信息 (3)开发者自定义配置:手工配置 package com.ithema; import co ...

  9. 实现hypothesis在网页标注后同步到本地obsidian

    实现hypothesis在网页标注后同步到本地obsidian 遇到的question 2023.3.21日 在更改了自己的模板之后,可以能按照Todo的方式展现所有的标记,但是发现在同一个网页上增加 ...

  10. springboot 连接不上 redis 的三种解决方案!

    针对于这种情况,首先,我们最简单直接的方法就是需要确认Redis是否已经正常启动(验证方法:如果安装在Linux下的话可以使用ps-ef|grep redis来进行确认是否开启) 如果未开启,我们可以 ...