ORB-SLAM2 --- MapPoint::ComputeDistinctiveDescriptors 函数

news2024/12/27 13:11:14

目录

一、函数作用

二、函数步骤 

三、code 

四、函数解析 


一、函数作用

        计算地图点最具代表性的描述子。

        由于一个地图点会被许多相机观测到,因此在插入关键帧后,需要判断是否更新代表当前点的描述子,先获得当前点的所有描述子,然后计算描述子之间的两两距离,最好的描述子与其他描述子应该具有最小的距离中值。

二、函数步骤 

Step 1 获取该地图点所有有效的观测关键帧信息

Step 2 遍历观测到该地图点的所有关键帧,对应的orb描述子,放到向量vDescriptors中

Step 3 计算这些描述子两两之间的距离.

Step 4 选择最有代表性的描述子,它与其他描述子应该具有最小的距离中值

三、code 

void MapPoint::ComputeDistinctiveDescriptors()
{
    // Retrieve all observed descriptors
    vector<cv::Mat> vDescriptors;

    map<KeyFrame*,size_t> observations;

    // Step 1 获取该地图点所有有效的观测关键帧信息
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        if(mbBad)
            return;
        observations=mObservations;
    }

    if(observations.empty())
        return;

    vDescriptors.reserve(observations.size());

    // Step 2 遍历观测到该地图点的所有关键帧,对应的orb描述子,放到向量vDescriptors中
    for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    {
        // mit->first取观测到该地图点的关键帧
        // mit->second取该地图点在关键帧中的索引
        KeyFrame* pKF = mit->first;

        if(!pKF->isBad())        
            // 取对应的描述子向量                                               
            vDescriptors.push_back(pKF->mDescriptors.row(mit->second));     
    }

    if(vDescriptors.empty())
        return;

    // Compute distances between them
    // Step 3 计算这些描述子两两之间的距离
    // N表示为一共多少个描述子
    const size_t N = vDescriptors.size();
	
    // 将Distances表述成一个对称的矩阵
    // float Distances[N][N];
	std::vector<std::vector<float> > Distances;
	Distances.resize(N, vector<float>(N, 0));
	for (size_t i = 0; i<N; i++)
    {
        // 和自己的距离当然是0
        Distances[i][i]=0;
        // 计算并记录不同描述子距离
        for(size_t j=i+1;j<N;j++)
        {
            int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
            Distances[i][j]=distij;
            Distances[j][i]=distij;
        }
    }

    // Take the descriptor with least median distance to the rest
    // Step 4 选择最有代表性的描述子,它与其他描述子应该具有最小的距离中值
    int BestMedian = INT_MAX;   // 记录最小的中值
    int BestIdx = 0;            // 最小中值对应的索引
    for(size_t i=0;i<N;i++)
    {
        // 第i个描述子到其它所有描述子之间的距离
        // vector<int> vDists(Distances[i],Distances[i]+N);
		vector<int> vDists(Distances[i].begin(), Distances[i].end());
		sort(vDists.begin(), vDists.end());

        // 获得中值
        int median = vDists[0.5*(N-1)];
        
        // 寻找最小的中值
        if(median<BestMedian)
        {
            BestMedian = median;
            BestIdx = i;
        }
    }

    {
        unique_lock<mutex> lock(mMutexFeatures);
        mDescriptor = vDescriptors[BestIdx].clone();       
    }
}

四、函数解析 

        判断该地图点是否是bad地图点,若不是则获取这个地图点的所有观测信息用临时变量observations保存,它是个map<KeyFrame*,size_t>类型的变量。

        存储的该地图点可以被哪些关键帧KeyFrame观测到,在这些关键帧中的索引size_t是多少。

        遍历观测到该地图点的所有关键帧observations,对应的orb描述子,放到向量vDescriptors中。

        计算这些描述子的两两距离存储到矩阵Distances中。

        假设这里的矩阵是4*4的。

