DSO代码解析--初始化

DSO 的入口是 FullSystem::addActiveFrame,输入的图像生成 FrameHessian 和 FrameShell 的对象,FrameShell 是 FrameHessian 的成员变量,FrameHessian 保存图像信息,FrameShell 保存帧的位置姿态信息。代码中一般用 fh 指针变量指向当前帧的 FrameHessian。在处理完成当前帧之后,会删除 FrameHessian,而保存 FrameShell 在变量 allFrameHistory 中,作为最后整条轨迹的输出。

对输入图像会做预处理,如果有光度标定,像素值不是灰度值,而是处理后的辐射值,这些辐射值的大小是 [0, 255],float 型。

数据预处理部分是在 FullSystem::addActiveFrame 中调用的 FrameHessian::makeImages,这个函数为当前帧的图像建立图像金字塔,并且计算每一层图像的梯度。这些计算结果都存储在 FrameHessian 的成员变量中,1. dIp 每一层图像的辐射值、x 方向梯度、y 方向梯度;2. dI 指向 dIp[0] 也就是原始图像的信息;3. absSquaredGrad 存储 xy 方向梯度值的平方和。

1.第一帧

进入 FullSystem::addActiveFrame,首先判断是否完成了初始化,如果没有完成初始化,就将当前帧 fh 输入 CoarseInitializer::setFirst 中。完成之后接着处理下一帧。

1
void CoarseInitializer::setFirst(   CalibHessian*HCalib, FrameHessian* newFrameHessian)

CoarseInitializer::setFirst,计算图像的每一层内参, 再针对不同层数选择大梯度像素, 第0层比较复杂1d, 2d, 4d大小block来选择3个层次的像素选取点,其它层则选出goodpoints, 作为后续第二帧匹配生成 pointHessians 和 immaturePoints 的候选点,这些点存储在 CoarseInitializer::points 中。每一层点之间都有联系,在 CoarseInitializer::makeNN 中计算每个点最邻近的10个点 neighbours,在上一层的最邻近点 parent。

pointHessians 是成熟点,具有逆深度信息的点,能够在其他影像追踪到的点。immaturePoints 是未成熟点,需要使用非关键帧的影像对它的逆深度进行优化,在使用关键帧将它转换成 pointHessians,并且加入到窗口优化。

2. 第2-7帧

初始化最少需要有七帧,如果第二帧CoarseInitializer::trackFrame 处理完成之后,位移足够,则再优化到满足位移的后5帧返回true. 在 FullSystem::initializerFromInitializer 中为第一帧生成 pointHessians,一共2000个左右。随后将第7帧作为 KeyFrame 输入到 FullSystem::deliverTrackedFrame,最终流入 FullSystem::makeKeyFrame。(FullSystem::deliverTrackedFrame 的作用就是实现多线程的数据输入。)

2.1 CoarseInitializer::trackFrame

CoarseInitializer::trackFrame 中将所有 points (第一帧上的点)的逆深度初始化为1。从金字塔最高层到最底层依次匹配,每一层的匹配都是高斯牛顿优化过程,在 CoarseIntializer::calcResAndGS 中计算Hessian矩阵等信息,计算出来的结果在 CoarseInitializer::trackFrame 中更新相对位姿(存储在局部变量中,现在还没有确定要不要接受这一步优化),在 CoarseInitializer::trackFrame 中调用 CoarseInitializer::doStep 中更新点的逆深度信息。随后再调用一次 CoarseIntializer::calcResAndGS,计算新的能量,如果新能量更低,那么就接受这一步优化,在 CoarseInitializer::applyStep 中生效前面保存的优化结果。

一些加速优化过程的操作:1. 每一层匹配开始的时候,调用一次 CoarseInitializer::propagateDown,将当前层所有点的逆深度设置为的它们 parent (上一层)的逆深度;2. 在每次接受优化结果,更新每个点的逆深度,调用一次 CoarseInitializer::optReg 将所有点的 iR 设置为其 neighbour 逆深度的中位数,其实这个函数在 CoarseInitializer::propagateDown 和 CoarseInitializer::propagateUp 中都有调用,iR 变量相当于是逆深度的真值,在优化的过程中,使用这个值计算逆深度误差,效果是幅面中的逆深度平滑。

优化过程中的 lambda 和点的逆深度有关系,起一个加权的作用,也不是很明白对 lambda 增减的操作。在完成所有层的优化之后,进行 CoarseInitializer::propagateUp 操作,使用低一层点的逆深度更新其高一层点 parent 的逆深度,这个更新是基于 iR 的,使得逆深度平滑。高层的点逆深度,在后续的操作中,没有使用到,所以这一步操作我认为是无用的。

2.2 FullSystem::initializeFromInitializer

FullSystem::initializeFromInitializer,第一帧是 firstFrame,第七帧是 newFrame,从 CoarseInitializer 中抽取出 2000 个点作为 firstFrame 的 pointHessians。设置的逆深度有 CoarseIntiailzier::trackFrame 中计算出来的 iR 和 idepth,而这里使用了 rescaleFactor 这个局部变量,保证所有 iR 的均值为 1。iR 设置的是 PointHessian 的 idepth,而 idepth 设置的是 PointHessian 的 idepth_zero(缩放了scale倍的固定线性化点逆深度),idepth_zero 相当于估计的真值,用于计算误差。

Author

imagine

Posted on

2020-11-10

Updated on

2020-12-24

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.