LSD_SLAM代码笔记

Lsd_slam的主函数位于main_live_odometry.cpp中,其中主要的SLAM功能由slamNode.Loop();执行。Slam.Loop()主要为一个读取新图像并处理的死循环,由newImageCallback处理图像。newImageCallback执行slam的随机初始化和图像跟踪。1 随机初始化随机初始化函数为SlamSystem::randomInit1.1 ...
摘要由CSDN通过智能技术生成

Lsd_slam的主函数位于main_live_odometry.cpp中,其中主要的SLAM功能由slamNode.Loop();执行。

Slam.Loop()主要为一个读取新图像并处理的死循环,由newImageCallback处理图像。

newImageCallback执行slam的随机初始化和图像跟踪。

1 随机初始化

随机初始化函数为SlamSystem::randomInit

1.1 currentKeyFrame设置为当前图像的Frame

1.1.1 Frame类及其创建(构造函数)

Frame类中主要用来存储数据的类是Data类,Data类中保存了id、内参金字塔、图像金字塔、梯度图像金字塔、像素点深度金字塔、像素点逆深度方差金字塔等信息。

当用构造函数创建一个新的Frame类时,首先给data一个新的id,然后初始化Data类中的内参金字塔数据,然后对其他数据进行对应的初始化,再然后对图像金字塔赋值,不过只赋值金字塔的第0层。

Frame创建完后赋给currentKeyFrame。

1.2 DepthMap初始化

主要函数为DepthMap::initializeRandomly(Frame* new_frame)

首先复制了new_frame中的一些指针:互斥锁、new_frame、图像数据、和一个标志位activeKeyFrameIsReactivated。

计算图像梯度并且根据图像梯度给currentDepthMap赋初始值,并且将传进来的new_frame的深度设置为currentDepthMap中的值(Frame::setDepth)。

Frame::setDepth主要是对data.idepth[0],和data.idepthVar进行了内参分配和赋值。

再把当前帧添加到keyFrameGraph中。

2 图像跟踪

首先根据新的图像创建一个Frame类trackingNewFrame,跟踪的主要算法位于

SE3 SE3Tracker::trackFrame(
		TrackingReference* reference,
		Frame* frame,
		const SE3& frameToReference_initialEstimate)

reference为最近的一个KeyFrame,frame是当前帧,frameToReference_initialEstimate是初始值。整个跟踪过程从最高层的图像金字塔(也就是图像尺寸最小的那一层)开始计算,一直往下迭代到第一层。
论文中采用了最小化归一化方差的光度误差:
(1) E p ( ξ j i ) = ∑ p ∈ Ω D i ∥ r p 2 ( p , ξ j i ) σ r p ( p , ξ j i ) 2 ∥ δ E_p(\xi_{ji})=\sum_{\textbf p\in \Omega_{D_i}}\lVert\frac{r_p^2(\textbf p,\xi_{ji})}{\sigma_{r_p(\textbf p,\xi_{ji})}^2}\rVert_{\delta} \tag{1} Ep(ξji)=pΩDiσrp(p,ξji)2rp2(p,ξji)δ(1)
(2) r p ( p , ξ j i ) = I i ( p ) − I j ( ω ( p , D i ( p ) , ξ j i ) ) \\r_p(\textbf p,\xi_{ji})=I_i(\textbf p)-I_j(\omega(\textbf p,D_i(\textbf p),\xi_{ji})) \tag{2} rp(p,ξji)=Ii(p)Ij(ω(p,Di(p),ξji))(2)
(3) σ r p ( p , ξ j i ) 2 = 2 σ I 2 + ( ∂ r p ( p , ξ j i ) ∂ D i ( p ) ) 2 V i ( p ) \sigma_{r_p(\textbf p,\xi_{ji})}^2=2\sigma_I^2+(\frac{\partial r_p(\textbf p,\xi_{ji})}{\partial D_i(\textbf p)})^2V_i(\textbf p) \tag{3} σrp(p,ξji)2=2σI2+(Di(p)rp(p,ξji))2Vi(p)(3)
对于每层图像金字塔,计算参考帧到当前帧的相对位姿,主要由以下步骤构成。

