文章目录

  • 1 概述
  • 2 模块说明
    • 2.1 特征抽取器
    • 2.2 相关金字塔
    • 2.3 多级更新算子
    • 2.4 Slow-Fast GRU
    • 2.5 监督
  • 3 效果

1 概述

在双目立体匹配中,基于迭代的模型是一种比较主流的方法,而其鼻祖就是本文要讲的RaftStereo。
先来说下什么是双目立体匹配。给定极线矫正后的左图和右图(IL,IR)(I_L, I_R)(IL,IR),双目立体匹配的目的就是估计一张视差图dddddd中每个像素位置的视差值dxyd_{xy}dxy表示在左图ILI_LIL(x,y)(x, y)(x,y)位置的像素与右图IRI_RIR中的(x−dxy,y)(x - d_{xy}, y)(xdxy,y)位置的像素在真实3D世界中对应于同一个物理点。换句话说,ddd表示了左图和右图在水平方向上的匹配关系。
有了视差图ddd,左右相机的焦距fxf_xfx和基线BBB,我们就可以通过式(1-1)得到左图的深度图DDD,这部分具体可以参考这篇。
D=Bfd(1-1)D = \frac{Bf}{d} \tag{1-1} D=dBf(1-1)
RaftStereo的输入是左右图(IL,IR)(I_L, I_R)(IL,IR),输出是视差ddd。由于视差ddd本身与相机参数无关,因此该方式训练得到的模型可以应用于不同参数的相机。
RaftStereo参考了Raft,由特征抽取器,相关金字塔和基于GRU的迭代更新算子组成,可见图1-1。
RAFT整体网络结构

图1-1 RAFT整体网络结构

2 模块说明

2.1 特征抽取器

如图1-1所示,特征抽取器指的就是encoder,共有两种encoder,一个叫做Feature Encoder,另一个叫做Context Encoder。
Feature Encoder同时作用于左、右图像,将每幅图像映射为密集特征图,进而构建相关体。该网络由一系列残差块和下采样层组成,根据实验中使用的下采样层数不同,可生成分辨率为输入图像1/4或1/8且包含256个通道的特征图。在Feature Encoder采用了Instance Normalization。
Context Encoder的架构与特征编码器完全相同,不同之处在于使用Batch Normalization替代了Instance Normalization,并且仅在左图上应用Context Encoder。上下文特征用于初始化更新算子的隐藏状态,并在每次迭代更新算子时输入GRU中。
关于feature encoder使用IN,context encoder使用BN的疑问。有人在github的issue上面也问了这个问题,可见https://github.com/princeton-vl/RAFT-Stereo/issues/17。
feature encoder中的IN比BN更有意义,因为作者希望仅从单个图像中导出每组相关特征。context encoder也可以用IN,但是BN更考虑整个数据集的均值和方差。
有一个细节,作者的代码中对BN进行了freeze_bn的操作,对应的代码是m.eval()这只是将均值和方差限制为[0, 1],对于 γ\gammaγβ\betaβ 并没有进行限制, γ\gammaγβ\betaβ 还是会进行梯度更新的。回顾一下BN的公式:
y=x−E[x]Var[x]+ϵ∗γ+βy = \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] + \epsilon}} * \gamma + \beta y=Var[x]+ϵxE[x]γ+β

2.2 相关金字塔

