ORB-SLAM2 ---- Frame::GetFeaturesInArea函数

news2024/11/16 2:14:17

目录

1.函数用处

2.步骤 

3.code 

4.函数解释 

4.1 函数思想

4.2 代码解释 


1.函数用处

        找到在 以(x,y)为中心,半径为r的圆形内且金字塔层级在[minLevel, maxLevel]的特征点。

2.步骤 

Step 1 计算半径为r圆左右上下边界所在的网格列和行的id

Step 2 遍历圆形区域内的所有网格,寻找满足条件的候选特征点,并将其index放到输出里

3.code 

vector<size_t> Frame::GetFeaturesInArea(const float &x, const float  &y, const float  &r, const int minLevel, const int maxLevel) const
{
	// 存储搜索结果的vector
    vector<size_t> vIndices;
    vIndices.reserve(N);

    // Step 1 计算半径为r圆左右上下边界所在的网格列和行的id
    // 查找半径为r的圆左侧边界所在网格列坐标。这个地方有点绕,慢慢理解下:
    // (mnMaxX-mnMinX)/FRAME_GRID_COLS:表示列方向每个网格可以平均分得几个像素(肯定大于1)
    // mfGridElementWidthInv=FRAME_GRID_COLS/(mnMaxX-mnMinX) 是上面倒数,表示每个像素可以均分几个网格列(肯定小于1)
	// (x-mnMinX-r),可以看做是从图像的左边界mnMinX到半径r的圆的左边界区域占的像素列数
	// 两者相乘,就是求出那个半径为r的圆的左侧边界在哪个网格列中
    // 保证nMinCellX 结果大于等于0
    const int nMinCellX = max(0,(int)floor( (x-mnMinX-r)*mfGridElementWidthInv));


	// 如果最终求得的圆的左边界所在的网格列超过了设定了上限,那么就说明计算出错,找不到符合要求的特征点,返回空vector
    if(nMinCellX>=FRAME_GRID_COLS)
        return vIndices;

	// 计算圆所在的右边界网格列索引
    const int nMaxCellX = min((int)FRAME_GRID_COLS-1, (int)ceil((x-mnMinX+r)*mfGridElementWidthInv));
	// 如果计算出的圆右边界所在的网格不合法,说明该特征点不好,直接返回空vector
    if(nMaxCellX<0)
        return vIndices;

	//后面的操作也都是类似的,计算出这个圆上下边界所在的网格行的id
    const int nMinCellY = max(0,(int)floor((y-mnMinY-r)*mfGridElementHeightInv));
    if(nMinCellY>=FRAME_GRID_ROWS)
        return vIndices;

    const int nMaxCellY = min((int)FRAME_GRID_ROWS-1,(int)ceil((y-mnMinY+r)*mfGridElementHeightInv));
    if(nMaxCellY<0)
        return vIndices;

    // 检查需要搜索的图像金字塔层数范围是否符合要求
    //? 疑似bug。(minLevel>0) 后面条件 (maxLevel>=0)肯定成立
    //? 改为 const bool bCheckLevels = (minLevel>=0) || (maxLevel>=0);
    const bool bCheckLevels = (minLevel>0) || (maxLevel>=0);

    // Step 2 遍历圆形区域内的所有网格,寻找满足条件的候选特征点,并将其index放到输出里
    for(int ix = nMinCellX; ix<=nMaxCellX; ix++)
    {
        for(int iy = nMinCellY; iy<=nMaxCellY; iy++)
        {
            // 获取这个网格内的所有特征点在 Frame::mvKeysUn 中的索引
            const vector<size_t> vCell = mGrid[ix][iy];
			// 如果这个网格中没有特征点,那么跳过这个网格继续下一个
            if(vCell.empty())
                continue;

            // 如果这个网格中有特征点,那么遍历这个图像网格中所有的特征点
            for(size_t j=0, jend=vCell.size(); j<jend; j++)
            {
				// 根据索引先读取这个特征点 
                const cv::KeyPoint &kpUn = mvKeysUn[vCell[j]];
				// 保证给定的搜索金字塔层级范围合法
                if(bCheckLevels)
                {
					// cv::KeyPoint::octave中表示的是从金字塔的哪一层提取的数据
					// 保证特征点是在金字塔层级minLevel和maxLevel之间,不是的话跳过
                    if(kpUn.octave<minLevel)
                        continue;
                    if(maxLevel>=0)		//? 为何特意又强调?感觉多此一举
                        if(kpUn.octave>maxLevel)
                            continue;
                }               

                // 通过检查,计算候选特征点到圆中心的距离,查看是否是在这个圆形区域之内
                const float distx = kpUn.pt.x-x;
                const float disty = kpUn.pt.y-y;

				// 如果x方向和y方向的距离都在指定的半径之内,存储其index为候选特征点
                if(fabs(distx)<r && fabs(disty)<r)
                    vIndices.push_back(vCell[j]);
            }
        }
    }
    return vIndices;
}

4.函数解释 

