Advertisement

ORB_SLAM2算法如何提取图像的ORB特征点?

阅读量:

文章目录

特征提取接口是如何被调用的?
特征提取接口是如何定义的?
Mat image = _image.getMat();
assert(image.type() == CV_8UC1 );
ComputePyramid(image);
计算特征点
计算描述子
对提取到的特征点进行进一步处理

提取特征接口如何调用?

复制代码
    void Frame::ExtractORB(int flag, const cv::Mat &im)
    {
    if (flag == 0)
        (*mpORBextractorLeft)(im, cv::Mat(), mvKeys, mDescriptors);
    else
        (*mpORBextractorRight)(im, cv::Mat(), mvKeysRight, mDescriptorsRight);
    }
    
    
      
      
      
      
      
      
      
    
    AI助手

这段代码是Frame类中一个成员函数Frame::ExtractORB的实现。它旨在从输入图像 im 中提取ORBE特征点及其描述符。下面对代码的运行逻辑进行详细解析。

复制代码
    void Frame::ExtractORB(int flag, const cv::Mat &im)
    {
    if (flag == 0)
        (*mpORBextractorLeft)(im, cv::Mat(), mvKeys, mDescriptors);
    else
        (*mpORBextractorRight)(im, cv::Mat(), mvKeysRight, mDescriptorsRight);
    }
    
    
      
      
      
      
      
      
      
    
    AI助手

这是一个与类相关的静态成员函数声明和定义,在C++编程语言中使用

当变量 flag 的值等于 0 时

(*mpORBextractorLeft)(im, cv::Mat(), mvKeys, mDescriptors); // 这是一条函数调用指令 // 调用了通过指针mpORBextractorLeft` 所指向的对象实现的功能
// 该对象专门负责提取ORBE feature points及其描述符
// 并将其图像信息、掩码矩阵(默认为空)、关键点索引以及描述符数据分别传入指定变量中。

else:如果 flag 的值不为 0,则执行下面的代码块。

表示另一个函数调用语句。该函数调用了一个指向mpORBextractorRight指针所指向的重载operator()函数对象。同样地,该函数对象用于提取ORB特征点和描述符。它接收输入图像im以及一个空cv::Mat()对象作为掩码参数,并通过mvKeysRight和mDescriptorsRight作为输出参数传递相关数据。该函数对象用于提取OROB特征点和描述符。

根据传入的flag参数值的不同取向情况(即当flag为真时或假时),系统会分别调用相应的ORB特征提取器对象(即左眼ORB提取器或右眼ORB提取器)。随后程序会将计算出的特征点按照对应的目标存储空间(即mvKeys或mvKeysRight)进行分类存放,并相应地将计算出的描述信息存入对应的mDescriptors或mDescriptorsRight目标空间中。经过测试该机制能够有效支持不同应用场景下的ORB特征提取工作

提取特征接口如何定义?

Mat image = _image.getMat();

通过调用方法获取矩阵对象 Mat ,并将结果存储在变量 image

image 是一个参数变量,默认被指定为 InputArray 类型,并被定义为用于传递图像数据的对象。该变量 InputArray 具备多样的接收能力,在具体应用中可灵活配置不同的输入形式如 Mat、Mat 或 std::vector 等等。

getMat()InputArray 类提供的一项功能,在接收输入数据时将其转换为 Mat 对象的形式上具有特殊性。假如 _image 已经是以 Mat 类型存在的信息体,则 getMat() 的作用就是直接将其引用传递回去;但如果 _image 并不是 Mat 类型的信息体而是其他形式的数据体(比如说是 Mat_ 或者 std::vector),那么 getMat() 就需要执行相应的数据转化工作后才能完成任务并输出新的 Mat 对象信息体

