DSO学习笔记总集

一、概述

阅读完DSO项目一小部分,我觉得是时候写一个总集篇了,原因当然不是时间经费什么的,只是想回顾一下,免得又忘记。

二、makeImages

一大堆变量初始化以后,程序会运行到makeImages(HessianBlocks.cpp)。这时DSO会为图像生成金字塔。

过程:
(1)setGlobalCalibration(DatasetReader.h)确定图像金字塔层数,最大层数设为6;
(2)getImage(DatasetReader.h)读入图像,并且用memcpy()保存为数组;
(3)当前层像素由上一层4个像素取平均值得到,存入当前层三维数组第一维;
(4)当前层梯度由当前层像素计算,存入当前层三维数组第二维和第三维;
结果:
在这里插入图片描述

三、setfirst

DSO生成金字塔后,检测到当前帧是初始化的第一帧,则执行setfirst(CoarseInitializer.cpp)。
过程:

3.1 makeK

makeK计算金字塔各层的内参矩阵;

3.2 makeMaps

遍历金字塔,对第0层调用makeMaps提取特征像素:
(a)makeHists(PixelSelector2.cpp)将图像分为小块,块尺寸 32 × 32 32 \times 32 32×32,为小块计算梯度直方图,选择中位数梯度作为块梯度阈值, 3 × 3 3 \times 3 3×3个小块求平均值进行梯度平滑;
(b)select(PixelSelector2.cpp)在16个对应方向上随机选择一个,计算当前像素在对应方向上的投影,投影长度大于阈值,记录像素位置;
(c) 如果提取像素太少,需要减小pot尺寸之后递归重采样;反之增大pot重采样;

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

3.3 makePixelStatus

遍历金字塔,对第1层以上调用makePixelStatus提取特征像素:
(a)将当前层图像分为小块,每个小块默认为 5 × 5 5 \times 5 5×5
(b)遍历块内像素,如果梯度大于阈值,保存像素位置;
(c)如果提取的像素个数太少,需要减小pot尺寸之后递归重采样;反之增大pot重采样;
结果:
在这里插入图片描述

3.4 makeNN

把前面得到的点信息全部提取,保存到对应层的点集。
调用makeNN构建树结构,在当前层查询k最近邻,在高层查询1最近邻,保存对应的点和距离。

好了,初始化过程对第一帧的处理结束。

四、trackFrame

调用setfirst提取大梯度点和对应的最近邻后,dso调用trackFrame跟踪第一帧的梯度点。
过程:

4.1 resetPoints

这个函数主要针对setfirst中提取到的坏点,也就是isGood为false的点。事实上,根据程序设定,如果提取的梯度点在图像边缘3个像素内,这些点都被认为是坏点。

		for(int y=patternPadding+1;y<hl-patternPadding-2;y++)
		for(int x=patternPadding+1;x<wl-patternPadding-2;x++){...}

resetPoints的功能是:如果坏点的十个最近邻里有好点,那么求这些最近邻的逆深度平均值,赋值给坏点,然后就可以把isGood修改为true。

4.2 calcResAndGS

把第一帧作为参考帧,把输入帧作为当前帧,利用LM法,优化两帧之间的光度误差
r = L ( I 2 − I 2 ′ ) = w h ( I 2 [ x 2 ] − ( a 21 I 1 [ x 1 ] + b 21 ) ) r=L(I_2-I_2')=w_h(I_2[x_2]-(a_{21}I_1[x_1]+b_{21})) r=L(I2I2)=wh(I2[x2](a21I1[x1]+b21))待优化状态包括:逆深度 ρ \rho ρ、六自由度姿态 ξ 21 \xi_{21} ξ21、光度仿射变换参数[a,b] 。
dso没有使用g2o或者ceres,而是在calcResAndGS花费了大量的时间计算舒尔补和能量。

4.3 迭代求解

迭代停止的条件有3个:状态增量足够小、迭代次数大于阈值、失败2次以上。
这里的失败指的是两次accept都为false。按照程序设定

float eTotalNew = (resNew[0]+resNew[1]+regEnergy[1]);
float eTotalOld = (resOld[0]+resOld[1]+regEnergy[0]);
bool accept = eTotalOld > eTotalNew;

accept和所有特征的总平移量有关,和点的总逆深度有关,大概是要相机运动足够大。
然后很绕的是,accept为true之后还不够,位移要足够大,snapped才被设为true,这时snappedAt将被赋值。

if(snapped && snappedAt==0)
    snappedAt = frameID;
return snapped && frameID > snappedAt+5;

如果运气够好,之后的连续5帧,accept和snapped被相继设为true,那么程序返回true,初始化结束。
如果运气差,在连续的5帧之间,snapped被设为false,那前面就都变成无用功,只能从头来过。

4.4 propagateDown

当前帧金字塔最高层优化完毕后,下一层的逆深度也需要更新。方法是将父点的逆深度和初始逆深度求加权和来更新逆深度,然后和最近邻逆深度求加权和来平滑,从而更新金字塔逆深度。

4.5 propagateUp

当金字塔所有层都更新完毕后,程序会从第0层开始,为上层每一个父点,计算当前层其所有子点的逆深度平均值,然后父点和其最近邻逆深度求加权和来平滑,更新金字塔逆深度。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值