4.1 函数思想

        对于ORB-SLAM2这个算法来讲,它是认为相邻两帧间的运动微乎其微,于是,我们在匹配特征点时就有以下思想:

        由于两帧之间的运动不是很大,那么第一帧中的某一特征点的位置与第二帧中该特征点的位置应该差不多,于是我们就有了这个函数,我们将第一帧中的某一特征点在相机坐标系的位置记录,然后画一个区域在第二帧的该区域寻找所有特征点,找到与该特征点最相似的一个特征点(通过描述子距离比较)作为匹配的特征点。

        于是,我们看看是怎么做的吧!

        先看一下变量含义和一些量的含义:

        ①mnMinX:该帧的左边界点

        ②mnMaxX:该帧的左边界点

        ③FRAME_GRID_COLS:一个帧的列数量(如上图:一个帧分为了很多个格子)

        ④(mnMaxX-mnMinX)/FRAME_GRID_COLS:表示列方向每个网格可以平均分得几个像素

        ⑤mfGridElementWidthInv=FRAME_GRID_COLS/(mnMaxX-mnMinX) 是④的倒数,表示每个像素可以均分几个网格列

        ⑥x-mnMinX-r:特征点的x-帧的左边界-半径=圆的最左面的点,即mMinCellX的坐标

        ⑦(x-mnMinX-r)*mfGridElementWidthInv:这个值向下取整就表示圆的最左面的点所在哪列(在哪个列格子里)

        懂了这些我们就能读懂这块的代码了。

4.2 代码解释 

        我们现根据传入的参数r确定搜索的框框(确定一个方形区域,这个区域包含了当前的特征点,我们将这个框框投影到下一帧在下一帧的这个框框中取出所有的特征点挨个匹配)

        这个框框是由nMinCellX、nMaxCellX、nMinCellY、nMaxCellY围成的矩形区域。        

        遍历圆形区域内的每个网格,寻找满足条件的候选特征点:

        获取一个网格内的所有特征点在 Frame::mvKeysUn 中的索引(去畸变后的特征点)(在第二帧中的特征点的索引)存到vCell向量中,我们读取每个特征点放在临时变量kpUn中,判断这个特征点的合法性(金字塔层级范围是否合法,通过传入的参数minLevel,maxLevel确定),我们再判断这个特征点到“圆心的距离r(函数形参)”(我们找到的特征点是遍历每个矩形的,这是为了清楚矩形边缘的特征点)是否合理,若合理,我们将此特征点的索引放入Indice向量中。

        当我们遍历所有的栅格的时候,我们就得到了与第一帧中的某一特征点待匹配的所有特征点的索引了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/73522.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录Day44|完全背包、518.零钱兑换II、377.组合总和IV

文章目录完全背包518.零钱兑换II377.组合总和IV完全背包 文章链接:代码随想录 (programmercarl.com) 背包最大重量为4。 物品为&#xff1a;如果求组合数就是外层for循环遍历物品&#xff0c;内层for遍历背包。 如果求排列数就是外层for遍历背包&#xff0c;内层for循环遍历…

Linux多线程C++版(九) 线程同步和互斥-----线程信号量

目录1.基本概念2.信号量创建和销毁3.信号量加和减操作4.代码理解信号量5.信号量实例银行账户取款----实现互斥6.信号量实例计算和取结果----实现线程同步1.基本概念 信号量从本质上是一个非负整数计数器&#xff0c;是共享资源的的数目&#xff0c;通常被用来控制对共享资源的…

[附源码]JAVA毕业设计同学录网站(系统+LW)

[附源码]JAVA毕业设计同学录网站&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#…

从源码出发剖解正则表达式

✨✨hello&#xff0c;愿意点进来的小伙伴们&#xff0c;你们好呐&#xff01; &#x1f43b;&#x1f43b;系列专栏&#xff1a;【JavaSE】 &#x1f432;&#x1f432;本篇内容&#xff1a;详解正则表达式 &#x1f42f;&#x1f42f;作者简介:一名现大二的三非编程小白&…

[ MySQL ] 使用Navicat进行MySQL数据库备份 / 还原(备份.nb3文件方式)

本文主要讲解如何用Navicat&#xff08;Navicat Premium &#xff0c;或者Navicat for mysql&#xff09;进行MySQL备份和恢复数据库。 本文主要大纲为&#xff1a;使用Navicat备份工具方式进行备份和还原&#xff0c;其中包括还原自身数据库和还原到其他目标库。 文章目录一、…

Jenkins 中 shell 脚本执行失败却不自行退出

Jenkins 中 执行 shell 脚本时&#xff0c;有时候 shell 执行失败了&#xff0c;或者判断结果是错误的&#xff0c;但是 Jenkins 执行完成后确提示成功 success 。 此时&#xff0c;可以通过条件判断来解决这个问题&#xff0c;让 Jenkins 强制退出并提示执行失败 failed 。 …

Tensorflow笔记

