首页 > 编程语言 >ORB-SLAM2源码学习:ORBextractor.cc:ORBextractor特征提取器③

ORB-SLAM2源码学习:ORBextractor.cc:ORBextractor特征提取器③

时间:2024-11-10 13:45:51浏览次数:3  
标签:15 ORBextractor cc 特征 int 源码 umax 金字塔 nlevels

前言

特征点均匀化:

特征点一般集中在图像纹理比较丰富的区域,在缺乏纹理的区域则特征点数量会少。这会造成特征点冗余,本来几个特征点就能描述清楚某个区域,那么其余的该区域的特征点就多余了。当特征点过多的集中在某一个区域还会造成无法计算相机的位姿即特征点太过集中影响SLAM精度。

1.这个构造函数是干什么的?

ORBextractor是 ORB(Oriented FAST and Rotated BRIEF)特征提取器的构造函数,用于初始化 ORB 特征提取器的各项参数和内部数据结构。这个构造函数主要完成以下几项任务:

1.初始化特征提取器参数。

2.计算金字塔各层的缩放因子、层数平方值、缩放因子和层数平方值的倒数。

3.为图像金字塔容器和每层应分配的特征点容器分配内存。

4.按图像金字塔层级面积比例分配特征点数量(这里只是求出每层金字塔应该分配多少特征点,实际上并没用将特征点填入金字塔内)

5.加载预定义的二进制特征描述符。

6.为计算特征点方向进行预处理数据

2.构造函数ORBextractor的列表初始化

ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
         int _iniThFAST, int _minThFAST):
    nfeatures(_nfeatures),// 提取的特征点数。
    scaleFactor(_scaleFactor),// 图像金字塔的缩放系数。
    nlevels(_nlevels),// 图像金字塔层数。
    iniThFAST(_iniThFAST),// 提取FAST角点的阈值。
    minThFAST(_minThFAST)// 初始阈值检测不到角点则采用该较低的阈值。

3.构造函数ORBextractor内部解析

3.1 设置并计算金字塔的一些参数。

通过遍历金字塔的每一层,计算金字塔的缩放因子(mvScaleFactor)、层数平方(mvLevelSigma2)、缩放因子倒数(mvInvScaleFactor)、层数平方倒数(mvInvLevelSigma2)。

    mvScaleFactor.resize(nlevels);//存储每层图像缩放系数的vector调整其大小为金字塔的层数。
    mvLevelSigma2.resize(nlevels);//存储每层图像相对初始图像缩放因子的平方的vector调整其大小为金字塔的层数。
    //对于初始图像,这两个参数设置为1。
    mvScaleFactor[0]=1.0f;
    mvLevelSigma2[0]=1.0f;
    for(int i=1; i<nlevels; i++)//遍历金字塔的每一层计算mvScaleFactor和mvLevelSigma2。
    {
        mvScaleFactor[i]=mvScaleFactor[i-1]*scaleFactor;//下层乘缩放因子scaleFactor(累乘)。
        mvLevelSigma2[i]=mvScaleFactor[i]*mvScaleFactor[i];// 缩放因子scaleFactor的平方。
    }

    mvInvScaleFactor.resize(nlevels);//存储每层图像缩放系数倒数的vector调整其大小为金字塔的层数。
    mvInvLevelSigma2.resize(nlevels);//存储每层图像相对初始图像缩放因子的平方倒数的vector调整其大小为金字塔的层数。
    for(int i=0; i<nlevels; i++)//遍历金字塔的每一层计算mvInvScaleFactor和mvInvLevelSigma2
    {
        //计算倒数
        mvInvScaleFactor[i]=1.0f/mvScaleFactor[i];
        mvInvLevelSigma2[i]=1.0f/mvLevelSigma2[i];
    }
mvImagePyramid.resize(nlevels);//调整图像金字塔vector的大小为层数。
3.2  定义并逐层分配的特征点个数mnFeaturesPerLevel
3.2.1 数学背景

如何给金字塔分配特征点数量?

面积求和利用了等比数列求和的思想。

