• ORB-SLAM2 ---- ORBextractor::ComputePyramid函数


    目录

    1.ComputePyramid函数作用

    2. 代码解释

    2.1 整体代码

    2.2 几个图像的区别

    2.3 拷贝图像的方式

    2.3.1 图像扩充边界的方式

    2.3.2 为什么要扩充图像边界

    2.3.3 拷贝图像代码解释 

    2.3.4 要分清构造图像的大小Sz、构造空图像Mat、填补图像resize、扩充图像MakeBorder的区别!!!


    1.ComputePyramid函数作用

            根据输入的图片CV::Mat构建图像金字塔图像。

    2. 代码解释

    2.1 整体代码

    1. void ORBextractor::ComputePyramid(cv::Mat image)
    2. {
    3. //开始遍历所有的图层,levels是yaml文件里面的
    4. for (int level = 0; level < nlevels; ++level)
    5. {
    6. //获取本层图像的缩放系数,mvInvScaleFactor[level]是从orbextrator得到的
    7. float scale = mvInvScaleFactor[level];
    8. //计算本层图像的像素尺寸大小
    9. Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
    10. //全尺寸图像。包括无效图像区域的大小。将图像进行“补边”,EDGE_THRESHOLD区域外的图像不进行FAST角点检测
    11. Size wholeSize(sz.width + EDGE_THRESHOLD*2, sz.height + EDGE_THRESHOLD*2);
    12. // temp是扩展了边界的图像,是一个构造函数,拷贝了wholeSize的图像
    13. Mat temp(wholeSize, image.type()), masktemp;
    14. // mvImagePyramid 刚开始时是个...空的vector
    15. // 将扩充后的图像拷贝给mvImagePyramid容器
    16. mvImagePyramid[level] = temp(Rect(EDGE_THRESHOLD, EDGE_THRESHOLD, sz.width, sz.height));
    17. // Compute the resized image
    18. //计算第0层以上resize后的图像
    19. if( level != 0 )
    20. {
    21. //将上一层金字塔图像根据前文设定sz缩放到当前层级
    22. resize(mvImagePyramid[level-1], //输入图像
    23. mvImagePyramid[level], //输出图像
    24. sz, //输出图像的尺寸
    25. 0, //水平方向上的缩放系数,留0表示自动计算
    26. 0, //垂直方向上的缩放系数,留0表示自动计算
    27. cv::INTER_LINEAR); //图像缩放的差值算法类型,这里的是线性插值算法
    28. //把源图像拷贝到目的图像的中央,四面填充指定的像素。图片如果已经拷贝到中间,只填充边界
    29. //这样做是为了能够正确提取边界的FAST角点
    30. //EDGE_THRESHOLD指的这个边界的宽度,由于这个边界之外的像素不是原图像素而是算法生成出来的,所以不能够在EDGE_THRESHOLD之外提取特征点
    31. copyMakeBorder(mvImagePyramid[level], //源图像
    32. temp, //目标图像(此时其实就已经有大了一圈的尺寸了)
    33. EDGE_THRESHOLD, EDGE_THRESHOLD, //top & bottom 需要扩展的border大小
    34. EDGE_THRESHOLD, EDGE_THRESHOLD, //left & right 需要扩展的border大小
    35. BORDER_REFLECT_101+BORDER_ISOLATED); //扩充方式,opencv给出的解释:
    36. }
    37. else
    38. {
    39. //对于第0层未缩放图像,直接将图像深拷贝到temp的中间,并且对其周围进行边界扩展。此时temp就是对原图扩展后的图像
    40. copyMakeBorder(image, //这里是原图像
    41. temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
    42. BORDER_REFLECT_101);
    43. }
    44. }
    45. }

    2.2 几个图像的区别

    1. for (int level = 0; level < nlevels; ++level)
    2. {
    3. //获取本层图像的缩放系数,mvInvScaleFactor[level]是从orbextrator得到的
    4. float scale = mvInvScaleFactor[level];
    5. //计算本层图像的像素尺寸大小
    6. Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
    7. //全尺寸图像。包括无效图像区域的大小。将图像进行“补边”,EDGE_THRESHOLD区域外的图像不进行FAST角点检测
    8. Size wholeSize(sz.width + EDGE_THRESHOLD*2, sz.height + EDGE_THRESHOLD*2);
    9. // temp是扩展了边界的图像,是一个构造函数,拷贝了wholeSize的图像
    10. Mat temp(wholeSize, image.type()), masktemp;
    11. // mvImagePyramid 刚开始时是个...空的vector
    12. // 把中间区域拷贝给mvImagePyramid容器
    13. mvImagePyramid[level] = temp(Rect(EDGE_THRESHOLD, EDGE_THRESHOLD, sz.width, sz.height));

            我们从第0层到第八层确定金字塔的尺寸及图像。

    1. std::vector<float> mvScaleFactor; ///<每层图像的缩放因子
    2. std::vector<float> mvInvScaleFactor; ///<以及每层缩放因子的倒数
    3. std::vector<float> mvLevelSigma2; ///<存储每层的sigma^2,即上面每层图像相对于底层图像缩放倍数的平方
    4. std::vector<float> mvInvLevelSigma2; ///
    5. ///这个是用来存储图像金字塔的变量,一个元素存储一层图像
    6. std::vector mvImagePyramid;

            先获取本层的缩放系数,然后构造本层图像像素的尺寸大小sz,这个大小就是传进来的参数图像的大小乘以缩放因子。

            然后构造全尺寸图像尺寸大小,全尺寸图像是将上下左右都镶上边框了,对图像进行补边,如下图所示。

             再构造空图片temp,用全尺寸大小进行初始化,并将格式设置与输入图片一致,最后一行代码的意思是将temp图片扩充边界大小保存到mvImagePyramid容器中,mvImagePyramid容器保存金字塔各层图像。

    2.3 拷贝图像的方式

    2.3.1 图像扩充边界的方式

            在opencv里面提供。

    2.3.2 为什么要扩充图像边界

            利用FAST算法在提取特征点时,图像边缘的特征点半径为3的圆无法取到(边界外无像素点),为了解决此问题,我们对图像边界进行填充。

    2.3.3 拷贝图像代码解释 

    1. // Compute the resized image
    2. //计算第0层以上resize后的图像
    3. if( level != 0 )
    4. {
    5. //将上一层金字塔图像根据前文设定sz缩放到当前层级
    6. resize(mvImagePyramid[level-1], //输入图像
    7. mvImagePyramid[level], //输出图像
    8. sz, //输出图像的尺寸
    9. 0, //水平方向上的缩放系数,留0表示自动计算
    10. 0, //垂直方向上的缩放系数,留0表示自动计算
    11. cv::INTER_LINEAR); //图像缩放的差值算法类型,这里的是线性插值算法
    12. //把源图像拷贝到目的图像的中央,四面填充指定的像素。图片如果已经拷贝到中间,只填充边界
    13. //这样做是为了能够正确提取边界的FAST角点
    14. //EDGE_THRESHOLD指的这个边界的宽度,由于这个边界之外的像素不是原图像素而是算法生成出来的,所以不能够在EDGE_THRESHOLD之外提取特征点
    15. copyMakeBorder(mvImagePyramid[level], //源图像
    16. temp, //目标图像(此时其实就已经有大了一圈的尺寸了)
    17. EDGE_THRESHOLD, EDGE_THRESHOLD, //top & bottom 需要扩展的border大小
    18. EDGE_THRESHOLD, EDGE_THRESHOLD, //left & right 需要扩展的border大小
    19. BORDER_REFLECT_101+BORDER_ISOLATED); //扩充方式,opencv给出的解释:
    20. }
    21. else
    22. {
    23. //对于第0层未缩放图像,直接将图像深拷贝到temp的中间,并且对其周围进行边界扩展。此时temp就是对原图扩展后的图像
    24. copyMakeBorder(image, //这里是原图像
    25. temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
    26. BORDER_REFLECT_101);
    27. }
    28. }

            如果图像是非0层的,将上一层的图像作为输入缩放到本层并存储到mvImagePyramid容器作为本函数的输出,图像大小为本层计算出来的sz(不包含边界的),copyMakeBorder函数把源图像拷贝到目的图像的中央,四面填充指定的像素。图片如果已经拷贝到中间,只填充边界。

            如果图像是0层的,只填充边界。

    2.3.4 要分清构造图像的大小Sz、构造空图像Mat、填补图像resize、扩充图像MakeBorder的区别!!!

  • 相关阅读:
    ESP32-IDF使用I2S驱动MAX98375--解析WAV文件
    JDK8升级JDK11最全实践干货来了
    并行多核体系结构基础知识
    TensorFlow.NET机器学习环境搭建(1)C#
    Mybatis | Mybatis标签collection一对多的使用
    分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
    阿里P9被转载上100W次的Java面试题!已助我拿下12家大厂offer!
    C++入门第八篇---STL模板---list的模拟实现
    RTMP协议解析
    golang上传文件到ftp服务器
  • 原文地址:https://blog.csdn.net/qq_41694024/article/details/126293781