Tensorflow笔记基础概念计算图Eager Execution&#xff08;即刻执行&#xff09;eager模式下计算梯度基本使用tf.app加载flag&#xff08;tf.app.flags&#xff09;启动( tf.app.run )基础概念 计算图 Tensor&#xff08;张量&#xff09;&#xff0c;在Tensorflow中可以理解…

畅聊两小时后谈谈chatGPT体验感受

文章目录背景注册聊天实录基于自然语言的SQL翻译shell解析k8s回答其他类型我的问题为何这么接近人类的回答&#xff1f;回答是离线的吗&#xff1f;背景 最近几周不管是T还是微信公众号&#xff0c;大家都在疯玩这个东西。 我姑且将这个应用叫小C吧。我和小C愉快的聊了几个小…

ComponentOne Studio Enterprise 2022

ComponentOne Studio Enterprise 2022 添加了Microsoft.NET 7支持。 FlexGrid for.NET MAUI预览版-您现在可以使用以前使用的相同.NET数据网格&#xff0c;只是它是为MAUI本机开发的&#xff0c;因此您不必学习多种移动开发平台。 WinForms 2022 v3中的新功能 增强的.NET 6控件…

Android系统属性文件浅析

Android的属性文件是Android系统攻防中重要的一环,属性中的一些只读字段(以ro开头)通常会被当作大厂的指纹而加入检测,于是如何mock和检测mock成了安全中举足轻重的知识。属性的检测有几种方案: 通过java标准接口的Build类读取通过shell的getprop [属性key]的方式读取通过sh…

Python作业题:函数和代码复用

本次练习题涉及到的知识点&#xff1a; Python中函数的定义和使用传入函数的参数个数不固定的使用语法lambda函数的使用语法Python异常处理的相关语法 1.关于函数的描述&#xff0c;错误的选项是&#xff08;A&#xff09;。 解析&#xff1a;Python使用保留字def定义一个函…

聚类算法OPTICS的理解及实现

前言 前面给大家介绍到了聚类算法中比较经典的 DBSCAN 算法&#xff0c;对于数据量小而且相对比较密集、密度相似的数据集来说&#xff0c;是比较合适的。那么接下来给大家介绍它的改进版 OPTICS (Ordering points to identify the clustering structure)&#xff0c;针对 DBS…

4年外包终上岸,我只能说这类公司以后能不去就不去

我大学学的是计算机专业&#xff0c;毕业的时候&#xff0c;对于找工作比较迷茫&#xff0c;也不知道当时怎么想的&#xff0c;一头就扎进了一家外包公司&#xff0c;一干就是4年。现在终于跳槽到了互联网公司了&#xff0c;我想说的是&#xff0c;但凡有点机会&#xff0c;千万…

vue使用axios+element上传文件

引言 springboot后端接口类型&#xff1a;post&#xff0c;其它接口信息如下图 后端接口的实现 代码示例 post 请求头改成’Content-Type’: ‘multipart/form-data’用new FormData() 方式去传对象数据 axios封装请求 import request from /utils/request export function up…

线性表-顺序表

线性表 线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列。 前驱元素&#xff1a;若A元素在B元素的前面&#xff0c;则称A为B的前驱元素后继元素&#xff1a;若B元素在A元素的后面&#xff0c;则称B为A的后继元素 线性表…

将gitee上的项目拉取到本地

gitee&#xff1a;中国最大的开源代码共享社区 目录 一、安装git 二、拉取项目 1、首先在gitee上找到自己想要学习的项目 2、在本地新建一个文件夹&#xff08;用来存放你从gitee上拉下来的项目&#xff09; 3、输入命令 4、选择下载的分支代码&#xff08;我这里是mas…

【web课程设计】基于html鲜花商城项目的设计与实现

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

windows下使用免安装(.zip)MariaDB数据库

1. 下载 https://downloads.mariadb.org/ 2. 解压 3. 配置 cmd 进入bin目录 命令行输入&#xff1a;./mysqld.exe --install MariaDB 输出&#xff1a; 至此 安装成功 接下来进行data配置和初始化 4. 初始化 提示&#xff1a;非必要 如果直接执行服务启动命令&#xff1…

TF3-MongoDB基础

TF3-MongoDB基础课程介绍1、通用设置1.1 需求分析1.1.1 需求分析1.1.2 数据库表1.1.3 搭建提供者环境实体类mapper接口api接口api服务实现类1.2 查询通用设置1.2.1 接口文档1.2.2 代码实现vo对象SettingsControllerSettingServiceQuestionApiSettingApi1.2 陌生人问题1.2.1 接口…

STM32单片机软件模拟I2C读取AM2320温湿度传感器数据

STM32单片机使用软件模拟IIC读取AM2320温湿度传感器的数据并显示在0.96寸OLED屏上。 我用的单片机是STM32F103C8T6&#xff0c;程序用的是ST标准库写的。 STM32使用硬件I2C读取SHTC3温湿度传感器&#xff1a;https://blog.zeruns.tech/archives/692.html STM32单片机读取AHT1…