ORB_SLAM2源码:ORBmatcher.cc
??ORBmatcher.cc中的函數,主要實現(1)路標點和特征點的匹配(2D-3D點對)。(2)特征點和特征點的匹配(2D-2D點對)。SearchByProjection的函數重載看得我一臉懵逼。在這做一下筆記,以后可以參考參考。
??每個路標點會有一個自己的最優描述子。個人理解,這個最優描述子的含義應該是:一個路標點會對應多個特征點,先獲得所有特征點的描述子,然后計算描述子之間的兩兩距離,最好的描述子與其他描述子應該具有最小的距離中值。
匹配策略
??在匹配2D-2D點對,2D-3D點對時,常用的策略包括:
(1)比較描述子的漢明距離,選出最優的特征點(2D-2D、3D-3D)。
(2)使用詞袋加速匹配(2D-2D)。
??詞袋中包含單詞。每個單詞即使用聚類算法獲得的同一類的特征點的描述子。每幅圖像的每一個特征點都對應一個單詞。在兩幅圖像的單詞分布已知的情況下,如:
??圖像1:單詞1(包含50個特征點)、單詞2(包含100個特征點);
??圖像2:單詞1(包含60個特征點)、單詞2(包含90個特征點)。
??可以在每個單詞中去比較特征點,這樣只需比較50×60+100×90=12000次,遠小于150×150=22500。從而實現特征點的加速匹配。但這種方法會造成很多未匹配的特征點(比如選擇的兩個特征點間的漢明距離大于設置的閾值)。
約束條件
(1)相機坐標系下,z值應該大于0
(2)找到的特征點對間的漢明距離要小于閾值。
(3)找到的最優、次優特征點間的漢明距離應滿足一定的比例關系。
(4)相機坐標轉到像素坐標后,應該在圖像的范圍之內。
(5)路標點—光心間的長度應在一定范圍內。
(6)在旋轉直方圖中,只選出前3個直方圖中的特征點對。
旋轉直方圖:
??直方圖中存放的是找出的候選特征點的編號。
參考自知乎:https://zhuanlan.zhihu.com/p/267971447?utm_source=wechat_timeline
1)構建直方圖
??30個直方圖,每個直方圖的高(高,即存儲500個KeyPoint的索引)
2)計算KeyFrame1的KeyPoints和其對應KeyFrame2的KeyPoints的角度差。
??角度差為1~30之間的數,對應著30個直方圖,并將KeyFrame1中的KeyPoint索引值放入直方圖中。
??示例:角度差為100,那么100/30=3.3,四舍五入為3,應該將KeyFrame1中的KeyPoint索引值存入第3個直方圖中
3)篩選落在直方圖中索引值最多的3個直方圖:ComputeThreeMaxima
??最后取選擇上圖中最高的3個直方圖:(1)(2)(3)
?
?
SearchByProjection函數的重載
??SearchByProjection函數一共有4種重載。分別為局部地圖跟蹤,后一幀跟蹤前一幀,重定位中的跟蹤,回環檢測中的跟蹤。均是為了建立路標點與特征點間的聯系。
局部地圖跟蹤
int ORBmatcher::SearchByProjection(Frame &F, const vector<MapPoint*> &vpMapPoints, const float th)
流程為:
(1)遍歷有效的地圖點。
(2)設定搜索搜索窗口的大小。取決于視角, 若當前視角和路標點的平均視角夾角較小時, r取一個較小的值。
(3)通過投影點以及搜索窗口和預測的尺度進行搜索, 找出搜索半徑內的候選匹配點索引。
(4)尋找候選匹配點中的最佳和次佳匹配點。
(5)篩選最佳匹配點。
??建立局部地圖的路標點與當前幀的特征點間的聯系。流程如下:
?
當前幀追蹤上一幀
??將上一幀跟蹤的地圖點投影到當前幀,并且搜索匹配點。
int ORBmatcher::SearchByProjection(Frame &CurrentFrame, const Frame &LastFrame, const float th, const bool bMono)
流程為:
(1)建立旋轉直方圖,用于檢測旋轉一致性。
(2)計算當前幀和前一幀的平移向量。
(3)對于前一幀的每一個地圖點,通過相機投影模型,得到投影到當前幀的像素坐標。
(4)根據相機的前后前進方向來判斷搜索金字塔層的范圍。
(5)遍歷候選匹配點,尋找距離最小的最佳匹配點 。
(6)計算匹配點旋轉角度差所在的直方圖。
(7)進行旋轉一致檢測,剔除不一致的匹配。
?
重定位中的投影
??在重定位過程中,會首先使用詞袋算法加速特征點匹配,找到與當前幀F最相似的關鍵幀KF。建立起KF中的路標點和F中的特征點間的聯系。但這會使得很多匹配沒有被檢測到,因此還需將KF中的路標點投影到F中,進一步查找,以增加KF中的路標點和F中的特征點的匹配數量。
int ORBmatcher::SearchByProjection(Frame &CurrentFrame, KeyFrame *pKF, const set<MapPoint*> &sAlreadyFound, const float th , const int ORBdist)
(1)建立旋轉直方圖,用于檢測旋轉一致性。
(2)遍歷關鍵幀中的每個地圖點,通過相機投影模型,得到投影到當前幀的像素坐標。
(3)確定搜索半徑,獲得候選特征點。
(4)遍歷候選匹配點,尋找距離最小的最佳匹配點。
(5)計算匹配點旋轉角度差所在的直方圖。
(6)進行旋轉一致檢測,剔除不一致的匹配。
?
回環檢測時的投影
??首先使用詞袋加速算法,找到當前關鍵幀的閉環關鍵幀。但會有遺漏。
??此時已經找到了當前關鍵幀KFC的閉環關鍵幀KF(與KFC相似程度最高的關鍵幀)。將KF及其共視關鍵幀全部投影至KFC中,建立3D-2D聯系。
int ORBmatcher::SearchByProjection(KeyFrame* pKF, cv::Mat Scw, const vector<MapPoint*> &vpPoints, vector<MapPoint*> &vpMatched, int th)
流程為:
(1)分解Sim變換矩陣,獲得KF,KFC間的位姿變換關系。
(2)遍歷閉環KF及其共視KF的所有地圖點(不考慮當前KF已經匹配的地圖點)投影到當前KF。
(3)根據預測的路標點所在的金字塔層級獲得搜索半徑。搜索候選匹配特征點。
(4)遍歷候選匹配點,找到最佳匹配點。
(5)建立路標點與特征點的聯系。
?
?
詞袋模型加速匹配函數
詞袋算法的原理上面已經介紹了。建立的是當前幀的特征點和參考幀的路標點間的聯系。
??在后一幀追蹤前一幀、追蹤局部地圖時,不需要去尋找與當前幀最相似的一幀,因此無需使用。
??在回環檢測中,需要尋找當前關鍵幀的閉環關鍵幀。在重定位時,需要尋找與當前幀最相似的關鍵幀。此時使用詞袋加速算法,雖然會有很多遺漏的匹配,但可以快速的找到目標幀。
重定位中的詞袋加速
int ORBmatcher::SearchByBoW(KeyFrame* pKF,Frame &F, vector<MapPoint*> &vpMapPointMatches)
流程為:
(1)分別取出兩圖中屬于同一node的ORB特征點(只有屬于同一node,才有可能是匹配點)。
(2)遍歷KF中屬于該node的特征點。
(3)遍歷F中屬于該node的特征點,尋找最佳匹配點。
(4)根據漢明距離閾值和旋轉直方圖剔除誤匹配(關鍵幀和當前幀進行特征點匹配之后,已知兩個特征點的角度,從而可以獲得角度變化)。
?
回環檢測中的詞袋加速
int ORBmatcher::SearchByBoW(KeyFrame *pKF1, KeyFrame *pKF2, vector<MapPoint *> &vpMatches12)
流程與重定位中的流程相同。
?
?
檢測極線距離是否符合要求
bool ORBmatcher::CheckDistEpipolarLine(const cv::KeyPoint &kp1,const cv::KeyPoint &kp2,const cv::Mat &F12,const KeyFrame* pKF2)
??在已知基礎矩陣F的情況下,可獲得圖像1中的特征點,在圖像2中的極線方程。在已知基礎矩陣的情況下,用于檢測所匹配的特征點是否正確。
// Epipolar line in second image l2 = x1'F12 = [a b c]// Step 1 求出kp1在pKF2上對應的極線const float a = kp1.pt.x*F12.at<float>(0,0)+kp1.pt.y*F12.at<float>(1,0)+F12.at<float>(2,0);const float b = kp1.pt.x*F12.at<float>(0,1)+kp1.pt.y*F12.at<float>(1,1)+F12.at<float>(2,1);const float c = kp1.pt.x*F12.at<float>(0,2)+kp1.pt.y*F12.at<float>(1,2)+F12.at<float>(2,2);// Step 2 計算kp2特征點到極線l2的距離// 極線l2:ax + by + c = 0// (u,v)到l2的距離為: |au+bv+c| / sqrt(a^2+b^2)const float num = a*kp2.pt.x+b*kp2.pt.y+c;const float den = a*a+b*b;
?
?
單目初始化中的特征點匹配
??選第1幀作為參考,第2幀去匹配第一幀。如果匹配失敗的話,第3幀作為參考,第4幀去匹配。
int ORBmatcher::SearchForInitialization(Frame &F1, Frame &F2, vector<cv::Point2f> &vbPrevMatched, vector<int> &vnMatches12, int windowSize)
流程為:
(1)構建旋轉直方圖。
(2)在半徑窗口內搜索當前幀F2中所有的候選匹配特征點 。
(3)遍歷搜索搜索窗口中的所有潛在的匹配候選點,找到最優的和次優的。
(4)對最優次優結果進行檢查,滿足閾值、最優/次優比例,刪除重復匹配。
(5)計算匹配點旋轉角度差所在的直方圖,篩除旋轉直方圖中“非主流”部分。
(6)將最后通過篩選的匹配好的特征點保存。
?
?
局部建圖中的特征點匹配
??因為在local mapping線程中,關鍵幀的位姿已經相當準確了,即F12也是比較準確的。所以可以使用三角化生成新的MapPoint,匹配使用的是BoW,篩選部分使用了對極點鄰域剔除、極線約束、角度投票(旋轉一致性)進行剔除誤匹配。
int ORBmatcher::SearchForTriangulation(KeyFrame *pKF1, KeyFrame *pKF2, cv::Mat F12,vector<pair<size_t, size_t> > &vMatchedPairs, const bool bOnlyStereo)
(1)使用詞袋加速匹配,獲得匹配點對。
(2)使用特征點到極線的距離、旋轉直方圖剔除誤匹配。
回環檢測中尋找更多的匹配點
??在回環檢測時使用,考慮了尺度漂移,因此使用Sim3(Sim3有7自由度)。使用詞袋加速算法獲得的匹配點存在遺漏,因此對當前幀和回環幀中的ORB特征相互投影,從而找到更多的匹配點。
(1)遍歷KF1中的地圖點,如果該地圖點已經匹配(使用詞袋加速算法時已經匹配了),就跳過。
(2)轉換為KF2中的相機坐標、像素坐標。
(3)在搜索區域找到候選特征點。
(4)根據漢明距離,找到最優特征點。得到vnMatch1[i1]=bestIdx。其中i1為KF1中特征點的索引,bestIdx為在KF2中找到的特征點的索引。
(5)遍歷KF2中的地圖點,重復以上步驟,獲得vnMatch1[i2]=bestIdx。
(6)比較KF1中的特征點和KF2中的特征點是否相互索引。
int ORBmatcher::SearchBySim3(KeyFrame *pKF1, KeyFrame *pKF2, vector<MapPoint*> &vpMatches12,const float &s12, const cv::Mat &R12, const cv::Mat &t12, const float th)
路標點融合函數
??就是將未匹配的特征點投影至圖像中,進行路標點的融合
將路標點1投影至當前幀中,尋找與之匹配的特征點。
(1)若該特征點存在與之相連的路標點2,則在路標點1,路標點2中選擇被觀測次數最多的點。
(2)若該特征點沒有與之相連的路標點,則建立特征點與路標點1間的聯系。
int ORBmatcher::Fuse(KeyFrame *pKF, const vector<MapPoint *> &vpMapPoints, const float th)
總結
以上是生活随笔為你收集整理的ORB_SLAM2源码:ORBmatcher.cc的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三维刚体变化中Rcw,tcw的含义
- 下一篇: ORB_SLAM2程序入口(System