在这一段代码中,函数调用 _image.getMat() 将输入参数 `_image_转换为 Mat_对象,并将其结果赋值给变量 image。从而使得我们在后续代码中能够通过 image 变量来访问和操作图像数据。

assert(image.type() == CV_8UC1 )

该断言语句主要用于验证 image 的数据类型是否为 CV_8UC1 类型,并在数据类型不匹配时触发特定行为或错误处理机制。

该函数返回 image 的数据类型信息,并由 OpenCV 提供的一个宏定义变量来表示此值。具体而言,在这一特定的宏定义中,
其中 <bit-depth> 代表位深度,
<S|U|F> 则分别代表有符号、无符号以及浮点数类型的区分,
最后一个是 <channels> 代表图像中的通道数量。

此代码块定义了无符号8位单通道图像的表示方式。程序中的判断语句会验证 image.type() 的返回类型是否与预定义的 CV_8UC1 一致。当上述条件不满足时(即返回类型并非 CV_8UC1),判断逻辑将被触发,并导致程序终止以显示错误信息。

该段语句旨在保证在后续代码流程中对image变量进行正确的解析处理。具体而言,在使用该断言时会强制将image变量视为单通道无符号8位图像类型,并在此过程中确保后续操作能够顺利进行。当断言条件满足时(即当断言结果为真时),可能导致该现象的原因之一是输入图像的数据类型与预期不符;此时应采取相应的调整措施来解决。

ComputePyramid(image);

逐函数讲解ORB_SLAM2源码

逐函数讲解ORB_SLAM2源码

生成的图像金字塔如下图所示:

在这里插入图片描述

计算特征点

ComputeKeyPointsOctTree作为ORB-SLAM2算法的核心模块,在图像处理过程中负责提取关键信息以构建三维模型

该视觉SLAM算法OR-BSLAM 2主要依赖于特征点检测技术,在实时相机定位与三维环境地图构建方面具有显著效果。其核心模块ComputeKeyPointsOctTree负责从输入图像中提取关键信息。通过金字塔式多尺度分析方法,系统能够有效识别并精确描绘出物体的几何特性。

具体而言,在函数ComputeKeyPointsOctTree中,我们通过构造图像的多分辨率结构来定位关键点。该函数采用Oriented OR(OR)特征检测器,在从最低分辨率开始逐步细化的过程中识别出各个尺度上的特征点。为了生成这个多分辨率结构,我们持续对输入图像进行下采样处理,并将每个层次对应于图像的不同尺度信息。

检测到的特征点将在后续步骤中进行计算与匹配,并被用来完成相机定位以及地图构建的任务。

ORB-SLAM2是一种先进的视觉 SLAM 算法,在机器人导航与环境建模领域具有重要地位。该算法包含了多个关键组件:首先是基于深度学习的特征描述符计算模块;其次是高效的特征匹配机制;然后是基于视觉定位的核心模块;最后是全局地图优化技术。如需进一步了解有关该算法的细节及其实现,请参考相关文献和开源代码仓库。

计算描述子

复制代码
    Mat descriptors;
    
    int nkeypoints = 0;
    for (int level = 0; level < nlevels; ++level)
    nkeypoints += (int)allKeypoints[level].size();
    if( nkeypoints == 0 )
    _descriptors.release();
    else
    {
    _descriptors.create(nkeypoints, 32, CV_8U);
    descriptors = _descriptors.getMat();
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI助手

根据检测到的特征点数量创建一个存储特征描述符的cv::Mat对象。

具体来说,在代码中首先会进行金字塔层级(level)遍历操作。为了统计整体的关键点数量,在此过程中会先对每个层级中的关键点进行计数,并将这些数据存储在一个叫做allKeypoints的数组中。随后对所有层级的关键点数量进行求和运算,从而得到整个金字塔结构下的总关键点数。

随后对整个图像中的特征点总数进行计算。当计算结果等于零时, 表示在当前图像中没有识别出任何关键特征点, 因此该Mat对象将被释放(_descriptors.release())。这种现象通常常见于图像中缺乏足够的纹理细节或关键结构来生成稳定且可靠的特征描述符。

当总的特征点数量不为零时,该代码会生成一个大小为nkeypoints乘以32的CV_8U类型矩阵对象,并将其作为引用使用以存储特征描述符。

这段代码主要负责生成合适尺寸的Mat对象。这些矩阵元素用于表示特征点周围的局部图像结构。这些矩阵元素随后将被用来完成后续的特征匹配和定位任务。

对提取到的特征点进一步处理

复制代码
    int offset = 0;
    for (int level = 0; level < nlevels; ++level)
    {
    vector<KeyPoint>& keypoints = allKeypoints[level];
    int nkeypointsLevel = (int)keypoints.size();
    
    if(nkeypointsLevel==0)
        continue;
    
    // preprocess the resized image
    Mat workingMat = mvImagePyramid[level].clone();
    GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);
    
    // Compute the descriptors
    Mat desc = descriptors.rowRange(offset, offset + nkeypointsLevel);
    computeDescriptors(workingMat, keypoints, desc, pattern);
    
    offset += nkeypointsLevel;
    
    // Scale keypoint coordinates
    if (level != 0)
    {
        float scale = mvScaleFactor[level]; //getScale(level, firstLevel, scaleFactor);
        for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
             keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
            keypoint->pt *= scale;
    }
    // And add the keypoints to the output
    _keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI助手

用于在每个金字塔层级上计算特征描述符并进行后处理。

在过程中,在每一阶段代码会逐步覆盖各个层次结构中的关键点位置信息。对于每一个阶段而言,在这一阶段中代码会收集该阶段上识别出的关键点向量数据的同时统计该阶段上的关键点数量。

如果特征点数量为零,代码将跳过当前层级的处理。

对于非零特征点数量的层级,代码进行以下操作:

经过尺寸调整的图像预处理:系统会对当前层图像进行复制操作,并随后执行高斯模糊滤波以去除细节中的噪声污染。这种处理方法能够有效提升后续特征提取的分辨率并增强其鲁棒性与适应性。

生成特征描述符:依靠已经调用过的computeDescriptors函数,在经过了预处理的图像以及当前层级的关键点上进行运算。最终得出的结果被保存到了名为desc的那个变量里。

为了调整偏移量,在当前层级的基础上增加特征点的数量,并对offset变量进行更新;这样可以在描述符矩阵中精确指定各个特征点的位置。

缩放关键点坐标:当当前层级不是最底层时(即存在父级层级),代码会依据该层别特定的比例因子来调整特征点的位置参数。这主要是因为特征点在各个层级中的位置具有相对性,在不同层次的空间中其绝对位置无法直接对应对应关系。因此,在处理不同层次的数据时需要根据具体层次进行相应的调整以确保数据的一致性和完整性。

在处理过程中,该代码会将当前层级的特征点并将其加入输出向量_keypoints中。

左右目最终提取到的特征点

在这里插入图片描述

全部评论 (0)

还没有任何评论哟~