ORB_SLAM2::Initializer 用於單目情況下的初始化。
Initializer 的構造函數中傳入第一張影像,這張影像被稱作 reference frame(rFrame)。在獲得第二張影像時傳入第二張影像,這張影像被稱作 current frame(cFrame)。這一部分傳入的代碼可以在ORB_SLAM2::Tracking::MonocularInitialization()
中查看,要求 rFrame 與 cFrame 都至少具有 101 個特征點,而且 cFrame 與 rFrame 粗匹配結果不少於 100 個點對。這個粗匹配也很有意思,可以查看ORBmatcher::SearchForInitalization()
(粗匹配是對每一個 rFrame 的特征點選定一定大小的窗口,以該特征點在 rFrame 上的坐標為中心,在 cFrame 上提取出覆蓋網格內所有的特征點,計算 ORB 描述子的距離,距離夠小就說明是匹配點)。
Initializer::Initialize()
在這個函數中完成初始化。首先生成 RANSAC 需要用的最小子集的集合mvSets
。隨后開兩個線程同步進行FindHomography
和FindFundamental
,這兩個函數分別返回SH
、SF
這兩個數值用於判定是使用 H 作為初始模型更好,還是用 F 作為初始模型更好。
在用SH
、SF
判定是使用 H 還是 F 之后就是用 H (ReconstructH()
)或 F (ReconstructF()
)生成 R、t 和對應的可以三角化的點用於初始地圖生成。
ReconstructH()
是使用 Motion and structure from motion in a piecewise planar
environment 生成 8 種可能結果,再使用CheckRT()
確定是哪一種最為合適。
Initializer::FindHomography()
每次使用 8 個點通過 SVD 分解計算得到 H21。值得注意的是在進行 Homography 計算之前先進行歸一化過程(在函數Normalize()
中進行)。
Initializer::Normalize()
歸一化過程是將所有的 KeyPoints 進行一次 Affine Transformation,使得變換后的 KeyPoints 均值為原點 \(0\),方差為單位陣 \(I\)。
變換公式為:
歸一化的原因是計算出的 H 會依賴於特征點的位置,所以先歸一化再計算。(MVG Page 104)
歸一化的過程可以使用一個矩陣 \(T\) 表示:
后面的計算過程如下:
Initializer::ComputeH21()
在歸一化之后,使用歸一化的坐標計算 Homography。
沒啥好講,就是 Direct Linear Transformation,參考 MVG Page 88。
Initializer::CheckHomography()
用 H21 和 H12 分別將 rFrame(1) 中的特征點和 cFrame(2) 轉換到另一張影像中,計算匹配點的距離誤差,距離誤差轉換為卡方距離,卡方距離小於 5.991 說明顯著性為 5%,應該認為它們匹配成功,否則不成功將這一對匹配標記為 false。注意這里有兩個自由度。
https://en.wikipedia.org/wiki/Chi-squared_distribution#Table_of_.CF.872_values_vs_p-values
匹配成功能就能將於顯著性相關的數值加入到評分中,評分越高說明由這八個點計算出的 Homography 越正確。即由CheckHomography()
返回的評分currentScore
,取 RANSAC 中評分最高的 Homography 作為最終選定的 Homography。
這個 score 會被傳入Initialize()
函數中的 SH,用作計算 SH/(SH+SF),判斷是使用 Homography 還是 Fundamental。
Initializer::ReconstructH()
用函數FindHomography()
中 RANSAC 計算得到的 Homography 分解,分解能夠得到 8 種可能的 \(R, t\) 結果,用CheckRT()
判斷選擇哪一種結果。
好像這有點錯了吧,應該用所有的 inlier 匹配計算 Homography,再用這個更靠譜的 Homography 分解計算 \(R, t\)。
函數ReconstructH()
最后也輸出三角化成功的三維點。
Initializer::FindFundamental()
FindFundamental()
的計算過程與 FindHomography 類似,都是需要進行歸一化操作。
函數ComputeF21()
用八點法計算 Fundamental,計算得到的實際 Fundamental 通過設置最小特征值為 0 投影到 Fundamental 空間,作為輸出。
函數CheckFundamental()
是將點與線的距離作為誤差,計算卡方距離,注意這里有一個自由度,所以顯著性檢驗使用的卡方距離為 3.84。
都差不多,沒啥好說的。
Initializer::CheckRT()
這個函數挺重要的,因為分解 H 和 F 都會有很多可能的結果,使用這個函數能夠分辨出什么結果是靠譜的。
函數CheckRT()
接受 \(R, t\) ,一組成功的匹配。最后給出的結果是這組匹配中有多少匹配是能夠在這組 \(R, t\) 下正確三角化的(即 \(Z\) 都大於0),並且輸出這些三角化之后的三維點。
如果三角化生成的三維點 \(Z\) 小於等於0,且三角化的“前方交會角”(余弦是 cosParallax)不會太小,那么這個三維點三角化錯誤,舍棄。
通過了 \(Z\) 的檢驗,之后將這個三維點分別投影到兩張影像上,計算投影的像素誤差,誤差大於2倍中誤差,舍棄。
總結
ORB 里面對通過“最大值”確定的結果都非常小心。一般要求這個“最大值” outstanding,如 ORBmatcher 的構造函數中就有會傳入一個 (0,1) 的數值給成員變量 mfNNratio,只有最小距離小於次小距離的 mfNNratio 倍才能算是匹配成功,不允許出現相似的匹配,而取好那么一點點的匹配作為匹配結果。
在Initializer::ReconstructH()
中最后 8 個可能結果中,最好模型 inlier 數要大於次好模型 inlier 的 1/0.75 倍。