3.2.2代码实现
    mnFeaturesPerLevel.resize(nlevels);//调整金字塔每一层应该提取特征点数的vector大小,调整为金字塔的层数。
    float factor = 1.0f / scaleFactor;//为了下边计算每层应该分配多少的特征点作铺垫(作为计算公式的一部分)。
    float nDesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels));// 计算第0层应分配的特征点

    int sumFeatures = 0;//初始化分配的特征点的累加器
    for( int level = 0; level < nlevels-1; level++ )//遍历金字塔每层(除最顶层外)
    {
        mnFeaturesPerLevel[level] = cvRound(nDesiredFeaturesPerScale);//分配特征点(四舍五入取整)
        sumFeatures += mnFeaturesPerLevel[level];//累积已经分配的特征点。
        nDesiredFeaturesPerScale *= factor;//计算下一层应该分配的特征点。
    }
    //最后一层分配的特征点数要用总的特征点减去之前分配的特征点数。
    //怕因为四舍五入带来的特征点分多(最后一层不分)或者是分少(最后一层分配剩余的)。
    mnFeaturesPerLevel[nlevels-1] = std::max(nfeatures - sumFeatures, 0);

这里我有个问题:那么如果每一层都四舍五入取大了,导致可分配的特征点数不够怎么办? 

3.3将bit_pattern_31_中的信息拷贝到pattern中
    const int npoints = 512;//变量pattern的长度。
    const Point* pattern0 = (const Point*)bit_pattern_31_;//(const Point*)强制类型转换将int[]转换为Point*
    std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern));// 将内容复制到pattern中。

为什么是512?

在 ORB 中使用的模式是一个预定义的 256 像素点(即 512 个像素的位置)bit_pattern_31_,这些像素对的位置被提前计算好并存储在一个静态整型数组bit_pattern_31_中。每一对像素的比较结果都会生成一个二进制位(0 或 1),256 对像素的比较结果组合成一个 256 位的描述符。

3.3.1 bit_pattern_31_
static int bit_pattern_31_[256*4] =
{
    8,-3, 9,5/*mean (0), correlation (0)*/,
    4,2, 7,-12/*mean (1.12461e-05), correlation (0.0437584)*/
    .......
}

每组数据由四个整数组成: (x1, y1, x2, y2)。其中 (x1, y1) 和 (x2, y2) 表示一个坐标对。这些坐标是从图像的一个特征点附近采样的。这些点的组合基于预先训练和优化,以确保特征描述子在图像旋转和其他几何变换下具有鲁棒性。代码中的注释部分(如 /*mean (0), correlation (0)*/)表示从统计数据中得到的这对坐标的均值和相关性。这些信息在设计 ORB 描述子时是通过大量训练数据得出的。

3.4计算不同的v值对应的u的最大值的容器umax
3.4.1示意图

3.4.2代码实现
    //This is for orientation
    // pre-compute the end of a row in a circular patch
    //umax存储不同v位置对应的u的最大值
    umax.resize(HALF_PATCH_SIZE + 1);//const int HALF_PATCH_SIZE = 15;

    int v, v0, vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);//计算结果为11。
    int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);//计算结果为11。
    const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;// 平方。
    for (v = 0; v <= vmax; ++v)
        umax[v] = cvRound(sqrt(hp2 - v * v));

    // Make sure we are symmetric
    for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
    {
        while (umax[v0] == umax[v0 + 1])
            ++v0;
        umax[v] = v0;
        ++v0;
    }
3.4.3循环思路:

外层循环从v=0开始,一直到v=11(即 vmax),umax依次是:15 15 15 15 14 14 14 13 13 12 11 10

为确保对称性:内层循环作对称性调整从 v = 15 开始,向下遍历:

umax[0]=umax[1]=15 v0=1 

umax[1]=umax[2]=15 v0=2

umax[2]=umax[3]=15 v0=3

umax[3] =15不等于umax[4]=14  此时v0不自增还是=3 umax[15]=3.

根据此思路依次递推,直到 v = vmin = 11,umax依次是:3 6 8 9 10

最后的结果为16个数。

3.4.4可视化代码显示大致是这样的:
v =  0 | *********************** (umax = 15)
v =  1 | *********************** (umax = 15)
v =  2 | *********************** (umax = 15)
v =  3 | *********************** (umax = 15)
v =  4 | *********************   (umax = 14)
v =  5 | *********************   (umax = 14)
v =  6 | *********************   (umax = 14)
v =  7 | *******************     (umax = 13)
v =  8 | *******************     (umax = 13)
v =  9 | ***************         (umax = 12)
v = 10 | *************           (umax = 11)
v = 11 | ***********             (umax = 10)
v = 12 | *********               (umax =  9)
v = 13 | *******                 (umax =  8)
v = 14 | ******                  (umax =  6)
v = 15 | ***                     (umax =  3)

