ORB_SLAM2修(Ru)仙(Keng)之路(一):重定位候选关键帧选取函数注释

本文详细解析了ORB_SLAM系统中关键帧数据库搜索算法的实现细节,介绍了如何从关键帧库中筛选出与当前帧最匹配的关键帧序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自从入了ORB_SLAM的坑以来,深感,在室外使用VO导航的艰辛,ORB_SLAM代码前后看了有一个月了,现在逐渐把一些函数的代码注释记录在这里,希望能给后面入坑的同志们些借鉴吧,当然自己也还有很多不明白的地方,所以,如果注释有错的,还请指出。

代码块

/**
 * 函数功能:从关键帧库中找出与当前帧匹配得最好的候选关键帧序列
 * 函数输入:当前帧
 * 函数输出:关键帧库中与当前帧匹配较好的候选关键帧序列
 * 几个变量含义:(1)mBowVec:BoW向量,里面存储的是从BoW词袋中查询到的“单词”
 * (2)mvInvertedFile:是一个向量,里面存放的是一个个单词,每个单词对应一个list链表,每个链表里存放的是拥有该单词的关键帧
 * 即,每一个单词都对应着所有看到该单词的关键帧
 * (3)pKFi->mnRelocWords:该关键帧与当前帧所共有的单词数
 * */
vector<KeyFrame*> KeyFrameDatabase::DetectRelocalizationCandidates(Frame *F)
{
    list<KeyFrame*> lKFsSharingWords;//与当前帧具有公共单词的所有关键帧

    {
        ///遍历该帧看到的所有单词
        unique_lock<mutex> lock(mMutex);
        for(DBoW2::BowVector::const_iterator vit=F->mBowVec.begin(), vend=F->mBowVec.end(); vit != vend; vit++)
        {
            list<KeyFrame*> &lKFs =   mvInvertedFile[vit->first];//找到这个单词所对应的所有关键帧
            ///遍历该单词的所有关键帧,并打上标签即:pKFi->mnRelocQuery=F->mnId,为了防止lKFsSharingWords中重复添加
            for(list<KeyFrame*>::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++)
            {
                KeyFrame* pKFi=*lit;
                if(pKFi->mnRelocQuery!=F->mnId)//为了不对同一个关键帧重复检测,这里打一个标签
                {
                    pKFi->mnRelocWords=0;
                    pKFi->mnRelocQuery=F->mnId;
                    lKFsSharingWords.push_back(pKFi);
                }
                pKFi->mnRelocWords++;//如果当前帧与该帧每共有一个单词,则加一
            }
        }
    }
    ///如果关键帧库里所有的关键帧与当前帧都没有公共单词,则返回空
    if(lKFsSharingWords.empty())
        return vector<KeyFrame*>();

    int maxCommonWords=0;//最大共有单词数量
    ///遍历所有与当前帧具有公共单词的关键帧,并找与当前帧具有的最大公共单词数
    for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    {
        if((*lit)->mnRelocWords>maxCommonWords)
            maxCommonWords=(*lit)->mnRelocWords;
    }

    int minCommonWords = maxCommonWords*0.8f;//最小共有单词数取最大共有单词数的0.8倍

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

    int nscores=0;

    ///找出共有单词数在minCommonWords与maxCommonWords之间的关键帧,作为“得分较高的关键帧”,
    /// 并且计算当前帧与该关键帧的得分,将得分与该关键帧组成pair存到lScoreAndMatch中
    for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++)
    {
        KeyFrame* pKFi = *lit;

        if(pKFi->mnRelocWords>minCommonWords)
        {
            nscores++;
            float si = mpVoc->score(F->mBowVec,pKFi->mBowVec);//比较两个vector向量的得分
            pKFi->mRelocScore=si;
            lScoreAndMatch.push_back(make_pair(si,pKFi));
        }
    }
    ///这一个应该是不会发生的,因为至少有一个关键帧与当前帧的共有单词数符合上边的阈值范围,就是共有单词数最多的那个关键帧
    if(lScoreAndMatch.empty())
        return vector<KeyFrame*>();

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

    ///遍历得分较高的关键帧所对应的10个最佳共视关键帧,这样lScoreAndMatch序列中“被共视”的越多的关键帧将越有可能被选为候选关键帧
    /// 注:这一块看的不是特别明白,如有错误请指出,谢谢
    for(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++)
    {
        KeyFrame* pKFi = it->second;
        vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);//获取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==NULL)//add by yuxi
                continue;
            if(pKF2->mnRelocQuery!=F->mnId)//如果该帧不在lKFsSharingWords中,则无须再处理
                continue;

            accScore+=pKF2->mRelocScore;//将pKFi的得分与它的共视关键帧得分累加
            if(pKF2->mRelocScore>bestScore)//如果共视关键帧的得分超过pKFi,则将pKFi替换掉
            {
                pBestKF=pKF2;
                bestScore = pKF2->mRelocScore;
            }
        }
        lAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));
        if(accScore>bestAccScore)
            bestAccScore=accScore;
    }

    ///将lAccScoreAndMatch accScore中满足阈值的得分作为候选关键帧,返回
    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;
        if(si>minScoreToRetain)
        {
            KeyFrame* pKFi = it->second;
            if(!spAlreadyAddedKF.count(pKFi))
            {
                vpRelocCandidates.push_back(pKFi);
                spAlreadyAddedKF.insert(pKFi);
            }
        }
    }

    return vpRelocCandidates;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值