ORB-SLAM2 ---- KeyFrameDatabase::DetectRelocalizationCandidates函数

news2024/11/23 15:26:14

目录

1.函数作用

2.步骤 

3.code 

4.函数解析 

4.1 找出和当前帧具有公共单词(word)的所有关键帧

4.2 统计上述关键帧中与当前帧F具有共同单词最多的单词数maxCommonWords,用来设定阈值1

4.3  遍历上述关键帧,挑选出共有单词数大于阈值1的及其和当前帧单词匹配得分存入lScoreAndMatch

4.4  计算lScoreAndMatch中每个关键帧的共视关键帧组的总得分,得到最高组得分bestAccScore,并以此决定阈值2

4.5  得到所有组中总得分大于阈值2的,组内得分最高的关键帧,作为候选关键帧组


1.函数作用

        用词袋找到与当前帧相似的候选关键帧。

2.步骤 

 * @brief 在重定位中找到与该帧相似的候选关键帧组
 * Step 1. 找出和当前帧具有公共单词的所有关键帧
 * Step 2. 只和具有共同单词较多的关键帧进行相似度计算
 * Step 3. 将与关键帧相连(权值最高)的前十个关键帧归为一组,计算累计得分
 * Step 4. 只返回累计得分较高的组中分数最高的关键帧
 * @param F 需要重定位的帧
 * @return  相似的候选关键帧数组

3.code 

vector<KeyFrame*> KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F)
{
    list<KeyFrame*> lKFsSharingWords;

    // Search all keyframes that share a word with current frame
    // Step 1:找出和当前帧具有公共单词(word)的所有关键帧
    {
        unique_lock<mutex> lock(mMutex);

        // mBowVec 内部实际存储的是std::map<WordId, WordValue>
        // WordId 和 WordValue 表示Word在叶子中的id 和权重
        for(DBoW2::BowVector::const_iterator vit=F->mBowVec.begin(), vend=F->mBowVec.end(); vit != vend; vit++)
        {
            // 根据倒排索引,提取所有包含该wordid的所有KeyFrame
            list<KeyFrame*> &lKFs = mvInvertedFile[vit->first];

            for(list<KeyFrame*>::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
            {
                KeyFrame* pKFi=*lit;
                // pKFi->mnRelocQuery起标记作用,是为了防止重复选取
                if(pKFi->mnRelocQuery!=F->mnId)
                {
                    // pKFi还没有标记为F的重定位候选帧
                    pKFi->mnRelocWords=0;
                    pKFi->mnRelocQuery=F->mnId;
                    lKFsSharingWords.push_back(pKFi);
                }
                pKFi->mnRelocWords++;
            }
        }
    }
    // 如果和当前帧具有公共单词的关键帧数目为0,无法进行重定位,返回空
    if(lKFsSharingWords.empty())
        return vector<KeyFrame*>();

    // Only compare against those keyframes that share enough words
    // Step 2:统计上述关键帧中与当前帧F具有共同单词最多的单词数maxCommonWords,用来设定阈值1
    int maxCommonWords=0;
    for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    {
        if((*lit)->mnRelocWords>maxCommonWords)
            maxCommonWords=(*lit)->mnRelocWords;
    }

    // 阈值1:最小公共单词数为最大公共单词数目的0.8倍
    int minCommonWords = maxCommonWords*0.8f;

    list<pair<float,KeyFrame*> > lScoreAndMatch;

    int nscores=0;

    // Compute similarity score.
    // Step 3:遍历上述关键帧,挑选出共有单词数大于阈值1的及其和当前帧单词匹配得分存入lScoreAndMatch
    for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    {
        KeyFrame* pKFi = *lit;

        // 当前帧F只和具有共同单词较多(大于minCommonWords)的关键帧进行比较
        if(pKFi->mnRelocWords>minCommonWords)
        {
            nscores++;  // 这个变量后面没有用到
            // 用mBowVec来计算两者的相似度得分
            float si = mpVoc->score(F->mBowVec,pKFi->mBowVec);
            pKFi->mRelocScore=si;
            lScoreAndMatch.push_back(make_pair(si,pKFi));
        }
    }

    if(lScoreAndMatch.empty())
        return vector<KeyFrame*>();

    list<pair<float,KeyFrame*> > lAccScoreAndMatch;
    float bestAccScore = 0;

    // Lets now accumulate score by covisibility
    // Step 4:计算lScoreAndMatch中每个关键帧的共视关键帧组的总得分,得到最高组得分bestAccScore,并以此决定阈值2
    // 单单计算当前帧和某一关键帧的相似性是不够的,这里将与关键帧共视程度最高的前十个关键帧归为一组,计算累计得分
    for(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
    {
        KeyFrame* pKFi = it->second;
        // 取出与关键帧pKFi共视程度最高的前10个关键帧
        vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);

        // 该组最高分数
        float bestScore = it->first; 
        // 该组累计得分
        float accScore = bestScore;  
        // 该组最高分数对应的关键帧
        KeyFrame* pBestKF = pKFi;   
        // 遍历共视关键帧,累计得分 
        for(vector<KeyFrame*>::iterator vit=vpNeighs.begin(), vend=vpNeighs.end(); vit!=vend; vit++)
        {
            KeyFrame* pKF2 = *vit;
            if(pKF2->mnRelocQuery!=F->mnId)
                continue;
            // 只有pKF2也在重定位候选帧中,才能贡献分数
            accScore+=pKF2->mRelocScore;

            // 统计得到组里分数最高的KeyFrame
            if(pKF2->mRelocScore>bestScore)
            {
                pBestKF=pKF2;
                bestScore = pKF2->mRelocScore;
            }

        }

        lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));

        // 记录所有组中最高的得分
        if(accScore>bestAccScore) 
            bestAccScore=accScore; 
    }

    // Return all those keyframes with a score higher than 0.75*bestScore
    // Step 5:得到所有组中总得分大于阈值2的,组内得分最高的关键帧,作为候选关键帧组
    //阈值2:最高得分的0.75倍
    float minScoreToRetain = 0.75f*bestAccScore; 
    set<KeyFrame*> spAlreadyAddedKF;
    vector<KeyFrame*> vpRelocCandidates;
    vpRelocCandidates.reserve(lAccScoreAndMatch.size());
    for(list<pair<float,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++)
    {
        const float &si = it->first;
        // 只返回累计得分大于阈值2的组中分数最高的关键帧
        if(si>minScoreToRetain)
        {
            KeyFrame* pKFi = it->second;
            // 判断该pKFi是否已经添加在队列中了
            if(!spAlreadyAddedKF.count(pKFi))
            {
                vpRelocCandidates.push_back(pKFi);
                spAlreadyAddedKF.insert(pKFi);
            }
        }
    }

    return vpRelocCandidates;
}

