/函數的三要素是:函數返回值類型,函數名稱,函數參數
函數的返回值是裝有關鍵幀指針的vector
該函數是類KeyFrameDatabase的成員函數,函數名是DetectLoopCandidate
該函數的參數分別是KeyFrame類型的指針變量 pKF和最小得分vector<KeyFrame*> KeyFrameDatabase::DetectLoopCandidates(KeyFrame* pKF, float minScore)
{spConnectedKeyFrames是一個set定義的變量,set中裝的是在covisibility graph中與關鍵幀pKF相關聯的關鍵幀。GetConnectedKeyFrame()是類KeyFrame的成員函數,通過遍歷變量map變量 mConnectedKeyFrameWeights來得到關聯幀。map<KeyFrame*, int> mConnectedKeyFrameWeights;set 有自動排序功能,不能直接存取元素list不可以隨機存取元素set<KeyFrame*> spConnectedKeyFrames = pKF->GetConnectedKeyFrames();list<KeyFrame*> lKFsSharingWords;// Search all keyframes that share a word with current keyframes// Discard keyframes connected to the query keyframe{unique_lock<mutex> lock(mMutex);//遍歷pKF中所有生成的Bow向量for(DBoW2::BowVector::const_iterator vit=pKF->mBowVec.begin(), vend=pKF->mBowVec.end(); vit != vend; vit++){//在inverse indexes中查找該word都在哪些圖像中出現過list<KeyFrame*> &lKFs = mvInvertedFile[vit->first];//遍歷這些查找出來的與pKF有共視的word的關鍵幀for(list<KeyFrame*>::iterator lit=lKFs.begin(), lend= lKFs.end(); lit!=lend; lit++){//緊接著這一小段程序可以統計pKF與pKFi共視words的個數。//到了這里就是說pKF與pKFi有共視關系,但是并不是pKFi都可以被認為是閉環候選幀//只有當pKFi不是在covisibility graph中與pKF直接相連的關鍵幀才有機會入圍。KeyFrame* pKFi=*lit;//如果pKFi是第一次被pKF查詢,那么先初始化成員變量mnLoopwords為0//經判斷pKFi確實不與pKF直接相連則將成員變量mnLoopQuery設置為pKF的Id號碼//表示pKFi已經被pKF查詢過,下次再次查詢pKFi的時候//pKFi->mnLoopQuery = pKF->mnId 則直接讓 pKFi->mnLoopWords++;//并且將pKFi插入到lKFsSharingwords中去。if(pKFi->mnLoopQuery!=pKF->mnId){pKFi->mnLoopWords=0;if(!spConnectedKeyFrames.count(pKFi)){pKFi->mnLoopQuery=pKF->mnId;lKFsSharingWords.push_back(pKFi);}}pKFi->mnLoopWords++;}}}if(lKFsSharingWords.empty())return vector<KeyFrame*>();//IScoreAndMatch變量中與pKF有共視關系的關鍵幀以及兩者之間的得分//pair<float, KeyFrame>pair的使用是將兩者捆綁到一起存儲list<pair<float,KeyFrame*> > lScoreAndMatch;int maxCommonWords=0;//遍歷那些所有與pKF有共視關系又滿足條件的存儲在lKFsSharingWords中的關鍵幀for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++){//從上面的程序我們知道mnLoopWords變量中存儲了該關鍵幀與pKF的共視word數目//找到這些所有與pKF有共視關系的關鍵幀中與pKF共視word最大值 maxCommonWordsif((*lit)->mnLoopWords>maxCommonWords)maxCommonWords=(*lit)->mnLoopWords;}//但是我們如果要求這么嚴格,那滿足我們條件的關鍵幀真的是寥寥無幾啦,所以為了得到多一些的//閉環候選幀我們不得不降低要求,讓前20%的關鍵幀都能進入下一輪的比賽。//如果這個要求您都不能滿足的話,那對不起,您只能等下一次了。int minCommonWords = maxCommonWords*0.8f;int nscores=0;//再次遍歷lKFsSharingWords中存儲的所有與pKF有共視關系的關鍵幀for(list<KeyFrame*>::iterator lit=lKFsSharingWords.begin(), lend= lKFsSharingWords.end(); lit!=lend; lit++){//將每一個關鍵幀單獨拿出來,看一看他的mnLoopWords與minCommonWords的大小KeyFrame* pKFi = *lit;if(pKFi->mnLoopWords>minCommonWords){nscores++;//對于那些共視單詞數滿足條件的pKFi計算與pKF之間的BoW得分float si = mpVoc->score(pKF->mBowVec,pKFi->mBowVec);//mLoopScore目前的值是pKFi與pKF之間的Bow得分。pKFi->mLoopScore = si;//只有那些得分大于minScore的pKFi才可以留下第三關:Bow得分限制if(si>=minScore)lScoreAndMatch.push_back(make_pair(si,pKFi));}}if(lScoreAndMatch.empty())return vector<KeyFrame*>();list<pair<float,KeyFrame*> > lAccScoreAndMatch;float bestAccScore = minScore;// Lets now accumulate score by covisibility//遍歷所有上一貫留下的關鍵幀pKFifor(list<pair<float,KeyFrame*> >::iterator it=lScoreAndMatch.begin(), itend=lScoreAndMatch.end(); it!=itend; it++){//單獨拿出每一幀KeyFrame* pKFi = it->second;//查找在covisibility graph上與pKFi連接最密切的10個關鍵幀vector<KeyFrame*> vpNeighs = pKFi->GetBestCovisibilityKeyFrames(10);//bestScore初始化為pKFi與pKF之間的得分float bestScore = it->first;//這個累計得分accScore也被初始化為pKFi與pKF之間的得分float accScore = it->first;//而最佳幀選也初始化為pKFiKeyFrame* pBestKF = pKFi;//遍歷每一個pKFi的10個聯系最為密切的關鍵幀for(vector<KeyFrame*>::iterator vit=vpNeighs.begin(), vend=vpNeighs.end(); vit!=vend; vit++){KeyFrame* pKF2 = *vit;//如果在這10個關鍵幀中有之前被pKF查詢過(即有共視單詞),并且共視的單詞數還滿足//大于minCommonwords的要求if(pKF2->mnLoopQuery==pKF->mnId && pKF2->mnLoopWords>minCommonWords){//那么就要在原來pKFi與pKF得分的基礎上再加上pKFi的“好友”pKF2與pKF之間的得分accScore+=pKF2->mLoopScore;//殘忍的時刻到了,倘若pKF2與pKF之間的得分要比pKFi大,//pKF2就會超過pKFi pBestKF就成了pKF2了if(pKF2->mLoopScore>bestScore){pBestKF=pKF2;bestScore = pKF2->mLoopScore;}}}//現在存儲是從多個成員是11的小組內選擇出的與pKF得分最高的pBestKF以及累計得分accScorelAccScoreAndMatch.push_back(make_pair(accScore,pBestKF));//并且在所有的accScore中找到那個最大的得分bestAccScore.if(accScore>bestAccScore)bestAccScore=accScore;}//但是為了能夠得到多一些的閉環候選幀,需要降低要求,將那些上一關留下來分數靠前25%的關鍵幀//留下來float minScoreToRetain = 0.75f*bestAccScore;set<KeyFrame*> spAlreadyAddedKF;vector<KeyFrame*> vpLoopCandidates;vpLoopCandidates.reserve(lAccScoreAndMatch.size());//遍歷所有上一關留下的關鍵幀for(list<pair<float,KeyFrame*> >::iterator it=lAccScoreAndMatch.begin(), itend=lAccScoreAndMatch.end(); it!=itend; it++){//將那些上一關留下來分數靠前25%的關鍵幀留下來if(it->first>minScoreToRetain){KeyFrame* pKFi = it->second;//如果檢測到set中已經有pKFi了就不要重復插入了,其實這個判斷是多余的//set本來就具有值唯一性,不可以存入重復的值。if(!spAlreadyAddedKF.count(pKFi)){vpLoopCandidates.push_back(pKFi);spAlreadyAddedKF.insert(pKFi);}}}//最后終于得到了想要的關鍵幀,就想皇帝選妃子,需要層層選拔//可以走到這里的關鍵幀真的是過五關斬六將了//第一關:與pKF有共視單詞的pKF1,且不能是與pKF在covisibility graph中與pKF直接相連的//關鍵幀//第二關:共視單詞數必須大于minCommonWords的才可以留下 pKF2//第三關:pKF2中與pKF的BOw得分必須大于minScore的才可以留下 pKF3//第四關:pKF3要與自己最親密的“朋友”PK與pKF之間的共視單詞數,留下的記為pKF4//第五關:pKF4中那些與pKF得分大于minScoreToRetain的才可以最終留下來 記為pKF5;return vpLoopCandidates;
}
?