结束语

以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。

标签:15,ORBextractor,cc,特征,int,源码,umax,金字塔,nlevels
From: https://blog.csdn.net/2301_76831056/article/details/143180928

相关文章

  • JavaCC 实战三:整数加法运算
    前两篇文章我们主要介绍了JavaCC安装以及入门介绍。在这篇文章中介绍如何使用Javacc实现判断输入是否是一个合法的加法运算。在如下这个例子中,我们需要实现对如下数字进行加和:99+42+0+15并且在输入中可以允许在数字之间的任意位置出现空格或者换行符。除此之......
  • [LeetCode] 3090. Maximum Length Substring With Two Occurrences
    Givenastrings,returnthemaximumlengthofasubstringsuchthatitcontainsatmosttwooccurrencesofeachcharacter.Example1:Input:s="bcbbbcba"Output:4Explanation:Thefollowingsubstringhasalengthof4andcontainsatmosttw......
  • (开题报告)django+vue人力资源管理系统源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于人力资源管理系统的研究,现有研究多集中在传统的管理模式或者单一功能模块的优化上。在国内外,一些大型企业已经开始采用先进的技术......
  • [CKS] K8S ServiceAccount Set Up
    最近准备花一周的时间准备CKS考试,在准备考试中发现有一个题目关于Rolebinding的题目。Question1ThebuffyPodinthesunnydalenamespacehasabuffy-saServiceAccountwithpermissionsthePoddoesn’tneed.ModifytheattachedRolesothatitonlyhasthea......
  • 语义分割实战——基于DeepLabv3+神经网络头发分割系统源码
       第一步:准备数据头发分割数据,总共有1050张图片,里面的像素值为0和1,所以看起来全部是黑的,不影响使用第二步:搭建模型DeepLabV3+的网络结构如下图所示,主要为Encoder-Decoder结构。其中,Encoder为改进的DeepLabV3,Decoder为3+版本新提出的。1.1、Encoder在Encoder部分,主要......
  • dc-aichat(一款支持ChatGPT+智谱AI+讯飞星火+书生浦语大模型+Kimi.ai+MoonshotAI+豆包A
    dc-aichat一款支持ChatGPT+智谱AI+讯飞星火+书生浦语大模型+Kimi.ai+MoonshotAI+豆包AI等大模型的AIGC源码。全网最易部署,响应速度最快的AIGC环境。PHP版调用各种模型接口进行问答和对话,采用Stream流模式通信,一边生成一边输出。前端采用EventSource,支持Markdown格式解析,支持公式......
  • 【开题报告】基于Springboot+vue停车场管理系统(程序+源码+论文) 计算机毕业设计
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加速,车辆数量急剧增加,停车难问题已成为制约城市发展的重要瓶颈。传统的停车场管理方式,如人工收费、车位查找等,不仅效率低下,还容易导......
  • 【开题报告】基于Springboot+vue中学生心理健康管理系统(程序+源码+论文) 计算机毕业设
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在当今社会,随着教育竞争的日益激烈和生活节奏的加快,学生面临着前所未有的心理压力。学业负担、人际关系、家庭环境等多重因素交织在一起,对学生的心理......
  • 【开题报告】基于Springboot+vue运动场馆预约系统(程序+源码+论文) 计算机毕业设计
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着全民健身意识的日益增强,各类运动场馆的需求急剧上升。无论是专业运动员还是普通健身爱好者,都希望能够高效、便捷地预约和使用合适的运动场地。然......
  • 计算机毕设源码 基于PHP的老年服务网站的设计与实现
    标题:基于PHP的老年服务网站的设计与实现基于PHP的老年服务网站旨在为老年人提供便捷的服务和信息,帮助他们更好地融入数字生活。以下是一些主要的功能模块及其详细说明:1.用户管理•注册与登录:•注册:用户可以通过邮箱、手机号或其他方式进行注册。•登录:用户通过用户名和......