4.函数解析 

4.1 找出和当前帧具有公共单词(word)的所有关键帧

        因为我们要进行重定位,因此要找到先前的一帧和当前帧特征点匹配较多的。

        因此我们要找到和当前帧有相同特征点(描述子)的帧。

        mBowVec里面的第一维是该帧的特征点在ORB词典中的索引,我们根据倒排索引,得到和该帧的某一特征点共视的所有帧。

        mnRelocQuery标记是标记某一帧是哪个帧的重定位参考帧,遍历倒排索引,取出每一个与当前关键帧有共视的关键帧。

        如果这个帧还没有标记为当前帧的重定位关键帧(这个帧的mnRelocQuery不是当前待重定位关键帧 ),则置位mnRelocQuery为当前待重定位的关键帧,将mnRelocWords(和当前帧的共视程度)置为0。

        如果这个帧标记为当前帧的重定位关键帧了,则将共视程度mnRelocWords++。

        执行完这一步后我们得到了与当前待重定位帧的所有共视关键帧并且得到共视程度。

        这些帧被存放在lKFsSharingWords中。

4.2 统计上述关键帧中与当前帧F具有共同单词最多的单词数maxCommonWords,用来设定阈值1

        我们遍历lKFsSharingWords容器,统计和当前帧的最大共视次数存放在maxCommonWords,我们设置最小阈值minCommonWords(不超过这个阈值则抛弃关键帧)为0.8倍的maxCommonWords

4.3  遍历上述关键帧,挑选出共有单词数大于阈值1的及其和当前帧单词匹配得分存入lScoreAndMatch

        遍历lKFsSharingWords容器,挑选出共有单词数大于阈值1的及其和当前帧单词匹配得分存入lScoreAndMatch。我们遍历这个容器,对于每个关键帧,我们将这个帧和当前帧的共视程度和minCommonWords比对,若满足阈值,则记录共视地图点的相似得分记录在si中,将满足阈值的帧pkFi和得分si做成对组存储在lScoreAndMatch中。