(1)相关体
采用特征向量之间的点积作为视觉相似度的衡量指标,对具有相同y坐标的像素进行相关计算。给定分别从ILI_LILIRI_RIR提取的特征图f,g∈RH×W×Df, g ∈ R^{H×W×D}f,gRH×W×D,将内积运算限制在具有相同第一索引的特征向量之间进行,可得到相关体,如下式(2-1)所示。
Cijk=∑hfijh⋅gikh,C∈RH×W×W(2-1)C_{ijk} = \sum_h f_{ijh} \cdot g_{ikh}, C \in R^{H \times W \times W} \tag{2-1} Cijk=hfijhgikh,CRH×W×W(2-1)
式(2-1)看不明白的话,可以先不看iii,也就是我们只看yyy方向确定的情况下,同一行的相关体计算方法。很容易看出CjkC_{jk}Cjk就表示左图jjj位置与右图kkk位置之间的相关性,这个相关性就是长度为DDD的向量fijf_{ij}fijgikg_{ik}gik的点积。
相关体的计算可以通过单个矩阵乘法来高效实现,这可以在GPU上轻松计算,并且只占用总运行时间的一小部分。
由于模型输入是极线校正后的图像,因此可以假设所有视差均为正值。因此,相关体的计算实际上只需针对正视差进行。然而,完整体计算的优势在于其运算可通过矩阵乘法实现,而该运算经过高度优化。这简化了整体架构设计,使作者能够采用通用运算而非定制GPU内核。
(2)相关金字塔
通过重复对最后一维进行平均池化,构建了一个四层结构的相关体金字塔。金字塔的第kkk层是通过使用核尺寸为2、步长为2的一维平均池化操作得到,从第kkk层的体积生成的相关体Ck+1C_{k+1}Ck+1,其维度为H×W×W/2kH×W×W/2^kH×W×W/2k。虽然金字塔的每一层都具有更大的感受野,但通过仅对最后一维进行池化处理,保留了原始图像中的高分辨率信息,从而能够恢复极其精细的结构特征。
(3)相关查找
为了在相关金字塔中建立索引,作者定义了一个类似于Raft中定义的查找算子LCL_CLC。给定当前视差估计值ddd,作者会围绕该估计值构建一个带有整数偏移量的一维网格(如图2-1所示)。这个网格用于从相关金字塔的每一层进行索引操作。
相关查找示意图

图2-1 相关查找示意图

由于网格的值都是整数,在每个相关体取索引时使用了线性插值。取回的值最终被拼接到一个特征图中。这部分的代码可以参考下面的x0变量的计算方式。

class CorrBlock1D:def __call__(self, coords):r = self.radiuscoords = coords[:, :1].permute(0, 2, 3, 1)batch, h1, w1, _ = coords.shapeout_pyramid = []for i in range(self.num_levels):corr = self.corr_pyramid[i]dx = torch.linspace(-r, r, 2*r+1)dx = dx.view(2*r+1, 1).to(coords.device)x0 = dx + coords.reshape(batch*h1*w1, 1, 1, 1) / 2**iy0 = torch.zeros_like(x0)coords_lvl = torch.cat([x0,y0], dim=-1)corr = bilinear_sampler(corr, coords_lvl)corr = corr.view(batch, h1, w1, -1)out_pyramid.append(corr)out = torch.cat(out_pyramid, dim=-1)return out.permute(0, 3, 1, 2).contiguous().float()

2.3 多级更新算子

从初始点d0=0d_0 = 0d0=0出发,预测一系列视差场{d1,...,dN}\{ d_1, ..., d_N \}{d1,...,dN}。在每次迭代中,利用当前视差估计值对相关体进行索引,生成一组相关特征。这些特征会依次通过两个卷积层处理,同时当前视差估计值也会经过两次卷积层处理。随后将相关特征、视差特征和上下文特征拼接后输入GRU,由GRU更新隐藏状态。最终利用更新后的隐藏状态来预测视差的动态变化。
(1)多个隐藏状态
原始的Raft算法完全采用固定高分辨率进行更新。这种方法存在一个明显缺陷:感受野面积会随着GRU更新次数的增加而缓慢增长,这在处理具有大面积无纹理区域且局部信息匮乏的场景时容易引发问题。为解决这一难题,提出了一种多分辨率更新算子,该算子可同时作用于1/8、1/16和1/32分辨率的特征图。实验结果表明,采用这种多分辨率更新算子能显著提升模型的泛化性能。
如图2-2所示,GRU通过相互使用对方的隐藏状态作为输入进行交叉连接。相关查找和最终的视差更新由分辨率最高的GRU完成。
多级GRU