\begin{bmatrix} a_{11} & a_{12} &a_{13} &a_{14} \\ a_{21} & a_{22}& a_{23}&a_{24} \\ a_{31}& a_{32}& a_{33} &a_{34} \\ a_{41}& a_{42}& a_{43}& a_{44} \end{bmatrix}

         即观测到该地图点的帧有4个,取出它们四个的描述子,a_{11}=a_{22}=a_{33}=a_{44}=0,即第一个描述子和第一个描述子的距离为0(自己和自己比较当然为0),a_{12}=a_{21},它们的数值等于第一个描述子和第二个描述子的汉明距离。

        我们有了描述子矩阵后,我们遍历每一行描述子矩阵,寻找每一行的距离中值,拿第一行来说,a_{11} ~a_{12} ~a_{13} ~a_{14}的中位数,遍历所有行,找到最小行的中位数以及它的行索引。

        将这个地图点最具代表性的描述子设置为最小的行的中位数索引对应的描述子。

        

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

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

相关文章

毕业设计-微博评论文本情感分析,SVM+朴素贝叶斯+AdaBoost,含完整项目文档

基于AdaBoost算法的情感分析研究 完整代码及文档下载地址&#xff1a;毕业设计-微博评论文本情感分析 此项目为本科毕业设计项目&#xff0c;大家借鉴一下思路就好 大学时没有好好学算法&#xff0c;毕竟那些树、图实在提不起兴趣&#xff0c;好在毕业设计选择了个机器学习算…

rabbitmq基础9——流控、镜像队列

文章目录一、流控1.1 流控机制1.2 流控原理1.3 流控状态显示1.4 流控对象1.5 性能提升二、镜像队列2.1 机制原理2.1.1 集群结构2.2 镜像结构2.2.1 组播GM2.2.1.1 实现原理2.2.1.2 加入新节点2.2.1.3 节点宕机的影响2.3 配置镜像队列2.3.1 定义参数2.3.2 命令配置2.3.4 相关命令…

数字验证学习笔记——SystemVerilog芯片验证20 ——线程间的通信

一、线程间的通信 测试平台中的所有线程都需要同步并交换数据。一个线程需要等待另一个。多个线程可能同时访问同一个资源。线程之间可能需要交换数据。所有这些数据交换和同步称之为线程间的通信&#xff08;IPC&#xff09;。 1.1 event 事件 Verilog 中&#xff0c;一个线…

【好书推荐】车载以太网权威指南

20年后&#xff0c;会令你失望的不是做过的事&#xff0c;而是你没做过的&#xff0c;所以解开帆索&#xff0c;从安全的港湾出发&#xff0c;乘风而行&#xff0c;去探索、去梦想、去发现&#xff01; Twenty years from now you will be more disappointed by the things tha…

Linux系统 Ubuntu18.04安装的详细教程(提供18.04ubuntu镜像)

文章目录一、镜像安装二、vim更新 gcc ifconfig下载三、共享文件夹设置设置使用&#xff08;测试共享文件夹是否能使用&#xff0c;这步可以省略&#xff09;四、另外虚拟机名称全名、用户名镜像文件下载&#xff1a;链接&#xff1a;https://pan.baidu.com/s/12bEdRBwO1YbLt23…

数学杂谈:圆上随机落点问题(一)

数学杂谈&#xff1a;圆上随机落点问题&#xff08;一&#xff09; 1. 问题描述2. 问题解答 1. 解法一&#xff1a;递推2. 解法二&#xff1a;受限制的均匀分布3. 数值模拟验证 3. 讨论 & 扩展 1. 问题描述 这道题其实很早之前自己做过一遍&#xff0c;然后前阵子发现苏神…

【寒假每日一题】洛谷 P1079 [NOIP2012 提高组] Vigenère 密码

题目链接&#xff1a;P1079 [NOIP2012 提高组] Vigenre 密码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 16 世纪法国外交家 Blaise de Vigenre 设计了一种多表密码加密算法 Vigenre 密码。Vigenre 密码的加密解密算法简单易用&#xff0c;且破译难度比较高&…

类、对象与接口

前言 类、对象与接口 文章目录前言一、类与对象二、源文件声明的规则三、修饰符四、继承五、多态六、接口1、定义2、接口3、实现4、接口一、类与对象 类&#xff1a;定义一种全新的数据类型&#xff0c;包含一组变量&#xff08;数据&#xff09;和函数&#xff08;逻辑&#…

【django】各种关联关系的模型类设计

文章目录前言一、级联操作二、一对多&#xff08;多对一&#xff09;的关联模型类设计1、学生表模型类设计2、渠道表模型类设计三、多对多的关联模型类设计1、课程表模型类设计四、多对多的关联模型类设计&#xff08;自定义中间表&#xff09;1、模型类设计课程表模型类设计报…

