立体匹配算法推理 - 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. Servlet与JSP学习笔记

    一.Servlet 注册 web.xml里边注册Servlet ,定义格式如下: <servlet> <servlet-name>helloworld</servlet- ...

  2. protobuf怎么处理java中的Object和Object[],protobuf的bytestring和object[]

    如题,作者一开始也遇到了这个比较棘手的问题. 话不多说,直接说解决方案. 这里使用bytestring,如果是object[]的话则用repeated定义即可. 那么问题又来了,用这个类型怎么做到与j ...

  3. vue 数组修改 页面无法刷新

    saveData: { current: 1, records:[] , total:0}, countSaveMoney:{ bidSuccessMoney:0, saveMoney:0},页面上有 ...

  4. 利用selenium爬取前程无忧招聘数据

    1.背景介绍 selenium通过驱动浏览器,模拟浏览器的操作,进而爬取数据.此外,还需要安装浏览器驱动,相关步骤自行解决. 2.导入库 import csv import random import ...

  5. springboot邮箱验证功能部署到服务器后报25 timeout的解决方式

    可以写在application.yml中或者 写在配置类中, 如下; 原理就是更改端口,并且配置ssl的相关配置 package com.wfszmg.config; import org.sprin ...

  6. QGIS 导入文本数据(WKT)

    在做GIS数据处理的时候,经常会遇到原始数据是 text.csv.Excel 等格式的数据.要使用数据前提是要先转换数据. 这里是介绍用 QGIS 导入数据.打开导入方式如下(根据自己的文本类型选择不 ...

  7. 解密Prompt系列4. 升级Instruction Tuning:Flan/T0/InstructGPT/TKInstruct

    这一章我们聊聊指令微调,指令微调和前3章介绍的prompt有什么关系呢?哈哈只要你细品,你就会发现大家对prompt和instruction的定义存在些出入,部分认为instruction是promp ...

  8. [BUUCTF]Web刷题记录

    为提升观感体验,本篇博文长期更新,新题目以二次编辑形式附在最后 [ACTF2020 新生赛]Exec 打开后发现网页是关于执行一个ping指令,经过测试是直接执行的,所以就直接命令执行了 127.0. ...

  9. NEFU高级程序设计-期末复习习题组

    1. 用链表实现单词序列倒序输出 题目 用链表实现单词序列倒序输出.与以往不同,请考虑采用一种完全的动态分配方式! 为降低难度,"仁慈"的我已经给出了输出和释放的代码,你只要写出创 ...

  10. 基于开源的 ChatGPT Web UI 项目,快速构建属于自己的 ChatGPT 站点

    作为一个技术博主,了不起比较喜欢各种折腾,之前给大家介绍过 ChatGPT 接入微信,钉钉和知识星球(如果没看过的可以翻翻前面的文章),最近再看开源项目的时候,发现了一个 ChatGPT Web UI ...