精华内容
下载资源
问答
  • ORB-SLAM2的最大贡献就是把原来的系统扩展到了双目rgbd上,这一篇也主要讲的是怎么使用双目或者深度相机的信息,以及他们和单目的区别。 I.INTRODUCTION Place Recognition是SLAM中一个对回环很重要的模块,作用...

    ORB-SLAM2的最大贡献就是把原来的系统扩展到了双目,rgbd上,这一篇也主要讲的是怎么使用双目或者深度相机的信息,以及他们和单目的区别。

    I.INTRODUCTION

    1. Place Recognition是SLAM中一个对回环很重要的模块,作用是:1)检测传感器是否返回已经建过图的区域。2)修正累计误差。 3)在追踪失败之后重新定位相机。
    2. 单目SLAM的优缺点:
    • 优点:成本更低,传感器配置更简单
    • 缺点:由于无法直接获得深度信息,所以就需要利用多视图或者滤波来生成初始地图(在最开始无法进行三角化);会有尺度漂移;纯旋转时可能会失效。(如果用双目或者rgbd相机,所有的缺点都可以被解决)
    1. 主要贡献中的两个亮点:
    • RGB-D结果表明使用BA能比sota的ICP或者基于光度和深度误差最小化的方法更准。
    • 通过使用近距离和远距离立体点和单目观测结果,我们的立体结果比sota的直接法立体 SLAM 更准确。

    II.RELATED WORK

    双目SLAM

    • 文献[5]第一次使用了近点和远点(双目相机中,因为视差太小导致深度无法被可靠估计的点),使用了逆深度来表示远点。经验上,如果点的深度小于双目基线的40倍,那么这些点可以被可靠的三角化。
    • 用滑窗可以实现BA的常数时间复杂度,但是不能保证全局一致性(?)。对于ORB-SLAM2,自局部的关键帧使用BA来保证时间复杂度与map大小无关;在回环时,系统先对其两边,所以追踪可以继续用老地图定位,然后用全局BA来实现位姿图优化来最小化累计漂移。

    RGB-D SLAM

    • ORB-SLAM2使用深度信息来给图像上提取出的特征点合成双目坐标。这样双目和rgb-d的输入的之后处理其实就可以统一了。ORB-SLAM2这里的后端用的是BA,也建立了一个全局一致的稀疏重建。因为目的就是长时间和全局一致的定位,而不是为了有很多细节的稠密重建。但是在有了很准的关键帧位姿之后,就可以融合深度地图和得到局部准确的重建;或者是在全局BA后,后处理由所有关键帧构成的深度地图,得到整个场景的准确的3D模型。

    III.ORB-SLAM2

    扩充传感器之后,整体的流程图为:
    在这里插入图片描述1. 三个平行的主线程是:
    1)追踪:每一帧都去找和局部地图的特征匹配来定位相机,并使用motion only BA来最小化重投影误差。
    2)局部建图:管理局部地图并优化,使用局部BA
    3)回环:检测大回环,通过位姿图优化修正累计漂移(~)。这个线程还启动了第四个线程在位姿图优化之后进行全局BA。
    2. 需要用到重定位的场合:

    • 追踪失效(如遮挡)
    • 重初始化(在已经建图过的场景)
    • 回环检测

    A. Monocular, Close Stereo and Far Stereo Keypoints

    从前面的流程图可以看到,后续双目和rgbd其实是没有区别的。所以这里重点说双目关键点和单目关键点。

    双目关键点

    双目关键点的深度如果小于40倍基线长度的值,就被叫做近关键点,否则就是远关键点。近关键点可以较好的被三角化,并提供尺度,平移,旋转信息。而远关键点可以提供比较好的旋转信息,但只能有比较差的尺度和平移信息,远点用多视角进行三角化。
    定义: ( u L , v L , u R ) (u_L, v_L, u_R) (uL,vL,uR)表示。前两个就是在左图像的特征点坐标, u R u_R uR是在右图像匹配特征点的水平坐标。对于双目相机,利用双目的校正后图像进行搜索(此时极线水平,搜索很快)。对于RGB-D相机,就计算出一个虚拟的右坐标:
    u R = u L − f x b d u_R = u_L - \frac{f_xb}{d} uR=uLdfxb
    f x f_x fx是水平焦距,b是结构光投影和红外线相机的基线,深度传感器的不确定度就是用虚拟右坐标的不确定度表示。

    单目关键点

    定义: 对于ORB特征点中,那些没有对应双目匹配的,或者是没有有效深度值的特征点,取他们在左图像中的点坐标作为单目关键点,即 ( u L , v L ) (u_L, v_L) (uL,vL)
    如何三角化: 只能通过多视角三角化,不提供尺度信息,只提供旋转和平移估计。

    B. System Bootstrapping

    不需要像单目那样进行系统初始化了。第一帧时就可以创建一个关键帧,把它的pose设置到起点,从所有双目关键点创建出一个初始地图。

    C. Bundle Adjustment with Monocular and Stereo Constraints

    追踪线程:用BA优化相机位姿(motion only BA)
    局部建图线程:局部BA,优化一个局部窗口内的关键帧和点
    闭环之后:全局BA,优化所有关键帧和点
    使用的是g2o的LM方法

    Motion-only BA

    最小化匹配的世界坐标系3D点 X i ∈ R 3 X^i \in \mathbb R^3 XiR3和关键点 x ( ⋅ ) i x^i_{(·)} x()i之间的重投影误差。对于单目关键点 x m i ∈ R 2 x_m^i \in \mathbb R^2 xmiR2或者双目关键点 x s i ∈ R 3 x^i_s \in \mathbb R^3 xsiR3, 都满足下面的式子:
    { R , t } = arg ⁡ min ⁡ R , t ∑ ρ ( ∥ x ( ⋅ ) i − π ( ⋅ ) ( R X i + t ) ∥ ∑ 2 ) \{ R,t \} = \mathop{\arg\min_{R,t}} \sum \rho (\Vert x^i_{(·)} - \pi_{(·)}(RX^i + t) \Vert _{\sum} ^2) {R,t}=argR,tminρ(x()iπ()(RXi+t)2)
    这里的i就是所有匹配集合中的某一个; ρ \rho ρ就是鲁棒的Huber cost function; ∑ \sum 是关键点尺度相关的协方差矩阵;对于投影方程 π ( ⋅ ) \pi_{(·)} π(),单目和双目的都有各自的定义:

    π m ( [ X Y Z ] ) = [ f x X Z + c x f y Y Z + c y ] , π s ( [ X Y Z ] ) = [ f x X Z + c x f y Y Z + c y f x X − b Z + c x ] \pi_m(\begin{bmatrix} X\\ Y\\ Z\\ \end{bmatrix}) = \begin{bmatrix} f_x \frac{X}{Z} + c_x\\ f_y \frac{Y}{Z} + c_y\\ \end{bmatrix}, \pi_s(\begin{bmatrix} X\\ Y\\ Z\\ \end{bmatrix}) = \begin{bmatrix} f_x \frac{X}{Z} + c_x\\ f_y \frac{Y}{Z} + c_y\\ f_x \frac{X-b}{Z} + c_x\\\end{bmatrix} πm(XYZ)=[fxZX+cxfyZY+cy],πs(XYZ)=fxZX+cxfyZY+cyfxZXb+cx

    Local BA

    优化共视的关键帧 K L K_L KL和这些关键帧中的所有点 P L P_L PL。那些没有共视的关键帧 K F K_F KF,其中被观察到的 P L P_L PL对cost函数有贡献,但是在优化过程中保持不变(??)。定义 χ k \chi_k χk是在 P L P_L PL中的点和一个关键帧k中关键点之间的匹配集合,优化问题如下:
    { X i , R l , t l ∣ i ∈ P L , l ∈ K L } = arg min ⁡ X i , R l , t l ∑ k ∈ K L ∪ K F ∑ j ∈ χ k ρ ( E k j ) E k j = ∥ x ( ⋅ ) i − π ( ⋅ ) ( R k X j + t k ) ∥ ∑ 2 \{X^i, R_l, t_l \vert i \in P_L, l \in K_L\} = \mathop{\argmin_{X^i, R_l, t_l} \sum_{k\in K_L \cup K_F} \sum_{j \in \chi_k}\rho (E_{kj})} \\E_{kj} = \Vert x^i_{(·)} - \pi_{(·)}(R_kX^j + t_k) \Vert _{\sum} ^2 {Xi,Rl,tliPL,lKL}=Xi,Rl,tlargminkKLKFjχkρ(Ekj)Ekj=x()iπ()(RkXj+tk)2

    Full BA

    这个就是Local BA的特例,此时所有的关键帧和地图中的所有点都会被优化,除了被固定的初始关键帧(固定是为了消除gauge freedom)。

    D. Loop Closing and Full BA

    对于双目和rgbd的情况,不会有尺度漂移,而且双目或者深度信息是基于刚体转换的而不是相似度(~)。
    在 ORB-SLAM2 中,在位姿图之后加入了完整的 BA 优化以实现最佳解决方案。这种优化可能很耗时,所以在单独的线程中执行,这样就可以让系统继续创建地图和检测回环。但是,这让BA输出和地图当前状态的合并造成了困难。

    • 如果在优化运行时检测到新回环,将中止优化并继续闭环,这将再次启动完整的 BA 优化。
    • 当全局 BA 完成时,需要将更新的关键帧子集和由全局BA优化的点与 未更新的关键帧和在优化运行时插入的点合并(~)。这是通过将更新的关键帧的校正(即从未优化到优化的姿势的转换)通过生成树传播到未更新的关键帧来完成的。未更新的点根据应用于其参考关键帧的校正进行变换。 (~)

    E. Keyframe Insertion

    和单目的一样,都是尽可能多的加入关键帧,然后再去掉冗余的关键帧。
    但考虑到近关键点和远关键点,这里还引入了一个新的条件:如果跟踪的近点的数量小于阈值 τ t \tau_t τt且这一帧可以创造至少 τ c \tau_c τc个近双目点,那么就插入一个新关键帧。经验值 τ t = 100 , τ c = 70 \tau_t=100, \tau_c=70 τt=100τc=70

    F. Localization Mode

    局部建图和回环线程是不激活的,只有追踪线程工作,而追踪线程使用视觉里程计匹配和地图点匹配。

    • 视觉里程计匹配:当前帧ORB特征点和之前帧从双目或深度信息得来的3D点的匹配。这种匹配可以对没有建图的区域能鲁棒的定位,但是有累计的漂移。
    • 地图点匹配:对现存地图的无漂移的定位

    IV. EVALUATION

    对于kitti的01序列(高速公路场景)来说,平移的结果是比较不好的,原因就是能被追踪的近点太少了(汽车高速运动,而相机低帧率),但角度还是能估计的比较准。和单目相比,双目的效果更好,一是因为近点更好追踪,因为从一个双目关键帧就可以创建点,而不用像单目那样弄延迟的初始化(要在俩关键帧之间匹配),双目的情况更不容易出现track lost;二是双目可以带尺度的估计地图和轨迹,没有轨迹漂移。(可以明显看出左边图中,路程后段的尺度漂移)
    可以明显看出左边图中,路程后段的尺度漂移
    对于EuRoC数据集,由于严重的运动模糊会使track lost出现。论文提到的一个解决办法是使用imu信息,之前在github看到有人提到的一个解决办法是,把track lost部分的图像进行锐化的预处理(没有证实过是否有效)

    对于时效性。回环中关键帧的数量就可以对应出回环的耗时。关键帧越多,共视图就会越密集,回环的融合,位姿优化,全局BA也就会更加耗时。高密度的共视图会让局部地图包含更多关键帧和点,因此局部地图的追踪和局部BA会更耗时。

    展开全文
  • 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 相机标定 ...
  • Dense Bundle Adjustment Layer:首先, DBA层将更新模块输出的稠密光流场变化量转换为相机位姿和稠密深度值: 这里的相机位姿可以使用传统方法计算得到, 深度值则是根据下面的目标函数和舒尔补公式, 迭代优化的方式...

    点击上方“3D视觉工坊”,选择“星标”

    干货第一时间送达

    f361c3a82803e309c29d055efe6ccac6.png

    作者丨paopaoslam

    来源丨泡泡机器人SLAM

    标题:DROID-SLAM: Deep Visual SLAM for Monocular Stereo, and RGB-D Cameras

    作者:Zachary Teed, Jis Deng

    来源:arXiv 2021

    编译:方川 阮建源

    审核:张海晗

    大家好,今天给大家带来的Princeton VL的SLAM工作: DROID-SLAM: Deep Visual SLAM for Monocular Stereo, and RGB-D Cameras. 这篇工作把Visual-SLAM问题使用深度神经网络直接端到端地实现了,并且取得了比以往传统SLAM方案更高的精度和鲁棒性。

    d7a7bbef29fef4b5617d3b7d0390ade5.png

    摘要

    9161910d95ee599ba5b3727850dfeef5.png

        本文提出了DROID-SLAM, 一个全新的基于深度学习的SLAM系统. DROID-SLAM通过一个深度BA层来循环迭代的更新相机位姿和像素深度值. 实验证明, DROID-SLAM比传统SLAM取得了更高的精度和鲁棒性, 在实验场景中几乎不会失败. 尽管我们只在单目视频上训练了我们的网络, 但是在测试阶段,这个网络仍然可以在双目和RGB-D视频上取得很好的表现.代码开源在https://github.com/princeton-vl/DROID-SLAM.

    0911dab8bc912f01a7f7bb1705b801aa.png

    主要贡献

    fd4e6c213d862b9e102f12ac54c3adf9.png

    1, High Accuracy: 在TartanAir、ETH-3D、EuRoc、TUM-RGBD数据集上处于领先地位, 并且极大地超越原先方法;

    2, High Robustness: 非常稳定的跟踪能力, 除了ETH-3D, 其他数据集上没有出现fail情况;

    3, Strong Generalization: 虽然本文只使用单目视频训练, 但是在测试阶段直接使用双目视频和RGB-D作为输入, 仍然得到了很好的预测结果;

    9d0dcc496d48b20f1bae165ea7fdd5a6.png

    图,DROID-SLAM可以在单目、立体和RGB-D相机上运行。它构建了一个环境的稠密3D地图,同时在地图中定位相机。

    a782ff3ebbe4b703d81d1c164eaa9020.png

    算法流程

    e0a43a80a625f3346c2fa51e5f50cec6.png

    1. Notation

      算法的输入是一个视频或者图像序列I_t {t=0~N}每一张图像, 算法的目标是求解相机位姿 G_t和 逆深度d_t.  相机位姿序列 G_t {t=0~N}和逆深度序列d_t {t=0~N}是未知的的系统状态变量, 在输入的图像序列中迭代的更新最终收敛. 同时, 本文设计了一个frame-graph (V, E)结构表示图像之间的共视关系, 边(i,j) 表示 I_i 和 I_j之间存在共视关系. frame-graph随着位姿和深度的更新也会动态更新, 对于回环检测, 我们在frame-graph中添加长的回环边.

    2.特征提取和关联

        特征提取和关联这一部分与RAFT中的特征网络和相关信息张量correlation volume 完全一致.

    特征提取网络: feature network由6个残差模块和3个下采样层组成, 生成输入图像1/8分辨率的feature map; context network提取图像全局信息, 作为下文更新算子的一个输入;

    Correlation Pyramid: 对于frame-graph中的每条边(i,j), 本文使用点积计算一个4D的correlation volume:

    9753614b69a12d5e886877b5dcceee35.png

    Correlation Lookup: 根据像素坐标和查找半径r, 查找算子L_r会在不同分辨率的correlation volume上查找对应的相关信息张量,最后将他们拼接为一个feature vector;

    3.更新算子

    更新模块是本文网络的核心模块, 整体结构如下图所示:

    8bc300af2e46215f6be75aeb5700a1a9.png

    图2:更新操作的说明。算子作用于框架图中的边,预测流修正通过(DBA)层映射到深度和姿态更新。

    C_ij是图像I_i与I_j之间的相关信息张量,h_ij是隐藏状态. 每轮更新之后,  h_ij会被更新, 并且输出位姿变化和深度变化d^k, 然后更新下一帧的位姿和深度:

    d914c7d8905c7156958ff75636edfe23.png

    Correspondece: 在每次更新之前, 根据当前的pose和depth, 对于图像I_i中的每个网格, 网格中的像素坐标集合p_i , 那么它在图像 I_j上的对应网格像素集合p_ij可以表示为:

    59ee3aee968972bc4eeac73a97a15512.png

    Input: 根据上一步计算得到的grid correspondence, 查找两张图像的相关信息feature map C_ij;同时可以根据p_i和p_ij计算两张图像之间的光流场flow fileds. C_ij表征的是两张图像之间的视觉一致程度, 更新模块的目标是计算相对位姿来对齐两张图像使之一致性最大化. 但是因为视觉一致性会存在奇异, 因此我们同时利用光流场来提供位姿估计的鲁棒性.

    Update:与RAFT网络一样, correlation features 和 flow features经过两层卷积之后, 与context feature一同送入GRU模块. 在GRU模块中, 本文对隐藏状态h_ij作average pooling来提取global context, global context对于提高剧烈运动物体的光流估计鲁棒性有帮助.

    GRU模块同时更新隐藏状态得到 h^(k+1), 我们利用这个隐藏状态张量得到光流场的变化量 r_ij和对应的置信度 w_ij, 则修正后的网格p*_ij =  r_ij + p_ij. 再利用h^(k+1)得到pixel-wise的阻尼系数矩阵和 用于深度估计过程中的8x8的上采样mask;

    Dense Bundle Adjustment Layer:首先, DBA层将更新模块输出的稠密光流场变化量转换为相机位姿和稠密深度值: 这里的相机位姿可以使用传统方法计算得到, 深度值则是根据下面的目标函数和舒尔补公式, 迭代优化的方式得到的.

    36fec634ce559b9c214feaebf729109b.png

    这里仍然是使用Guass-Newton法计算位姿和深度的变化量, 利用舒尔补先计算位姿变化量d xi, 再计算深度变化量

    70bc43411ba7d3c51717abdebdada068.png

    v, w分别代表相机位姿和深度的梯度方向.

    DBA 层的实现和反向传播是基于LieTorch的, 是一个李群李代数的pytorch实现的package.

    4,训练过程

    单目尺度问题: 为了解决单目SLAM尺度问题, 我们把前两帧图像位姿固定为ground truth.

    采样视频/图像序列: 为了是我们的网络泛化能力更好, 我们通过计算图像序列中任意两张图像之间的光流场距离, 对这样的N_i * N_i flow distance matrix进行采样,得到采样后的心得图像序列形成的视频来输入网络进行训练.

    监督和loss: 监督信息是ground truth pose和ground truth flow. 光流程loss是 网络预测的flow fileds与ground truth flow fileds的L_2 loss. 图像位姿loss则是

    73bdfe3bfb5c088d6a987cd743d33537.png

    5, SLAM system

        和以前的SLAM系统一样, 本文方法实现的SLAM系统也包括前端和后端两个线程. 前端线程提取特征、选取关键帧、局部优化. 后端线程对所有关键帧进行全局优化.

    初始化:  选择视频中前部的12帧图像来完成初始化, 相邻两帧图像之间的光流必须大雨16px, 12帧图像集齐后, 我们建立起一个frame-graph, 并且运行10次更新算子的迭代.

    视觉前端: 前端部分选取并维护着关键帧序列. 新的图像到来时, 进行特征提取、计算光流场, 并根据光流场计算3个与之共视程度最大的关键帧, 然后根据共视关系来迭代更新当前关键帧的pose和depth. 同时, 前端部分也负责边缘化操作.

    后端优化: 后端部分将所有关键帧进行BA优化. 每次进行更新迭代时,都会对所有关键帧重新构建frame-graph, 这是根据所有关键帧之间的光流场距离矩阵N * N来构建的. 接着在frame-graph上运行更新算子, 在BA缓解我们使用的是LieTorch. 后端网络只在关键帧上运行BA优化, 对于视频中的普通帧, 只优化相机pose.

    Stereo and RGB-D:为了使我们设计的这个SLAM系统能够很好的应用到双目和RGB-D的场景中, 我们会在Stereo和RGB-D的情景中对公式(4)做一些修改. 比如在RGB-D场景中, 公式4添加一个残差项: 估计的depth map与测量的depth map之间的距离平方和. 在Stereo场景中, 公式4改为左右两个相机的位姿重投影误差.

    e54728781f6618ba7f7f78c8da6cf45f.png

    图3,DROID-SLAM可以推广到新的数据集。因此,我们展示了Tanks&Temples [21], ScanNet [10], Sintel [3], ETH-3D [42];全部使用单目相机。

    bd43d55e9721157b5e90a04936cee2ac.png

    主要结果

    3e6cafe77d1313ea745c505dbfc10fde.png

        本文提出的方法在多个数据集上进行了充分的实验, 并且和其他深度学习方法以及经典的SLAM算法做了比较. 实验部分着重比较了相机轨迹的绝对轨迹误差ATE.

        本文中的网络在合成的数据集TartanAir上面训练了250k次, 图像分辨率为384x512, 在4块 RTX-3090上训练了1周时间.

    7f078e04af7264fa2731c44f7343b702.png

    表1:TartanAir单目基准测试的结果。

    05dc4847f99524da225581ebbbd3c36f.png

    表2:TartanAir双目基准测试的结果。

    fb5ce3fe4f02595ae47117eb4ebf83de.png

    表3:TartanAir测试集的结果,与ECCV 2020 SLAM竞赛的前3名SLAM相比。使用归一化相对姿态误差计算所有可能的分数

    长度为f5的序列;10;15...40g米,详见比赛页面。

        在EuRoc和TUM-RGB-D数据集上也做了充分的实验, 实验正面,本文网络可以很好的泛化到Stereo和RGB-D上,同时取得很高的精度和鲁棒性.

    5b03f6b91ba7bee63c8fabbbea29f58a.png

    表4:基于EuRoC数据集的单目SLAM, ATE[m]。+表示视觉里程计方法。

    b3138a79c422c25a0757a1b814115c7f.png

    表5:基于EuRoC数据集的双目SLAM, ATE[m]。

    5575836e196d7896a719753fe2c2ff8f.png

    表6:TUM-RGBD基准上的ATE。所有方法都使用单目视频,除了DeepTA 使用RGB-D和TartanVO使用地面真实来缩放相对姿态。

    74c60bca50956825e8ac26452deb08b5.png

    图4:RGB-D ETH3D-SLAM基准的总体结果。(左)我们的方法, 它只在合成的TartanAir数据集上训练,在训练和测试分割中都排名第一。(右)将成功轨迹数作为ATE的函数绘制出来。我们的方法成功跟踪30/32的图像数据可用的数据集。

    bf6959533ca680ae0b2ff64c8fd995bc.png

    图5:关键帧图像的可视化、深度、光流和置信度估计。

    c538ba9d2e99569c41af87bf9bf3498d.png

    图6:(左)我们展示了不同输入(单目和双目)的系统性能以及是否在局部BA之外执行全局优化(局部vs.完全)。(右)跟踪精度和关键帧数量的关系。我们在实验中使用了5个关键帧(粗体)。

    5cdd8e31c65d1455551ceb150cf10ab7.png

    图7:(左)更新操作对全局上下文的影响。(右)使用BA的影响在训练时使用BA层vs直接在管流上训练,然后在测试时使用BA

    Abstract 

    We introduce DROID-SLAM, a new deep learning based SLAM system. DROIDSLAM consists of recurrent iterative updates of camera pose and pixelwise depththrough a Dense Bundle Adjustment layer. DROID-SLAM is accurate, achievinglarge improvements over prior work, and robust, suffering from substantially fewercatastrophic failures. Despite training on monocular video, it can leverage stereoor RGB-D video to achieve improved performance at test time. The URL to ouropen source code is https://github.com/princeton-vl/DROID-SLAM.

    点击阅读原文,即可获取本文下载链接。提取码:n575

    本文仅做学术分享,如有侵权,请联系删文。

    3D视觉精品课程推荐:

    1.面向自动驾驶领域的多传感器数据融合技术

    2.面向自动驾驶领域的3D点云目标检测全栈学习路线!(单模态+多模态/数据+代码)
    3.彻底搞透视觉三维重建:原理剖析、代码讲解、及优化改进
    4.国内首个面向工业级实战的点云处理课程
    5.激光-视觉-IMU-GPS融合SLAM算法梳理和代码讲解
    6.彻底搞懂视觉-惯性SLAM:基于VINS-Fusion正式开课啦
    7.彻底搞懂基于LOAM框架的3D激光SLAM: 源码剖析到算法优化
    8.彻底剖析室内、室外激光SLAM关键算法原理、代码和实战(cartographer+LOAM +LIO-SAM)

    9.从零搭建一套结构光3D重建系统[理论+源码+实践]

    10.单目深度估计方法:算法梳理与代码实现

    重磅!3DCVer-学术论文写作投稿 交流群已成立

    扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

    同时也可申请加入我们的细分方向交流群,目前主要有3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、多传感器融合、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流、ORB-SLAM系列源码交流、深度估计等微信群。

    一定要备注:研究方向+学校/公司+昵称,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,可快速被通过且邀请进群。原创投稿也请联系。

    b3c9cc93f5436be0bc6afdcebdd710c5.png

    ▲长按加微信群或投稿

    d711c77fbeec0d154f83eda04a5eebf1.png

    ▲长按关注公众号

    3D视觉从入门到精通知识星球:针对3D视觉领域的视频课程(三维重建系列三维点云系列结构光系列手眼标定相机标定激光/视觉SLAM自动驾驶等)、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答五个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近4000星球成员为创造更好的AI世界共同进步,知识星球入口:

    学习3D视觉核心技术,扫描查看介绍,3天内无条件退款

    51ed91f375010ac4ba58b3034d5ce0f3.png

     圈里有高质量教程资料、答疑解惑、助你高效解决问题

    觉得有用,麻烦给个赞和在看~  

    展开全文
  • 3、ORB_SLAM2利用gazebo仿真环境跑双目仿真 双目仿真使用的是stereo插件,相比于单目要复杂一点,主要参考于: https://www.jianshu.com/p/811e24e8965a 首先需要修改相机参数,双目相机参数如下: <!-- stereo ...

    1、ORB_SLAM2利用笔记本摄像头跑单目

    1、下载usb_cam源码并配置环境:

    cd catkin_ws/src
    git clone https://github.com/bosch-ros-pkg/usb_cam.git
    cd ..
    ctakin_make
    

    注意这里我的catkin_ws是之前编译过的,如果使用未编译的文件夹首次编译后需要添加source路径,在前面很多篇中都提到,不赘述。

    2、测试摄像头

    roslaunch usb_cam usb_cam-test.launch
    

    正常情况下是能够显示摄像头图像的,如果没有的话要思考前面的编译过程是否有问题。应该来说没什么问题。

    3、用ORB-SLAM2实时跑数据

    $ rosrun ORB_SLAM2 Mono /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Vocabulary/ORBvoc.txt /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/Monocular/TUM1.yaml    
           
    

    (即 rosrun ORB-SLAN2 Mono ORBvoc.txt路径 TUM1.yaml路径)
    在这里插入图片描述
    这里的

    /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/Monocular/TUM1.yaml
    

    似乎应该是相机内参,在:

    /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/Asus.yaml  
    

    路径下也有一个对应的可运行的参数文件,所以这里如果执行:

    rosrun ORB_SLAM2 Mono /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Vocabulary/ORBvoc.txt /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/Asus.yaml  
    

    同样也是可以运行的。
    在这里插入图片描述

    另外这里还有一个小问题:

    如果运行ORB_SLAM2之后图像显示不出来,可能是因为topic的问题,这时候可以查看发布的topic以及订阅的topic是否相同。gazebo插件中发布的topic可以使用:

    rostopic list
    

    命令查看,一般usb摄像头发布的图像格式应该是:usb_cam/image_raw
    而我们订阅的程序在:catkin/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/src路径下的ros_mono.cc文件中,可以看到它的ros::subscriber一般初始化为:camera/image_raw。这里将其修改为上面的topic即可。

    2、ORB_SLAM2利用gazebo仿真环境跑单目仿真

    关于仿真环境的建立,具体可以参考之前写的:ROS学习总结十:Gazebo物理仿真环境搭建,这里就不赘述了。

    例如下面的是我随手建立的一个gazebo仿真环境(中间蓝色的是我的机器人):
    在这里插入图片描述
    然后使用三个终端分别打开下面的命令:

    $ roscore
    $ roslaunch mbot_gazebo view_mbot_with_camera_gazebo.launch
    $ rosrun ORB_SLAM2 Mono /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Vocabulary/ORBvoc.txt /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/Monocular/TUM1.yaml 
    

    注意这里中间的:

    $ roslaunch mbot_gazebo view_mbot_with_camera_gazebo.launch
    

    为我的gazebo启动程序,不一定相同,根据自己的路径设定。

    另外注意image的rostopic与ORB_SLAM2中订阅的topic问题。

    正常来说这时候就可以运行了,我们看一下效果:

    在这里插入图片描述
    嗯。。。效果不怎么样,发现在gazebo仿真中的特征点非常少,虽然我给了很多的特征了但是不知道为什么并没有被识别。

    于是我又改用了另一个参数运行:

    rosrun ORB_SLAM2 Mono /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Vocabulary/ORBvoc.txt /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2/Asus.yaml  
    

    得到新的效果:

    在这里插入图片描述
    虽然效果比第一个好,但是特征跟使用笔记本摄像头相比差的真不是一点半点。

    原本以为是gazebo仿真环境的问题,但是后来参考了一篇博客才发现应该还是参数的问题,在该博客中给出了另一种参数配置:

    https://www.freesion.com/article/6807208904/
    

    就是将原来TUM3.yaml中的参数:

    # Camera calibration and distortion parameters (OpenCV) 
    Camera.fx: 535.4
    Camera.fy: 539.2
    Camera.cx: 320.1
    Camera.cy: 247.6
    
    Camera.k1: 0.0
    Camera.k2: 0.0
    Camera.p1: 0.0
    Camera.p2: 0.0
    
    # Camera frames per second 
    Camera.fps: 30.0
    
    # Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
    Camera.RGB: 1
    

    改成新的:

    # Camera calibration and distortion parameters (OpenCV) 
    Camera.fx: 277.19135641132203
    Camera.fy: 277.19135641132203
    Camera.cx: 160.5
    Camera.cy: 120.5
    
    Camera.k1: 0.0
    Camera.k2: 0.0
    Camera.p1: 0.0
    Camera.p2: 0.0
    
    Camera.width: 320
    Camera.height: 240
    
    # Camera frames per second 
    Camera.fps: 50.0
    
    # Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
    Camera.RGB: 1
    

    为了保险起见最好重命名一个TUM4.yaml。

    重新运行以后特征提取上确实好了很多:
    在这里插入图片描述
    但是似乎特征点数量还是不太够,最终我绕着跑了一圈都没有初始化成功:
    在这里插入图片描述
    于是我使用了ROS-Academy-for-Beginners功能包,这个可以直接在GitHub上下载编译,编译过程与其他ROS功能包相同,中间可能会提示缺少几个依赖项,使用sudo apt-get install 安装即可

    编译后通过运行:

    $ roslaunch robot_sim_demo robot_spawn.launch
    

    打开gazebo环境,然后运行:

    $ rosrun ORB_SLAM2 Mono /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Vocabulary/ORBvoc.txt /home/zhangxingsheng/catkin_ws/src/ORB_SLAM2/Examples/Monocular/TUM4.yaml
    

    可以看到新运行的环境比之前的环境中多了很多的特征点。

    启动键盘节点运动小车初始化相机:

    $ roslaunch mbot_teleop mbot_teleop.launch
    

    在这里遇到了单目调试过程中最大的一个坑:
    每次我初始化结束后,下面map viewer上有位姿之后程序立马闪退:
    在这里插入图片描述
    就到这里然后报错:
    在这里插入图片描述
    吐槽一下:

    segmentation fault(core dumped)真的是难搞

    花了三天各种找原因,试了一万种方法,差点崩溃,最后在这里:

    https://blog.csdn.net/qq_43525260/article/details/104378643?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
    

    找到了解决方法。

    只是cmake.list文件中多出的一个-march=native导致了程序各种bomb。关于-march=native,百度了一个解释是:-march=[native]选项:gcc/g++编译器通过-march指定cpu架构,指定该选项之后编译器将不会生成兼容的指令集,而是该架构支持的特定指令集,可以取得一部分优化的效果。特殊地,-march=native选项让编译器获取当前机器的cpu架构,并生成该架构的最优指令,达到优化指令集的目的。不是很能理解。

    最终我通过将:

    ORB_SLAM2/Thirdparty/DBoW2/CMakeLists.txt
    ORB_SLAM2/Examples/ROS/ORB_SLAM2/CMakeLists.txt
    ORB_SLAM2/CMakeLists.txt
    ORB_SLAM2/Thirdparty/g2o/CMakeLists.txt
    

    中的-march=native全部删除后,按照之前的编译方式重新全部编译一次以后,终于可以正常运行了。

    注意不只是要运行:

    ./build_ros.sh
    

    需要把前面的g2o以及DBoW2等包都要重新编译一遍,具体的翻看上一篇博客的编译过程。不赘述。

    然后看一下效果:

    在这里插入图片描述
    总体来说其实还行,但是似乎对于自身的定位是有点差的:

    例如当我绕场景跑完一圈以后得到的图像:

    在这里插入图片描述
    这起点与终点差的不是一点半点。

    不过幸好似乎有个回环检测,总算把自己给圆回去了:
    在这里插入图片描述
    这张看起来还有点样子,不过单纯从自定位的角度来说单目的效果真的不太好。

    3、ORB_SLAM2利用gazebo仿真环境跑双目仿真

    双目仿真使用的是stereo插件,相比于单目要复杂一点,主要参考于:

    https://www.jianshu.com/p/811e24e8965a
    

    首先需要修改相机参数,双目相机参数如下:

    <!-- stereo camera -->
      <gazebo reference="camera_link">
          <sensor type="multicamera" name="stereo_camera">
            <update_rate>30.0</update_rate>
            <camera name="left">
              <horizontal_fov>1.3962634</horizontal_fov>
              <image>
                <width>800</width>
                <height>800</height>
                <format>R8G8B8</format>
              </image>
              <clip>
                <near>0.02</near>
                <far>300</far>
              </clip>
              <noise>
                <type>gaussian</type>
                <mean>0.0</mean>
                <stddev>0.007</stddev>
              </noise>
            </camera>
            <camera name="right">
              <pose>0 -0.07 0 0 0 0</pose>
              <horizontal_fov>1.3962634</horizontal_fov>
              <image>
                <width>800</width>
                <height>800</height>
                <format>R8G8B8</format>
              </image>
              <clip>
                <near>0.02</near>
                <far>300</far>
              </clip>
              <noise>
                <type>gaussian</type>
                <mean>0.0</mean>
                <stddev>0.007</stddev>
              </noise>
            </camera>
            <plugin name="stereo_camera_controller" filename="libgazebo_ros_multicamera.so">
              <alwaysOn>true</alwaysOn>
              <updateRate>0.0</updateRate>
              <cameraName>camera</cameraName>
              <imageTopicName>image_raw</imageTopicName>
              <cameraInfoTopicName>camera_info</cameraInfoTopicName>
              <frameName>camera_link</frameName>
              <hackBaseline>0.07</hackBaseline>
              <distortionK1>0.0</distortionK1>
              <distortionK2>0.0</distortionK2>
              <distortionK3>0.0</distortionK3>
              <distortionT1>0.0</distortionT1>
              <distortionT2>0.0</distortionT2>
            </plugin>
          </sensor>
        </gazebo>
    

    建议新建一个模型,复制原来的参数过来以后替换掉相机的部分,这样在保留原来的模型的基础上修改更少。

    然后再给一个相机配置文件:

    %YAML:1.0
    
    #--------------------------------------------------------------------------------------------
    # Camera Parameters. Adjust them!
    #--------------------------------------------------------------------------------------------
    
    # Camera calibration and distortion parameters (OpenCV) 
    Camera.fx: 277.19135641132203
    Camera.fy: 277.19135641132203
    Camera.cx: 160.5
    Camera.cy: 120.5
    
    Camera.k1: 0.0
    Camera.k2: 0.0
    Camera.k3: 0.0
    Camera.p1: 0.0
    Camera.p2: 0.0
    
    Camera.width: 752
    Camera.height: 480
    
    # Camera frames per second 
    Camera.fps: 20.0
    
    # stereo baseline times fx
    Camera.bf: 47.90639384423901
    
    # Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
    Camera.RGB: 1
    
    # Close/Far threshold. Baseline times.
    ThDepth: 35
    
    #--------------------------------------------------------------------------------------------
    # Stereo Rectification. Only if you need to pre-rectify the images.
    # Camera.fx, .fy, etc must be the same as in LEFT.P
    #--------------------------------------------------------------------------------------------
    LEFT.height: 480
    LEFT.width: 752
    LEFT.D: !!opencv-matrix
       rows: 1
       cols: 5
       dt: d
       data:[-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05, 0.0]
    LEFT.K: !!opencv-matrix
       rows: 3
       cols: 3
       dt: d
       data: [458.654, 0.0, 367.215, 0.0, 457.296, 248.375, 0.0, 0.0, 1.0]
    LEFT.R:  !!opencv-matrix
       rows: 3
       cols: 3
       dt: d
       data: [0.999966347530033, -0.001422739138722922, 0.008079580483432283, 0.001365741834644127, 0.9999741760894847, 0.007055629199258132, -0.008089410156878961, -0.007044357138835809, 0.9999424675829176]
    LEFT.P:  !!opencv-matrix
       rows: 3
       cols: 4
       dt: d
       data: [435.2046959714599, 0, 367.4517211914062, 0,  0, 435.2046959714599, 252.2008514404297, 0,  0, 0, 1, 0]
    
    RIGHT.height: 480
    RIGHT.width: 752
    RIGHT.D: !!opencv-matrix
       rows: 1
       cols: 5
       dt: d
       data:[-0.28368365, 0.07451284, -0.00010473, -3.555907e-05, 0.0]
    RIGHT.K: !!opencv-matrix
       rows: 3
       cols: 3
       dt: d
       data: [457.587, 0.0, 379.999, 0.0, 456.134, 255.238, 0.0, 0.0, 1]
    RIGHT.R:  !!opencv-matrix
       rows: 3
       cols: 3
       dt: d
       data: [0.9999633526194376, -0.003625811871560086, 0.007755443660172947, 0.003680398547259526, 0.9999684752771629, -0.007035845251224894, -0.007729688520722713, 0.007064130529506649, 0.999945173484644]
    RIGHT.P:  !!opencv-matrix
       rows: 3
       cols: 4
       dt: d
       data: [435.2046959714599, 0, 367.4517211914062, -47.90639384423901, 0, 435.2046959714599, 252.2008514404297, 0, 0, 0, 1, 0]
    
    #--------------------------------------------------------------------------------------------
    # ORB Parameters
    #--------------------------------------------------------------------------------------------
    
    # ORB Extractor: Number of features per image
    ORBextractor.nFeatures: 1200
    
    # ORB Extractor: Scale factor between levels in the scale pyramid   
    ORBextractor.scaleFactor: 1.2
    
    # ORB Extractor: Number of levels in the scale pyramid  
    ORBextractor.nLevels: 8
    
    # ORB Extractor: Fast threshold
    # Image is divided in a grid. At each cell FAST are extracted imposing a minimum response.
    # Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST
    # You can lower these values if your images have low contrast           
    ORBextractor.iniThFAST: 20
    ORBextractor.minThFAST: 7
    
    #--------------------------------------------------------------------------------------------
    # Viewer Parameters
    #--------------------------------------------------------------------------------------------
    Viewer.KeyFrameSize: 0.05
    Viewer.KeyFrameLineWidth: 1
    Viewer.GraphLineWidth: 0.9
    Viewer.PointSize:2
    Viewer.CameraSize: 0.08
    Viewer.CameraLineWidth: 3
    Viewer.ViewpointX: 0
    Viewer.ViewpointY: -0.7
    Viewer.ViewpointZ: -1.8
    Viewer.ViewpointF: 500
    

    编写launch文件:
    orbslam2_stereo.launch:

    <launch>
        <arg name="PATH_TO_VOCABULARY" value="$(find ORB_SLAM2)/vocabulary_files/ORBvoc.txt"/>
        <arg name="PATH_TO_SETTINGS_FILE" value="$(find ORB_SLAM2)/setting_files/Stereo_setting.yaml"/>
        
        <node name="Stereo" pkg="ORB_SLAM2" type="Stereo" args="$(arg PATH_TO_VOCABULARY) $(arg PATH_TO_SETTINGS_FILE) false">
        </node>
    
    </launch>
    

    在这里要说明一下ORB_SLAM2的节点启动,最后有一个false,是代表是否需要双目校正,在这里填ture的话,反而会出现严重的畸变,因此推测,仿真出来的相机镜头是不需要标定和校正的。

    启动命令:

    roslaunch ORB_SLAM2 orbslam2_stereo.launch
    

    这里的ORB_SLAM2是上面launch文件的一级路径,这里在我使用这个roslaunch的时候会出现参数文件找不到的问题,是因为它对应这里的ORB_SLAM2是指的catkin_ws/src/ORB_SLAM2/Examples/ROS/ORB_SLAM2路径,而我们前面的参数文件是以catkin_ws/src/ORB_SLAM2作为路径的,简单点的方法就是将前面的参数以这个路径重新保存一份,只保存其中的vox.txt以及yaml文件即可。

    运行结果:
    在这里插入图片描述

    在这里插入图片描述
    可以看到在我快走完一圈的时候,整个位姿的偏差其实还是非常大的,跟单目的效果感觉差不多

    最后也是靠一个回环检测拯救了过来:

    在这里插入图片描述

    4、ORB_SLAM2利用gazebo仿真环境跑RGBD仿真

    同样的修改一下相机模型参数:

      <!-- camera -->
        <gazebo reference="camera_link">  
          <sensor type="depth" name="camera">
            <always_on>true</always_on>
            <update_rate>20.0</update_rate>
            <camera>
              <horizontal_fov>${60.0*3.14/180.0}</horizontal_fov>
              <image>
                  <format>R8G8B8</format>
                  <width>640</width>
                  <height>480</height>
              </image>
              <clip>
                  <near>0.05</near>
                  <far>8.0</far>
              </clip>
            </camera>
            <plugin name="kinect_camera_controller" filename="libgazebo_ros_openni_kinect.so">
              <cameraName>camera</cameraName>
              <alwaysOn>true</alwaysOn>
              <updateRate>10</updateRate>
              <imageTopicName>rgb/image_raw</imageTopicName>
              <depthImageTopicName>depth/image_raw</depthImageTopicName>
              <pointCloudTopicName>depth/points</pointCloudTopicName>
              <cameraInfoTopicName>rgb/camera_info</cameraInfoTopicName>
              <depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
              <frameName>camera_frame_optical</frameName>
              <baseline>0.1</baseline>
              <distortion_k1>0.0</distortion_k1>
              <distortion_k2>0.0</distortion_k2>
              <distortion_k3>0.0</distortion_k3>
              <distortion_t1>0.0</distortion_t1>
              <distortion_t2>0.0</distortion_t2>
              <pointCloudCutoff>0.4</pointCloudCutoff>
            </plugin>
          </sensor>
        </gazebo>
    

    这里我重新复制了ROS-Academy-for-Beginners功能包下的ros_sim_demo/xbot-ugazebo,重命名xbot_kinect,这个里面本身使用的是双目相机,然后将相机参数部分修改掉。注意修改robot.xacro文件中的模型名字,因为launch文件调用的是robot.xacro文件。

    launch文件可以不用写,因为在ROS-Academy-for-Beginners功能包下的orbslam2_demo下有一个对应的launch文件,打开看一下我们可以知道它是一个对应的RGBD相机的launch文件,可以直接使用这个launch文件。

    <launch>
        <arg name="PATH_TO_VOCABULARY" value="$(find ORB_SLAM2)/../../../Vocabulary/ORBvoc.txt"/>
        <arg name="PATH_TO_SETTINGS_FILE" value="$(find orbslam2_demo)/param/Zdzn.yaml "/>
        
        <node name="RGBD" pkg="ORB_SLAM2" type="RGBD" args="$(arg PATH_TO_VOCABULARY) $(arg PATH_TO_SETTINGS_FILE)"/>
       	 <remap from="/camera/depth_registered/image_raw" to="/camera/depth/image_raw"/>
    </launch>
    

    然后我们分别运行下列命令:

    $ roscore
    $ roslaunch robot_sim_demo robot_spawn.launch
    $ roslaunch orbslam2_demo ros_orbslam2.launch
    $ roslaunch mbot_teleop mbot_teleop.launch
    

    最终我们运行得到:

    这是快走完一圈时的路径:

    在这里插入图片描述
    这是走完一圈回环检测后的路径:

    在这里插入图片描述
    只能疯狂赞扬一下ORB_SLAM2的回环检测是真的强大,每次跑到天上去都能通过回环检测圆回来是真的可以。

    但是这个前端位置检测真的一言难尽,不知道是不是我相机参数的问题,有知道的小伙伴可以评论告知一下。

    展开全文
  • 深度/RGBD相机简介

    万次阅读 多人点赞 2019-12-11 10:33:40
    深度相机RGBD相机的区别?为何经常概念混淆? 什么是深度图? 什么是深度/RGB-D相机(有什么关系?)? RGB-D相机原理简介 结构光 飞行时间 RGB-D相机有哪些坑? RGB-D相机优点 RGB-D相机应用 深度图...

    深度相机与RGBD相机的区别?为何经常概念混淆?

    • 什么是深度图?
    • 什么是深度/RGB-D相机(有什么关系?)?
    • RGB-D相机原理简介
    1. 结构光
    2. 飞行时间
    • RGB-D相机有哪些坑?
    • RGB-D相机优点
    • RGB-D相机应用

    深度图一般是16位的

    单目结构光?双目结构光?

    单目结构光 有一个红外发射器和一个红外接收器

    双目结构光 有一个红外发射器和两个红外接收器

    RGB-D相机有哪些坑

    理解一下这里的视差~这个影响比较小。基线越大影响越明显,同时越远越明显。

    RGB-D相机的优点:

    RGB-D相机的应用?

     

    展开全文
  • 目前,视觉SLAM(SLAM是“Simultaneous Localization And Mapping”的缩写,可译为同步定位与建图)可分为单目、双目(多目)、RGBD这三类,另还有鱼眼、全景等特殊相机,但目前在研究和产品中还属于少数。从实现难度...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,193
精华内容 477
关键字:

双目相机rgbd