图2-2 多级GRU

(2)上采样
预测的视差场分辨率是输入图像的1/4或1/8。为了输出全分辨率视差图,采用了与Raft相同的凸上采样方法。RAFT-Stereo将全分辨率视差值视为其粗分辨率邻近点3x3网格的凸组合结果,而凸组合权重则由最高分辨率GRU进行预测。
上采样部分的代码为

def upsample_flow(self, flow, mask):""" Upsample flow field [H/8, W/8, 2] -> [H, W, 2] using convex combination """N, D, H, W = flow.shapefactor = 2 ** self.args.n_downsamplemask = mask.view(N, 1, 9, factor, factor, H, W)mask = torch.softmax(mask, dim=2)up_flow = F.unfold(factor * flow, [3,3], padding=1)up_flow = up_flow.view(N, D, 9, 1, 1, H, W)up_flow = torch.sum(mask * up_flow, dim=2)up_flow = up_flow.permute(0, 1, 4, 2, 5, 3)return up_flow.reshape(N, D, factor*H, factor*W)

其中的mask就是最高分辨率GRU预测得到的凸组合权重。

2.4 Slow-Fast GRU

将GRU更新到1/8分辨率的隐藏状态,其浮点运算量大约是更新1/16分辨率隐藏状态的四倍。为了利用这一特性提升推理速度,作者对RAFT-Stereo模型进行了优化,每当更新1/8分辨率隐藏状态时,就会同步多次更新1/16和1/32分辨率的隐藏状态。在KITTI分辨率图像上进行32次GRU更新后,这一改进使RAFTStereo的运行时间从0.132秒缩短至0.05秒,效率提升达52%。
这种改进使RAFT-Stereo在实时立体视觉方面具有竞争力的性能,而运行的方法快一个数量级,如下表2-1的Slow-Fast行所示。
消融实验

表2-1 消融实验

作者发现,通过增加低分辨率GRU的迭代次数并减少高分辨率GRU的迭代次数,在略微降低精度的情况下,RAFT-Stereo的运行时间显著缩短。Slow-Fast版本的RaftStereo分别将最低、中等和最高分辨率的隐藏状态更新30次、20次和10次,而Regular版本则将每个隐藏状态更新32次。无论是Slow-Fast还是Regular版本,都使用相同的模型权重。Slow-Fast-GRU这部分的代码如下所示

for itr in range(iters):coords1 = coords1.detach()corr = corr_fn(coords1) # index correlation volumeflow = coords1 - coords0with autocast(enabled=self.args.mixed_precision):if self.args.n_gru_layers == 3 and self.args.slow_fast_gru: # Update low-res GRUnet_list = self.update_block(net_list, inp_list, iter32=True, iter16=False, iter08=False, update=False)if self.args.n_gru_layers >= 2 and self.args.slow_fast_gru:# Update low-res GRU and mid-res GRUnet_list = self.update_block(net_list, inp_list, iter32=self.args.n_gru_layers==3, iter16=True, iter08=False, update=False)net_list, up_mask, delta_flow = self.update_block(net_list, inp_list, corr, flow, iter32=self.args.n_gru_layers==3, iter16=self.args.n_gru_layers>=2)

从代码中不难看出,self.args.slow_fast_gru=True时,计算量反而会增加,并没有起到提速的效果。这是为啥呢?
使用Slow-Fast-GRU时的做法是将总的迭代次数减少,32->7,但是这样的效果会变差。但现在模型的做法都是在Slow-Fast-GRU为True的情况下,同时设置迭代次数为32,这其实更慢了。在github issue上面其他人的提问和作者解答可见https://github.com/princeton-vl/RAFT-Stereo/issues/25。