4.4  计算lScoreAndMatch中每个关键帧的共视关键帧组的总得分,得到最高组得分bestAccScore,并以此决定阈值2

         我们遍历lScoreAndMatch对组,单单计算当前帧和某一关键帧的相似性是不够的,这里将与关键帧共视程度最高的前十个关键帧归为一组,计算累计得分。

        我们将lScoreAndMatch中的每个帧视为一组关键帧,我们取出lScoreAndMatch中的每个帧共视程度最高的前10个关键帧存入vpNeighs中,将该组的最高分数初始化为当前帧的scorebestScore,该组最高分数对应的关键帧设置为pBestKF,我们遍历所有共视关键帧(10帧中的每一帧)如果这帧是被标记了当前追踪候选帧,我们累加accScore的值,并统计这组中的分数最高的关键帧,更新变量pBestKF、bestScore

        在完成一次遍历后,我们添加这组中数最高的KeyFramepBestKF及这组的累计得分accScore放入lAccScoreAndMatch对组中。并记录所有组中最高得分bestAccScore

4.5  得到所有组中总得分大于阈值2的,组内得分最高的关键帧,作为候选关键帧组

        我们定义最后的阈值为上步中的累计得分最高的0.75倍(0.75f*bestAccScore

        我们创建帧的集合spAlreadyAddedKF,帧的容器vpRelocCandidates

        遍历lAccScoreAndMatch容器,取出得分与阈值判断,若大于阈值,且该关键帧没有添加到队列spAlreadyAddedKF中,则将该帧作为最终候选匹配关键帧并将其放入容器vpRelocCandidates中,返回给上层函数。

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

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

相关文章

JUC并发编程第五篇,如何优雅的使用线程中断机制和线程等待唤醒机制?

JUC并发编程第五篇&#xff0c;如何优雅的使用线程中断机制和线程等待唤醒机制&#xff1f;一、线程中断机制1. 什么是线程中断&#xff1f;2. 你知道 interrupt() 方法的含义吗&#xff1f;3. 如何使用中断标识优雅的停止线程&#xff1f;第一种&#xff1a;通过volatile变量实…

元年智答|数据洞察功能介绍

什么是数据洞察 随着企业积累数据量增多&#xff0c;数据分析师常常需要处理“长且宽”的数据集。依靠人的经验处理海量数据&#xff0c;从海量数据中发掘出有用的信息无异于大海捞针。虽然人工智能技术的普及和单位算力价格的下降大大降低了数据挖掘的门槛&#xff0c;但是面…

消息队列概述与扩展

一、消息队列的特性 与业务解藕&#xff1a;一个具有普适性质的消息队列组件不需要考虑上层的业务模型&#xff0c;只做好消息的分发就可以了&#xff0c;上层业务的不同模块反而需要依赖消息队列所定义的规范进行通信。FIFO&#xff1a;先投递先到达的保证是一个消息队列和一…

【HTML】猜拳小游戏

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录一、HTML完整源码二、效果三、完整资源文件一、HTML完整源码 <!DOCTYPE html PUBLIC "…

文本分类方案,飞浆PaddleNLP涵盖了所有

文章目录1.前言2.核心技术2.1 文本分类方案全覆盖2.1.1 分类场景齐全2.1.2 多方案满足定制需求方案一&#xff1a;预训练模型微调方案二&#xff1a;提示学习方案三&#xff1a;语义索引2.2 更懂中文的训练基座2.3 高效模型调优方案2.4 产业级全流程方案3. 快速开始4. 常用中文…

Photoshop、Illustrator、Sketch哪个更好

以前在交流组经常能看到大家争论哪个设计软件好&#xff1f;到底是你的吗&#xff1f;Illustrator好还是我的CorelDRAW或者他的Photoshop强大&#xff1f;但是跟着UI流行的设计&#xff0c;Sketch软件也加入了争论&#xff01;让我们和你分享一下这篇文章。让我们来看看平面设计…

云原生周刊 | AWS 开源 macOS 容器开发工具 Finch | 2022-11-28

今年的北美 KubeCon 大会结束后&#xff0c;来自 uptime.build 的 Jan Mundin 给会场的所有展台都拍了照&#xff0c;详细分析展台上的每一个单词&#xff0c;并汇总成了词云&#xff0c;其中热门词汇只有“安全”和“平台”&#xff0c;并不包含“自动化”和 DevOps。整个会场…

第四章 数字逻辑电路设计方法【Verilog】

第四章 数字逻辑电路设计方法【Verilog】前言推荐第四章 数字逻辑电路设计方法概览4.2 组合逻辑设计裁判表决电路方法1&#xff1a;真值表方式方法2&#xff1a;逻辑代数方式方法3&#xff1a;结构描述方式方法4&#xff1a;抽象描述方式测试结果4.2.1数字加法器2输入1 bit信号…

ATJ2157ATJ2127音乐按文件名拼音排序---标案是按内码进行排序

音乐按文件名拼音进行排序参考网站ATJ2157&ATJ2127 排序是按照内码(汉字为GBK即GBK936)排序的按拼音排序unicode与拼音的对比表(U2P.DAT)&#xff0c;需要打包到固件中U2P.DAT数据结构U2P.DAT生成代码是使用DEV-C生成其他说明U2P.DAT与ATJ2127平台代码参考网站 各种字符对…

springboot奥运会志愿者管理系统

当我知道奥运会志愿申请成功&#xff0c;也刚好是我的毕业&#xff0c;觉得自已需要做点什么&#xff0c;奥运会申请成功觉得自已去做一个志愿者&#xff0c;这样不断丰富了自已的经历&#xff0c;还能给自已在现实生活中上了一课&#xff0c;为了迎合志愿者需求&#xff0c;决…

SSM毕设项目 - 基于SSM的毕业设计管理系统(含源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.2.1 系统开发流程3.3.2 教师登录流程3.3.3 系统操作流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新…

经典Mysql入门必刷50题及全网最新最详细的笔记记录

文章目录Mysql50题练习题1练习题2练习题3练习题4练习题5练习题6练习题7练习题10练习题11练习题12练习题13练习题14练习题15练习题16练习题17练习题18练习题1919.按各科平均成绩进行排序&#xff0c;并显示排名练习题20练习题21练习题22练习题24练习题25练习题26.练习题27练习题…

代码随想录刷题| LeetCode 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II

目录 121. 买卖股票的最佳时机 思路 暴力解法 贪心算法 动态规划 买卖股票的最佳时机 贪心算法 动态规划 122.买卖股票的最佳时机II 思路 分析递推公式 买卖股票的最佳时机II 贪心算法 动态规划 121. 买卖股票的最佳时机 题目链接&#xff1a;力扣 思路 暴力解法 暴力解答会超…

3D视觉应用案例:法兰件/引擎盖/控制臂上料,轮毂抓取上架

法兰件上料 某大型汽配厂 项目背景 客户为某知名外资汽车零部件企业&#xff0c;其位于华东的工厂需求3D视觉实现喷砂机床的上料自动化。工件为板状多孔金属件&#xff0c; 厚度仅5mm&#xff0c;有序堆叠于深筐&#xff0c;需匹配喷砂机床高速上料作业。 作业流程 • 人工…

【抽样调查】CH3 分层随机抽样

目录 前言 一、概述 1.相关定义 &#xff08;1&#xff09;层 &#xff08;2&#xff09;分层抽样 2.分层随机抽样的步骤 3.分层抽样优于简单随机抽样的理由 4.分层原则 5.例 &#xff08;1&#xff09; &#xff08;2&#xff09; 6.符号 二、简单估计量及其性质 …

[附源码]Python计算机毕业设计Django大学生创新项目管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Briefings in bioinformatics2021 | QSAR模型中,传统表征要优于molecular embedding?

论文标题&#xff1a;Using molecular embeddings in QSAR modeling: does it make a difference? GitHub - VirginiaSabando/MolecularEmbeddings: Official site for "Using Molecular Embeddings in QSAR modeling: Does it Make a Difference?" (Briefings in…

uniapp组件传值的方法(父传子,子传父,对象传值)案例

文章目录前言父组件给子组件传值子组件给父组件传值父组件给父组件传对象值前言 最近看到uniapp组件传值的方法&#xff0c;这里记录一下&#xff0c;学过vue的应该都觉得很简单&#xff0c;传值的方法基本与vue的写法差不多 父组件给子组件传值 创建子组件comp.vue&#xf…

DDT+yaml实现数据驱动接口自动化

前言 在之前的文章中我们知道了yaml文件可以进行接口自动化。除了yaml文件&#xff0c;Excel文档也可以用来编写自动化测试用例。 一定很想知道这两者有什么区别吧&#xff1f; 1、Excel使用简单&#xff0c;维护难&#xff0c;多种数据类型转换起来比较复杂 2、yaml学习稍…

AVS3中的intra string copy(ISC)

AVS3是AVS系列的最新标准&#xff0c;其中新增了一些SCC工具&#xff0c;intra string copy(ISC)就是其中之一。下图1是AVS3的编码框架&#xff0c;其中橙色部分是ISC&#xff0c;可见ISC分为两个子模式FPSP和EUSP。 图1 AVS3编码框架 ISP是AVS3中新增的技术&#xff0c;它作用…