2.1 参考帧创建点云

reference->makePointCloud(lvl);

该函数主要用于计算参考帧中有效点在参考帧坐标系下的3D位置,参考帧有效点的像素值和方差,保存对应有效点的位置索引,有效点个数。这些参数是下一步计算残差需要的。

2.2 计算残差和梯度

float SE3Tracker::calcResidualAndBuffers(
		const Eigen::Vector3f* refPoint,
		const Eigen::Vector2f* refColVar,
		int* idxBuf,
		int refNum,
		Frame* frame,
		const Sophus::SE3f& referenceToFrame,
		int level,
		bool plotResidual)

计算残差时首先将参考帧坐标系下的3D点转换到当前帧坐标系,再通过差值计算点在当前帧的像素值和梯度。然后跟当前帧对应的像素作差得到残差,也就是公式(2)对应的残差。

每个残差都会有一个权重,按以下代码计算:

float weight = fabsf(residual) < 5.0f ? 1 : 5.0f / fabsf(residual);

计算梯度时把插值出来的梯度乘以当前层焦距。

该函数最终返回没有乘以权重的平均残差。

2.3 计算归一化残差

float SE3Tracker::calcWeightsAndResidual(
		const Sophus::SE3f& referenceToFrame)

该函数的功能是计算归一化方差的光度误差系数,也就是计算公式(3),并且乘以了Huber-weight,最终把这个系数存在数组buf_weight_p中。 接下来我们看具体实现。可能是考虑参考帧到当前帧的位姿变换比较小,所以作者只考虑了位移t而忽略旋转R。这样使得式子(3)中的偏导的形式简单了很多。

忽略旋转后,路标点在参考帧坐标系下和当前帧坐标系下的坐标满足以下公式:
(4) ( x ′ y ′ z ′ ) = ( p x / d p y / d 1 / d ) + ( t x t y t z ) \begin{pmatrix} x&#x27;\\ y&#x27;\\ z&#x27; \end{pmatrix}= \begin{pmatrix} \textbf p_x/d\\ \textbf p_y/d\\ 1/d \end{pmatrix}+ \begin{pmatrix} t_x\\ t_y\\ t_z \end{pmatrix} \tag{4} xyz=px/dpy/d1/d+txtytz(4)
整理一下得到归一化坐标:
(5) ω ( p , D i ( p ) , ξ ) = ( p x / d + t x 1 / d + t z p y / d + t y 1 / d + t z 1 ) \omega(\textbf p, D_i(\textbf p),\xi)= \begin{pmatrix} \frac{\textbf p_x/d+t_x}{1/d+t_z}\\ \frac{\textbf p_y/d+t_y}{1/d+t_z}\\ 1 \end{pmatrix} \tag{5} ω(p,Di(p),ξ)=1/d+tzpx/d+tx1/d+tzpy/d+ty1(5)
然后就可以把(3)中的偏导表示出来:
(6) ∂ r p ( p , ξ j i ) ∂ D i ( p ) = ∂ ( I i ( p ) − I j ( ω ( p , D i ( p ) , ξ j i ) ) ) ∂ D i ( p ) = − ∂ I j ( a ) ∂ a ∣ a = p ⋅ ∂ ω ( d ) ∂ d ∣ d = D i ( p ) = − ( d x f x d y f y ) ⋅ ( t x ( 1 / d + t z ) − t z ( p x / d + t x ) ( 1 / d + t z ) 2 d t y ( 1 / d + t z ) − t z ( p y / d + t y ) ( 1 / d + t z ) 2 d ) = − ( d x f x t x z ′ − t z x ′ z ′ 2 d + d y f y t y z ′ − t z y ′ z ′ 2 d ) \frac{\partial r_p(\textbf p,\xi_{ji})}{\partial D_i(\textbf p)}= \frac{\par

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值