2.5 监督

作者在预测序列{d1,...,dN}\{ d_1, ..., d_N \}{d1,...,dN}中,通过指数级递增的权重对预测视差与真实视差之间的L1L1L1距离进行监督。给定真实视差dgtd_{gt}dgt时,损失函数定义为
L=∑i=1NγN−i∣∣dgt−di∣∣1(2-2)L = \sum^N_{i=1} \gamma^{N-i} || d_{gt} - d_i ||_1 \tag{2-2} L=i=1NγNi∣∣dgtdi1(2-2)
其中,γ=0.9\gamma = 0.9γ=0.9

3 效果

作者对比了RaftStereo与其他双目深度估计算法的泛化能力,这些算法均在虚拟场景数据集Sceneflow上进行训练,并在真实场景数据集上进行测试,可见表3-1。表中的数值表示误差,即误差超过指定阈值的像素百分比。作者采用标准评估阈值是KITTI为3像素,Middlebury为2像素,ETH3D为1像素。
泛化能力效果对比

表3-1 泛化能力效果对比

不同模型之间的可视化效果对比可见图3-1,可见RaftStereo对于细结构的物体效果更好。
可视化效果对比

图3-1 可视化效果对比

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90768.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90768.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/90768.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内存优化:从堆分配到零拷贝的终极重构

引言 在现代高性能软件开发中,内存管理往往是性能优化的关键战场。频繁的堆内存分配(new/delete)不仅会导致性能下降,还会引发内存碎片化问题,严重影响系统稳定性。本文将深入剖析高频调用模块中堆分配泛滥导致的性能塌方问题,并…

【GoLang#2】:基础入门(工具链 | 基础语法 | 内置函数)

前言:Go 的一些必备知识 1. Go 语言命名 Go的函数、变量、常量、自定义类型、包(package)的命名方式遵循以下规则: 首字符可以是任意的Unicode字符或者下划线剩余字符可以是Unicode字符、下划线、数字字符长度不限 Go 语言代码风格及开发事项代码每一行结…

Bert项目--新闻标题文本分类

目录 技术细节 1、下载模型 2、config文件 3、BERT 文本分类数据预处理流程 4、对输入文本进行分类 5、计算模型的分类性能指标 6、模型训练 7、基于BERT的文本分类预测接口 问题总结 技术细节 1、下载模型 文件名称--a0_download_model.py 使用 ModelScope 库从模型仓…

sendfile系统调用及示例

好的,我们继续学习 Linux 系统编程中的重要函数。这次我们介绍 sendfile 函数,它是一个高效的系统调用,用于在两个文件描述符之间直接传输数据,通常用于将文件内容发送到网络套接字,而无需将数据从内核空间复制到用户空…

数据结构习题--删除排序数组中的重复项

数据结构习题–删除排序数组中的重复项 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 方法&…

Docker的容器设置随Docker的启动而启动

原因也比较简单,在docker run 的时候没有设置–restartalways参数。 容器启动时,需要增加参数 –restartalways no - 容器退出时,不重启容器; on-failure - 只有在非0状态退出时才从新启动容器; always - 无论退出状态…

JWT安全机制与最佳实践详解