神经网络的学习率如何选择?

文章目录学习率的概念学习率的选择方法参考资料学习率的概念 这里的学习率指的是深度学习神经网络训练过程中选取的一个超参数。 学习率作为参数更新时的一个乘数项&#xff0c;可以影响网络训练的速度&#xff0c;或者说是每次迈步的大小。 可以这样理解&#xff0c;如果学…

ZC706P+ADRV9009连接RADIOVERSE详解之二

上一个BLOG我们在WIN上安装了RADIOVERSE软件以及做好了SD卡映像。这篇文字我们记录ZC706ADRV9009硬件链接情况&#xff1a; 这里看到USB UART串口是可选的&#xff0c;主要是用来查看启动的系统log。 实际连接如下&#xff1a; 图中&#xff1a; 1&#xff0c;外接12V电源 2…

Python数据结构与算法篇(三)-- 队列的实现和应用

1 队列 1.1 简单队列 队列是一种有次序的数据集合&#xff0c;其特征是新数据项的添加总发生在一端&#xff08;通常称为“尾rear”端&#xff09;&#xff1b;而现存数据项的移除总发生在另一端&#xff08;通常称为“首front”端&#xff09;。当一个元素被加入到队列之后&a…

头歌作业之排序1、2、3、4

&#xff08;PS&#xff1a;直接拿的友友zy的&#xff09; 一个不知名大学生&#xff0c;江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2023.1.1 Last edited: 2023.1.1 目录 &#xff08;PS&#xff1a;直接拿的友友的&a…

SCI论文解读复现【NO.2】基于注意机制的YOLOv5改进算法在行星图像中的应用(代码已复现)

此前出了目标检测算法改进专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读发表高水平学术期刊中的SCI论文&am…

EMNLP22提示模板生成:GPS: Genetic Prompt Search for Efficient Few-shot Learning

GPS: Genetic Prompt Search for Efficient Few-shot Learning 1 简介 Genetic Prompt Search (GPS) 通过提示改进少样本学习&#xff0c;它利用遗传算法自动搜索高性能提示 遗传提示搜索 (GPS) 算法&#xff0c;该算法使用生成模型逐渐改变提示&#xff0c;并根据它们在小型…

C语言网刷题记录

作者&#xff1a;会敲代码的Steve 座右铭&#xff1a;博学笃志&#xff0c;切问静思。 大家好久不见啊&#xff0c;一看时间我已经好久没发文章了&#xff0c;最近在刷OJ题和学习&#xff1b;就没那么多心思把时间花在写文章上了&#xff0c;我对此感到很抱歉&#xff0c;本文呢…

int8,FLOPS,FLOPs,TOPS 等具体含义

1、定义 算力的计量单位FLOPS&#xff08;Floating-point operations per second&#xff09;&#xff0c;FLOPS表示每秒浮点的运算次数。具体使用时&#xff0c;FLOPS前面还会有一个字母常量&#xff0c;例如TFLOPS、PFLOPS。这个字母T、P代表次数&#xff0c;T代表每秒一万亿…

Linux学习笔记——MySQL数据库管理系统安装部署

5.1、MySQL数据库管理系统安装部署 5.1.1、简介 1、MySQL简介 MySQL数据库管理系统&#xff08;后续简称MySQL&#xff09;&#xff0c;是一款知名的数据库系统&#xff0c;其特点是&#xff1a;轻量、简单、功能丰富。 MySQL数据库可谓是软件行业的明星产品&#xff0c;无…

xilinx ZYNQ 7000 AXI GPIO

.0AXI GPIO 第一部分 PS 和 PL之间的通讯有一个接口称为AXI。AXI总线具体的内容这边不去深究&#xff0c;可以理解为一种特殊协议的通讯方式。 AXI GPIO是什么意思&#xff1f; PL是FPGA它可以做成任何你想要的东西&#xff0c;做一个GPIO外设当然是可以的。 如上图所示&…

DoIP协议从入门到精通——通信建立

在DoIP专栏中,关于DoIP文章,主要讲述从车辆物理连接、车辆声明、车辆通信激活(Routine Activation)和诊断通信几个步骤。 本文介绍了Tester与车辆获取物理连接、车辆声明自身信息后接下来需要操作的就是本文所要分享的内容:Tester与车辆控制器的通信建立。 一、通信模式…