当前位置 博文首页 > 文章内容

    DSO全家桶(二)——DSO前端:提取梯度点

    作者: 栏目:未分类 时间:2020-11-14 15:01:20

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



     

      嗨,各位读者朋友们好!今天我们接着讲DSO全家桶的第二讲——提取梯度点。

      首先,我们会先介绍一下DSO中从图像读取到提取梯度点的整个流程,然后再对重点的部分——“提取梯度点”进行讲解,让大家对整个流程的逻辑有个较为清晰的认识。这样写的目的主要是让大家在后续自己实现代码的时候,可以有目标地写测试用例。

    图1. 图像预处理到提取梯度点流程图

      OK,我们开始吧!如图1所示,我们将简单阐述一下每一步的操作。

      1. 根据输入的标定文件确定图像的原始尺寸和裁剪尺寸,并且甚至图像的路径。若有光度标定[1]文件,还需要设置光度标定参数;

      2. 在imageRW_OpenCV.cpp[2]中采用cv::imread[3]函数读取指定序号的图像,并拷贝到指定数据类型MinimalImageB中;

      3. 若事先进行了光度标定,DSO会对输入图像先进行光度校正;

      4. 对原始图像进行去畸变[4],并对输出图像进行高斯滤波,目标应该是使得图像平滑一些;

      5. 构建图像金字塔,并逐层逐像素计算梯度值以及梯度值的平方和;

      6. 对图像金字塔第0层(即原始图像)提取梯度点;

      7. 对于图像金字塔第1-5层,设置固定大小的网格,在每个网格中根据梯度值大小选择四类点;

      8. 对步骤6-7选择的点进行初始化,包括坐标、深度值和阈值等。

      上述步骤即是DSO从输入图像开始一直到完成提取梯度点的完整流程。但是我们这里并不会详细介绍每一个步骤,只挑比较重要的部分进行讲解,即上述的步骤6和步骤7。实际上,在自己实现代码的时候,可以借助OpenCV等工具完成图像读取、滤波和构建金字塔等操作,因此我们并不会花大篇幅介绍这些内容。


    DSO前端:提取梯度点

      DSO中对点的提取策略分为两类:

      1. 原始图像层的梯度点提取,即图像金字塔的第0层:由小到大的比较每一个像素的梯度值与阈值,找出满足要求的点;

      2. 图像金字塔第1-5层的梯度点选择:在每个固定大小的网格中,提取四类点。

      接下来,我们对这两个步骤分别进行介绍。

     

    图像金字塔第0层

      首先我们需要先设置密度权重,因为整张图像的像素多到吓人,为了秉承DSO中的Sparse,DSO将第0层的密度权重设置为0.03,即需要提取的目标点数是0.03*width*height。

      处理图像金字塔第0层的函数是PixelSelector::makeMaps(...),表示从无到有的过程。为了更加直观地显示整个过程,笔者引用了泡泡机器人SLAM龚益群同学发布在【泡泡读者来稿】的作品:DSO代码解读[5]中的一些图示进行介绍。

    图2. 梯度直方图

      1. 如图2所示,首先需要对每个32*32的网格创建梯度直方图,在最开始介绍系统流程时,我们提到过需要对图像计算梯度值以及梯度的平方和(dx2+dy2)。而在这里,就是利用梯度平方和统计直方图(梯度直方图的横轴为梯度值,纵轴为像素个数),统计该网格中同一梯度值的像素个数;

      2. 在梯度直方图中找到处于中间(即中位数)的梯度值,作为阈值;

      3. 在步骤2中我们计算了每个32*32的网格中位数的梯度值,对阈值矩阵进行3*3窗口的均值滤波,得到阈值矩阵;

     

    图3. 图像金字塔第0层梯度点筛选策略

      4. 如图3所示,DSO中采用了四级网格策略,其中蓝色网格是16*16,绿色网格是8*8,红色网格是4*4,最内层是1*1,并且彼此之间是包含关系;

      5. 在提取梯度点的时候需要用到我们步骤3计算得到的阈值矩阵,通过由内到外比较每个点的梯度值与阈值的大小,确定提取到的点。这里有几个值得注意的地方,第一是阈值的选取:

      假设阈值是th,

      在1*1的窗口时,阈值被设置为2*th;

      在4*4的窗口中,阈值被设置为th;

      在8*8的窗口中,阈值被设置为0.75*th;

      在16*16的窗口中,阈值被设置为0.75*0.75*th。

      由于DSO中采取的策略是,先从最小的网格开始提取梯度点,在确保梯度值大于阈值的前提下找出网格中梯度值最大的点。若不满足阈值条件,则进入更大的网格进行筛选。而更大的网格都是从小的网格组合得到的,若是阈值不改变,仍然是无法提取到点的。因此,DSO才有这种渐变式的梯度阈值条件。

      值得注意的是,DSO中的起始网格大小并不是图示的4*4,而是3*4。当且仅当第一次提取的点数量不满足要求时,才有可能改变为2*4或者4*4。DSO中采用0.25作为分界线:

      当quotia = numWant / numHave > 1.25,表示提取到的点远小于期望值,需要减小窗口大小以获得更多的点,这时窗口会变成2*4;

      当quotia = numWant / numHave < 0.25,表示提取到的点远大于期望值,需要增大窗口大小以获得更少的点,这时窗口会变成4*4。

     

    图像金字塔第1-5层

      不同于第0层,第1-5层的梯度点筛选是通过在固定网格中计算四类点的最大值来确定的。

    图4. 图像金字塔第1-5层梯度点筛选策略

      1. 首先需要确定的是,DSO预设的网格大小为5*5;

      2. 如图4所示,emmmm....笔者纯粹只是为了避免去画图(偷懒),姑且这里就按4*4算好了。DSO会在每个4*4的网格中逐个像素地计算梯度值sqrt(dx2+dy2);

      3. 整体的阈值条件被设置为th = 1 * 10 *0.75 = 7.5;

      4. 后续我们需要对网格中的所有大于阈值th的像素挨个比较gradX / gradY / gradX - gradY / gradX + gradY的大小,选择该网格中四类条件中最大的四个点。

     

    总结

      至此,第二讲——提取梯度点,我们就已经讲完了。我们在开头介绍了DSO从输入流进来到完成提取梯度点的整个流程,可以帮助读者更快地建立起写一个测试用例应该要考虑的东西,同时也是直接给读者介绍了DSO在图像预处理这块儿做了哪些功夫。后面我们详细介绍了DSO是如何提取梯度点的,主要还是区分图像金字塔第0层和第1-5层的策略。后续笔者完成代码以后会在总结这边贴一些实际运行的结果图,先欠着哈。

      再次感谢一些龚益群同学提供的PPT,感兴趣的同学可以详细阅读参考文献[5]。也非常欢迎各位同行向泡泡机器人SLAM投稿,我们有专门的泡泡读者来稿专栏平台供大家发挥,心动不如行动哇。

      最后的最后,劳烦各位亲爱的读者朋友们给小弟我点个关注吧!谢谢撒!

     

    参考文献

    [1] 光度标定.

    [2] imageRW_OpenCV.cpp.

    [3] cv::imread.

    [4] 去畸变.

    [5] 【泡泡读者来稿】DSO代码解读.

     

    版权声明

      如需转载,请联系本人邮箱peichu.ye at mail2.gdut.edu.cn。未经允许,不可转载。