ORB-SLAM 中使用了多种特征匹配的奇技淫巧,其中之一就是利用词袋信息 进行引导匹配SearchByBoW
:利用了BOW
里的正向引导进行两帧之间的匹配,核心点在于位于同一个节点处的特征才有可能属于同一匹配,相较于暴力匹配匹配速度更快。
注意:每幅图像都可以通过ComputeBoW
得到其对应的词袋向量。featureVector
存储的是节点的索引值以及对应图像feature对应的索引向量,即map<node_id,vector<featureID>
。这样的话就可以根据两帧图像的node_id
来初步确定二者共有的特征点,然后根据该id
取出vector<featureID>
,根据featureID找到图像上的特征点以及描述子,通过比较二者描述子距离来判定该特征点是否为匹配点,若距离小于某一阈值,则二者为匹配对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void Frame::ComputeBoW() { if (mBowVec.empty()) { vector <cv::Mat> vCurrentDesc = Converter::toDescriptorVector(mDescriptors); mpORBvocabulary->transform(vCurrentDesc,mBowVec,mFeatVec,4 ); } }
该函数在Tracking
线程中的TrackReferenceKeyFrame()
/Relocalization()
进行调用(注意:LoopClosing
线程中ComputeSim3()
也会调用该函数,与上述二者的区别在于,ComputeSim3()中的SearchByBoW是寻找关键帧之间的匹配,而非关键帧与当前帧之间的匹配)。
下面给出ORB-SLAM2
中用于关键帧与当前帧 进行词袋引导匹配的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 int ORBmatcher::SearchByBoW(KeyFrame* pKF,Frame &F, vector <MapPoint*> &vpMapPointMatches){ const vector <MapPoint*> vpMapPointsKF = pKF->GetMapPointMatches(); vpMapPointMatches = vector <MapPoint*>(F.N,static_cast <MapPoint*>(NULL )); const DBoW2::FeatureVector &vFeatVecKF = pKF->mFeatVec; int nmatches=0 ; vector <int > rotHist[HISTO_LENGTH]; for (int i=0 ;i<HISTO_LENGTH;i++) rotHist[i].reserve(500 ); const float factor = HISTO_LENGTH/360.0f ; DBoW2::FeatureVector::const_iterator KFit = vFeatVecKF.begin(); DBoW2::FeatureVector::const_iterator Fit = F.mFeatVec.begin(); DBoW2::FeatureVector::const_iterator KFend = vFeatVecKF.end(); DBoW2::FeatureVector::const_iterator Fend = F.mFeatVec.end(); while (KFit != KFend && Fit != Fend) { if (KFit->first == Fit->first) { const vector <unsigned int > vIndicesKF = KFit->second; const vector <unsigned int > vIndicesF = Fit->second; for (size_t iKF=0 ; iKF<vIndicesKF.size(); iKF++) { const unsigned int realIdxKF = vIndicesKF[iKF]; MapPoint* pMP = vpMapPointsKF[realIdxKF]; if (!pMP) continue ; if (pMP->isBad()) continue ; const cv::Mat &dKF= pKF->mDescriptors.row(realIdxKF); int bestDist1=256 ; int bestIdxF =-1 ; int bestDist2=256 ; for (size_t iF=0 ; iF<vIndicesF.size(); iF++) { const unsigned int realIdxF = vIndicesF[iF]; if (vpMapPointMatches[realIdxF]) continue ; const cv::Mat &dF = F.mDescriptors.row(realIdxF); const int dist = DescriptorDistance(dKF,dF); if (dist<bestDist1) { bestDist2=bestDist1; bestDist1=dist; bestIdxF=realIdxF; } else if (dist<bestDist2) { bestDist2=dist; } } if (bestDist1<=TH_LOW) { if (static_cast <float >(bestDist1)< mfNNratio*static_cast <float >(bestDist2)) { vpMapPointMatches[bestIdxF]=pMP; const cv::KeyPoint &kp = pKF->mvKeysUn[realIdxKF]; if (mbCheckOrientation) { float rot = kp.angle-F.mvKeys[bestIdxF].angle; if (rot<0.0 ) rot+=360.0f ; int bin = round(rot*factor); if (bin==HISTO_LENGTH) bin=0 ; assert(bin>=0 && bin<HISTO_LENGTH); rotHist[bin].push_back(bestIdxF); } nmatches++; } } } KFit++; Fit++; } else if (KFit->first < Fit->first) { KFit = vFeatVecKF.lower_bound(Fit->first); } else { Fit = F.mFeatVec.lower_bound(KFit->first); } } if (mbCheckOrientation) { int ind1=-1 ; int ind2=-1 ; int ind3=-1 ; ComputeThreeMaxima(rotHist,HISTO_LENGTH,ind1,ind2,ind3); for (int i=0 ; i<HISTO_LENGTH; i++) { if (i==ind1 || i==ind2 || i==ind3) continue ; for (size_t j=0 , jend=rotHist[i].size(); j<jend; j++) { vpMapPointMatches[rotHist[i][j]]=static_cast <MapPoint*>(NULL ); nmatches--; } } } return nmatches; }
另外,LoopClosing
线程中ComputeSim3()
调用的SearchByBoW
的函数声明为:1 int ORBmatcher::SearchByBoW(KeyFrame *pKF1, KeyFrame *pKF2, vector <MapPoint *> &vpMatches12)
参考链接
https://blog.csdn.net/qq_24893115/article/details/52629248