JWT(JSON Web Token) 是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为紧凑且自包含的 JSON 对象。它被广泛用于身份验证(Authentication)和授权(Authorization&#xff…

如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题 摘要 在开发过程中,我们常常会遇到pip install报错的问题,其中一个常见的报错是 ModuleNotFoundError: No module named…

从三维Coulomb势到二维对数势的下降法推导

题目 问题 7. 应用 9.1.4 小节描述的下降法,但针对二维的拉普拉斯方程,并从三维的 Coulomb 势出发 KaTeX parse error: Invalid delimiter: {"type":"ordgroup","mode":"math","loc":{"lexer&qu…

直播一体机技术方案解析:基于RK3588S的硬件架构特性​

硬件配置​​主控平台​​▸ 搭载瑞芯微RK3588S旗舰处理器(四核A762.4GHz 四核A55)▸ 集成ARM Mali-G610 MP4 GPU 6TOPS算力NPU▸ 双通道LPDDR5内存 UFS3.1存储组合​​专用加速单元​​→ 板载视频采集模块:支持4K60fps HDMI环出采集→ 集…

【氮化镓】GaN取代GaAs作为空间激光无线能量传输光伏转换器材料

2025年7月1日,西班牙圣地亚哥-德孔波斯特拉大学的Javier F. Lozano等人在《Optics and Laser Technology》期刊发表了题为《Gallium nitride: a strong candidate to replace GaAs as base material for optical photovoltaic converters in space exploration》的文章,基于T…

直播美颜SDK动态贴纸模块开发指南:从人脸关键点识别到3D贴合

很多美颜技术开发者好奇,如何在直播美颜SDK中实现一个高质量的动态贴纸模块?这不是简单地“贴图贴脸”,而是一个融合人脸关键点识别、实时渲染、贴纸驱动逻辑、3D骨骼动画与跨平台性能优化的系统工程。今天,就让我们从底层技术出发…

学习游戏制作记录(剑投掷技能)7.26

1.实现瞄准状态和接剑状态准备好瞄准动画,投掷动画和接剑动画,并设置参数AimSword和CatchSword投掷动画在瞄准动画后,瞄准结束后才能投掷创建PlayerAimSwordState脚本和PlayerCatchSwordState脚本并在Player中初始化:PlayerAimSwo…

【c++】问答系统代码改进解析:新增日志系统提升可维护性——关于我用AI编写了一个聊天机器人……(14)

在软件开发中,代码的迭代优化往往从提升可维护性、可追踪性入手。本文将详细解析新增的日志系统改进,以及这些改进如何提升系统的实用性和可调试性。一、代码整体背景代码实现了一个基于 TF-IDF 算法的问答系统,核心功能包括:加载…

visual studio2022编译unreal engine5.4.4源码

UE5系列文章目录 文章目录 UE5系列文章目录 前言 一、ue5官网 二.编译源码中遇到的问题 前言 一、ue5官网 UE5官网 UE5源码下载地址 这样虽然下载比较快,但是不能进行代码git管理,以后如何虚幻官方有大的版本变动需要重新下载源码,所以我们还是最好需要visual studio2022…

vulhub Earth靶场攻略

靶场下载 下载链接:https://download.vulnhub.com/theplanets/Earth.ova 靶场使用 将压缩包解压到一个文件夹中,右键,用虚拟机打开,就创建成功了,然后启动虚拟机: 这时候靶场已经启动了,咱们现…

Python训练Day24

浙大疏锦行 元组可迭代对象os模块

Spring核心:Bean生命周期、外部化配置与组件扫描深度解析

Bean生命周期 说明 程序中的每个对象都有生命周期,对象的创建、初始化、应用、销毁的整个过程称之为对象的生命周期; 在对象创建以后需要初始化,应用完成以后需要销毁时执行的一些方法,可以称之为是生命周期方法; 在sp…

日语学习-日语知识点小记-进阶-JLPT-真题训练-N1阶段(1):2017年12月-JLPT-N1

日语学习-日语知识点小记-进阶-JLPT-真题训练-N1阶段(1):2017年12月-JLPT-N1 1、前言(1)情况说明(2)工程师的信仰(3)真题训练2、真题-2017年12月-JLPT-N1(1&a…

(一)使用 LangChain 从零开始构建 RAG 系统|RAG From Scratch

RAG 的主要动机 大模型训练的时候虽然使用了庞大的世界数据,但是并没有涵盖用户关心的所有数据, 其预训练令牌(token)数量虽大但相对这些数据仍有限。另外大模型输入的上下文窗口越来越大,从几千个token到几万个token,…