深蓝学院-视觉SLAM课程-第6讲笔记

课程Github地址:https://github.com/wrk666/VSLAM-Course/tree/master

0. 内容

仍然是前端的内容,估计位姿,不过不是特征点法,而是另外的方法。
深蓝学院-视觉SLAM课程-第6讲笔记_第1张图片

1. 光流法

之前的前端工作流程:

  1. 特征提取
  2. 计算描述子
  3. 特征匹配
  4. 计算相机运动

其中前3步是一定要做的,但是特征的提取(主要是描述子费时)和匹配又是非常耗时,所以考虑用更快的方法来拿到点与点之间的对应关系。

深蓝学院-视觉SLAM课程-第6讲笔记_第2张图片
1图提取出了特征点,对2图不进行提取,找1图中的点在2图中的哪里(Track)。
深蓝学院-视觉SLAM课程-第6讲笔记_第3张图片

光流法分为稀疏和稠密光流,经典方法有LK和HS光流。
深蓝学院-视觉SLAM课程-第6讲笔记_第4张图片

给定一个强假设:t和t+dt时刻同一像素的亮度不变(但实际中不太可能成立,光线,材质,曝光等都会影响像素的亮度)
深蓝学院-视觉SLAM课程-第6讲笔记_第5张图片
深蓝学院-视觉SLAM课程-第6讲笔记_第6张图片
未知数多,方程少:欠定
未知数少,方程多:超定
深蓝学院-视觉SLAM课程-第6讲笔记_第7张图片

深蓝学院-视觉SLAM课程-第6讲笔记_第8张图片

光流法也可以进行物体跟踪,相机不动,对一辆车在远处时采集一个特征点,不断跟踪这个特征点,就能够估计出车的运动轨迹,实现物体跟踪。早期是这样做的,但是后期出现了Deep Learning都用DL了。

深蓝学院-视觉SLAM课程-第6讲笔记_第9张图片
对于之前的灰度不变假设,可以用一些手段处理,如去均值,归一化等。
对于梯度,可以在原始图像或者目标图像中计算,比如在 I 1 I_1 I1中是角点,在 I 2 I_2 I2中就不是角点了。(如何在目标图像中计算?不知道在哪啊,作业中会做,有参考文献)

2. 直接法

光流法没有用到相机的3D投影模型,仅仅是2D-2D的方法。
没有考虑相机的旋转和缩放。
深蓝学院-视觉SLAM课程-第6讲笔记_第10张图片
深蓝学院-视觉SLAM课程-第6讲笔记_第11张图片
直接法是估计相机本身的旋转和平移,而不是每个点的旋转和平移。
直接建立最小二乘问题:

已知 I 1 I_1 I1中的特征点 p 1 p_1 p1,构建光度误差,对齐进行最小化。

待估计的是相机的运动情况,这里取相机运动的李代数 ζ \zeta ζ,这里关键的就是如何求雅可比,
实际上这里是通过优化相机的位姿,来寻找与 p 1 p_1 p1更相似的 p 2 p_2 p2,但这里优化的不是重投影误差,而是光度误差(两个像素的亮度误差)。

深蓝学院-视觉SLAM课程-第6讲笔记_第12张图片

深蓝学院-视觉SLAM课程-第6讲笔记_第13张图片

深蓝学院-视觉SLAM课程-第6讲笔记_第14张图片
深蓝学院-视觉SLAM课程-第6讲笔记_第15张图片

3. 讨论

  1. 特征点法一步步来,如果某步出了问题,就很可能后面纠正不回来,而且可能没有这么多角点提取,如果提取不到相同的角点,那么100%匹配不上。
  2. 如果对于下面的情况,屏幕左边缘上的点,如何匹配?光流法也会沿着左侧的边缘滑动,此时误差不变,最后匹配到哪里无从可知。

深蓝学院-视觉SLAM课程-第6讲笔记_第16张图片
3. 这个问题通过直接法可以来解决,因为直接法使用的是整个相机的运动,而不是通过某几对点之间的匹配来确定的。这导致直接法在选点的时候选择有梯度的点即可,不需要每次都提角点或者有重复的点,也没有光流的那种假设。(有人设计特征:线的,圆的等,但是需要考虑的情况很多)
深蓝学院-视觉SLAM课程-第6讲笔记_第17张图片
直接法可以处理渐变的图像(有梯度),只要保持采光一致。
直接法的缺点:和光流法一样,很依赖于pose估计的准确性(这不就是来估计吗?不太理解)

深蓝学院-视觉SLAM课程-第6讲笔记_第18张图片

直接法讨论:
深蓝学院-视觉SLAM课程-第6讲笔记_第19张图片

4. 实践

1. 光流法

Opencv Optical Flow有一个module的介绍,可以去看
深蓝学院-视觉SLAM课程-第6讲笔记_第20张图片

2. 直接法

OpenCV没有直接法,使用g2o解(g2o)本身就是一个解最小二乘问题的一个库。

说是可以使用雅可比也可以不使用(不太理解)

也可以用ceres或者自己手写高斯牛顿法求解,也可以套多层的金字塔。
可以用多点的像素误差(类似于光流的5*5窗口)

这里例程出了点问题,使用的slambook ch8的代码poseEstimationDirect这个函数出问题,看了一些博客应该是指针的错误,看到g2o时再说。对照之前3d2d的代码改了改前几句:

#include   //G-N 使用相应的求解方法需要引库
#include   //LM

bool poseEstimationDirect ( const vector< Measurement >& measurements, cv::Mat* gray, Eigen::Matrix3f& K, Eigen::Isometry3d& Tcw )
{
    // 初始化g2o
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<6,1>> DirectBlock;  // 求解的向量是6*1的
    typedef g2o::LinearSolverDense<DirectBlock::PoseMatrixType> LinearSolverType;  //线性求解器类型
    //梯度下降方法
//    auto solver = new g2o::OptimizationAlgorithmGaussNewton( g2o::make_unique(g2o::make_unique()));
    auto solver = new g2o::OptimizationAlgorithmLevenberg ( g2o::make_unique<DirectBlock>(g2o::make_unique<LinearSolverType>()));

CMAkeLists.txt:
当时我改了link的库,出了个岔子,这里用的是库里面的节点VertexSE3Expmap,需要linkg2o_types_sba这个库,我给删了,整半天,老是这个报错

undefined reference to `g2o::VertexSE3Expmap::VertexSE3Expmap()

最终的CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( directMethod )

set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "-std=c++11")
# 添加cmake模块路径
list( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules )

find_package( OpenCV 3 REQUIRED)
find_package( G2O REQUIRED)
find_package(Sophus REQUIRED)

include_directories(
        ${OpenCV_INCLUDE_DIRS}
        ${G2O_INCLUDE_DIRS}
        "/usr/include/eigen3/"
        ${Sophus_INCLUDE_DIRS}
)

set( G2O_LIBS  g2o_core g2o_types_sba g2o_solver_csparse g2o_stuff g2o_csparse_extension)

add_executable( direct_sparse direct_sparse.cpp )
target_link_libraries( direct_sparse
        ${OpenCV_LIBS}
        ${G2O_LIBS}
        g2o_core g2o_stuff
        )

add_executable( direct_semidense direct_semidense.cpp )
target_link_libraries( direct_semidense ${OpenCV_LIBS} ${G2O_LIBS} )

半稠密直接法也类似的改VertexSE3Expmap函数。可以看出位姿的估计差不多,半稠密慢多了。
深蓝学院-视觉SLAM课程-第6讲笔记_第21张图片
撸书撸作业!

你可能感兴趣的:(SLAM,slam,自动驾驶)