一豁翎、通俗易懂理解LocalMapping類==建圖(抓要點 切題 Done)
1.參考資料:
ORB SLAM2源碼解讀(十):LocalMapping類
[1] 深藍學(xué)院 視覺SLAM開源代碼論文帶讀(ORB_SLAM2)local mapping部分
2.主要函數(shù):
void LocalMapping::ProcessNewKeyFrame()
MapPointCulling();
CreateNewMapPoints()
SearchInNeighbors();
Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame, &mbAbortBA,
mpMap);
KeyFrameCulling();
二噪馏、[w1]通俗易懂理解插入關(guān)鍵幀LocalMapping::ProcessNewKeyFrame
1.插入關(guān)鍵幀做了什么,具體流程是什么(W1)
mpCurrentKeyFrame = mlNewKeyFrames.front();
mlNewKeyFrames.pop_front();
(1)從隊列中取出一個關(guān)鍵幀
(2)計算當(dāng)前關(guān)鍵幀的詞袋信息
(只要詞袋向量是空的或者特征點向量是空的启泣,將一幀的描述子轉(zhuǎn)成詞袋向量和特征向量,具體怎么轉(zhuǎn)的skip)
(3)獲取關(guān)鍵幀對應(yīng)的地圖點
對于每個地圖點粘姜,如果該地圖點不是isBad的話
如果地圖點不包含當(dāng)前關(guān)鍵幀的觀測形入,那么就1)添加地圖點觀測,包含當(dāng)前幀和當(dāng)前幀對應(yīng)的特征點id藕赞,2)更新地圖點的平均觀測方向和最大最小距離成肘,這里的參考關(guān)鍵幀是什么?3)更新地圖點的最佳描述子
(4)更新當(dāng)前關(guān)鍵幀的共視圖和生成樹
mpCurrentKeyFrame->UpdateConnections();
(5)將關(guān)鍵幀插入到地圖中
=========================================================================
題目:一個地圖點的參考關(guān)鍵幀是什么?一個地圖點的最大最小距離怎么算的斧蜕。平均觀測方向是什么双霍?
參考:源碼
思路:
1.思路:
參考關(guān)鍵幀:第一次觀測到該地圖點的關(guān)鍵幀。
平均觀測方向:地圖點的位置減去觀測到該地圖點的關(guān)鍵幀的位置的單位向量求和再求平均惩激。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
見上
要點程序:
其他:
=========================================================================
題目:什么叫共視圖
參考:
思路:
1.思路:
通俗易懂理解KeyFrame類問題 要點(要點切題 Done)
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
=========================================================================
題目:什么叫地圖點的最佳描述子
參考:
void MapPoint::ComputeDistinctiveDescriptors()
思路:
1.思路:
首先一個地圖被多幀觀測店煞,一個地圖點對應(yīng)每幀有一個特征點,他的描述子是怎樣的风钻,獲取多幀觀測的全部描述子集合顷蟀。然后計算一個距離矩陣,每一行每一列都是對應(yīng)的描述子骡技。然后取出每一行鸣个,得到這一行的距離中值(第i行就是第i個描述子和其他描述子的距離)羞反,比較全部行,得到最小的距離中值囤萤,對應(yīng)的第i行的描述子就是最佳的描述子昼窗。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
void function() {
vector<vector<float>> vDistances;
vDistances.resize(N, vector<float>(N, 0));
for (int i = 0;i < N; i++) {
vDistances[i][i] = 0;
for (int j = i + 1; j < N; j++) {
distanceij = DescriptorDistance(vDescriptor[i], vDescriptor[j]);
vDistances[i][j] = distanceij;
vDistances[j][i] = distanceij;
}
}
int best_dist = INT_MAX;
int best_idx;
for (int i = 0; i < N; i++) {
vector<int> vDistance(vDistances[i].begin(), vDistances[i].end());
sort(vDistance.begin(), vDistance.end());
int median_distance = vDistance[0.5 * (N - 1)];
if (median_distance < best_dist) {
best_dist = median_distance;
best_idx = i;
}
}
}
其他:
三、通俗易懂理解地圖點刪除LocalMapping::MapPointCulling()
2.刪除地圖點做了什么涛舍,具體流程是什么
RGBD或者雙目情況下ProcessNewKeyFrame產(chǎn)生的地圖點對觀測不夠的進行setBagFlag澄惊,另一種情況下是CreateNewMapPoints函數(shù)也有mlpRecentAddedMapPoints,產(chǎn)生的地圖點對觀測不夠的進行setBagFlag
setBagFlag就是刪除地圖點的觀測
=========================================================================
題目:ProcessNewKeyFrame中mlpRecentAddedMapPoints的push的條件
參考:
思路:
1.思路:
(1)RGBD或者雙目情況下,當(dāng)前關(guān)鍵幀生成的地圖點.這個地圖點會被當(dāng)前關(guān)鍵幀觀測到,
這個會push到mlpRecentAddedMapPoints富雅。
(2)單目情況下,關(guān)鍵幀的地圖點基本是NULL的情況,因為還沒3角化,會不會有匹配產(chǎn)生的地圖點呢掸驱?
會,但是也不會進入這個mlpRecentAddedMapPoints没佑。
單目情況下毕贼,地圖點沒有被當(dāng)前幀觀測到,需要添加當(dāng)前幀的觀測。
=========================================================================
題目:地圖點刪除函數(shù)void LocalMapping::MapPointCulling(地圖點刪除是對雙目和RGBD而言的)蛤奢。erase到底第什么意思鬼癣?和setBadFlag有什么區(qū)別?
參考:
思路:
1.思路:
setBadFlag到底干了啥?把mappoint所有觀測給剔除掉啤贩。得有觀測!!!
(1)pMP->GetFoundRatio() < 0.25f這是什么意思呢??? Found和Visible有什么區(qū)別呢???
found:
對單目來說待秃,在TrackLocalMap的Optimization后,如果當(dāng)前幀的地圖點不是outlier的話瓜晤,那就增加1锥余。由于當(dāng)前幀的MapPoints可以被當(dāng)前幀觀測到,所以其被觀測統(tǒng)計量+1
單目情況下痢掠,當(dāng)前幀的地圖點應(yīng)該是NULL的情況驱犹,如果匹配上了,該關(guān)鍵幀對應(yīng)的地圖點就不為NULL了足画, 他就有深度了雄驹。對的。
Visible:
在TrackLocalMap搜索局部地圖點Tracking::SearchLocalPoints()進行匹配的時候淹辞,
如果地圖點(局部地圖點和當(dāng)前幀的地圖點)在當(dāng)前幀的視野范圍內(nèi)医舆,那這個地圖點可見次數(shù)就+1.
(2)(((int)nCurrentKFid - (int)pMP->mnFirstKFid) >= 3) 這個是一個質(zhì)量很好的點。
卻要 erase掉象缀,這是什么回事?可以不erase蔬将,不影響。
因為這個函數(shù)void LocalMapping::MapPointCulling是為雙目和RGB-D服務(wù)的,如果是壞點的話央星,
(怎么判斷是否是外點霞怀,外點的話就沒有觀測了么?)
有觀測質(zhì)量不好是要剔除莉给,所以要setBadFlag
好的點直接erase,這是什么意思呢毙石?
mlpRecentAddedMapPoints push完廉沮,然后進行選擇,然后它后續(xù)用來干啥呢徐矩?后續(xù)沒有用到滞时,只是用來管理地圖點。
所以他的功能就是對觀測次數(shù)不滿足條件以及found/visible比例小的進行setbadflag
結(jié)論:雙目和RGB-D情況下滤灯,對觀測次數(shù)不滿足條件以及found/visible比例小的進行setbadflag坪稽。或者單目情況下CreateNewMapPoints產(chǎn)生的地圖點進行setbadflag力喷。
=========================================================================
題目:CreateNewMapPoints函數(shù)也有mlpRecentAddedMapPoints,那么什么時候再次調(diào)用MapPointCulling呢刽漂?
參考:
思路:
1.思路:
這個會在下一次中調(diào)用MapPointCulling把觀測不合格的地圖點setbagflag.
=========================================================================
題目:刪除的地圖點是在哪里引入的。
參考:
思路:
1.思路:
雙目和RGB-D下ProcessNewKeyFrame中mlpRecentAddedMapPoints
單目只有在CreateNewMapPoints中的mlpRecentAddedMapPoints
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
=========================================================================
題目:地圖點找到(mnFound)和可見(mnVisible)是什么意思弟孟?
參考:
思路:
1.思路:
mnFound:
void MapPoint::IncreaseFound(int n) {
unique_lock<mutex> lock(mMutexFeatures);
mnFound += n;
}
[1]在不考慮閉環(huán)的情況下,MapPoint_Replace函數(shù)不起作用样悟。
void MapPoint::Replace(MapPoint* pMP)
[2]IncreaseFound函數(shù)在Tracking中是什么情況下被調(diào)用的呢拂募?
<1>定位模式下。TODO暫不討論
<2>在TrackLocalMap的Optimization后窟她,如果當(dāng)前幀的地圖點不是outlier的話陈症,那就增加1。由于當(dāng)前幀的MapPoints可以被當(dāng)前幀觀測到震糖,其被觀測統(tǒng)計量加1录肯。單目情況下,當(dāng)前幀的地圖點應(yīng)該是NULL的情況吊说,如果匹配上了论咏,該關(guān)鍵幀對應(yīng)的地圖點就不為NULL了, 他就有深度了颁井。對的厅贪。
[3]結(jié)論:在TrackLocalMap的Optimization后,如果當(dāng)前幀的地圖點不是outlier的話雅宾,那就增加1养涮。由于當(dāng)前幀的MapPoints可以被當(dāng)前幀觀測到,所以其被觀測統(tǒng)計量+1
單目情況下眉抬,當(dāng)前幀的地圖點應(yīng)該是NULL的情況贯吓,如果匹配上了,該關(guān)鍵幀對應(yīng)的地圖點就不為NULL了蜀变, 他就有深度了悄谐。對的。那么相應(yīng)的這個地圖點就被當(dāng)前幀觀測到昏苏。
SearchByProjection
//保存結(jié)果: 為Frame中的特征點增加對應(yīng)的MapPoint
F.mvpMapPoints[bestIdx] = pMP;
mnVisible:
在TrackLocalMap搜索局部地圖點Tracking::SearchLocalPoints()進行匹配的時候尊沸,如果地圖點(局部地圖點和當(dāng)前幀的地圖點)在當(dāng)前幀的視野范圍內(nèi)威沫,那這個地圖點可見次數(shù)就+1.
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
=========================================================================
題目:關(guān)鍵幀id和幀id是不一樣的吧
參考:
思路:
是的,他們沒有繼承的關(guān)系洼专,各自有自己的id棒掠,都是連續(xù)的
KeyFrame構(gòu)造函數(shù)中:
// 獲取id
mnId = nNextId++;
1.思路:
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
=========================================================================
題目:從建立該地圖點開始,到目前為止經(jīng)過了3個關(guān)鍵幀還在屁商,為什么要放棄對該mappoint的檢測?
參考:
思路:
無所謂的烟很。
1.思路:
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
四、[射線][w1]通俗易懂理解地圖點創(chuàng)建LocalMapping::CreateNewMapPoints()
3.創(chuàng)建地圖點做了什么蜡镶,具體流程是什么
[1]找到當(dāng)前關(guān)鍵幀共視程度最強的20幀關(guān)鍵幀
[2]計算當(dāng)前關(guān)鍵幀和1個共視關(guān)鍵幀的基本矩陣
[3]通過極線約束限制匹配的搜索范圍雾袱,進行特征點的匹配[特征點對應(yīng)的地圖點是NULL]
[4]三角化生成地圖點
=========================================================================
題目:F21和F12各是什么意思,為什么是相反的官还。
參考:
思路:
1.思路:
F12:當(dāng)前幀1,另一個共視幀2芹橡,正向解算F12,
// Epipolar line in second image l = x1'F12 = [a b c]
// 求出kp1在pKF2上對應(yīng)的極線
bool ORBmatcher::CheckDistEpipolarLine(const cv::KeyPoint &kp1,
const cv::KeyPoint &kp2,
const cv::Mat &F12,
const KeyFrame *pKF2)
初始化部分:
F21是從幀1到幀2望伦,將幀1上的點投到幀2上
// Step 2.2 計算 img1 上的點在 img2 上投影得到的極線 l2 = F21 * p1 =
// (a2,b2,c2)
float Initializer::CheckFundamental(
const cv::Mat &F21, //當(dāng)前幀和參考幀之間的基礎(chǔ)矩陣
vector<bool> &vbMatchesInliers, //匹配的特征點對屬于inliers的標(biāo)記
float sigma)
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
// 需要好好理解!!!
/*
* 這里可以這樣理解:世界坐標(biāo)系原點記為W林说,關(guān)鍵幀1和關(guān)鍵幀2的相機光心分別記為O1
* O2. 根據(jù)Frame類中的有關(guān)說明,在世界坐標(biāo)系下 這兩幀相機光心的坐標(biāo)可以記為:
* O1=-Rw1*t1w
* O2=-RW2*t2w
* 那么 t12 本質(zhì)上描述的是從O2 ->
* O1相機光心所產(chǎn)生的位移屯伞,當(dāng)在世界坐標(biāo)系下的時候可以寫成: t12(w) = O2-O1 =
* -Rw2*t2w+Rw1*t1w
* 要放在O1坐標(biāo)系下表示的話腿箩,需要進行一個旋轉(zhuǎn)變換(注意不要有平移變換,這個是對點才用的劣摇,如果對向量也應(yīng)用的話很明顯t12的長度都變了)
* t12(1) = R1w*t12(w)
* = -R1w*Rw2*t2w+Rw1*R1w*t1w
* = -R1w*Rw2+t2w+t1w
* 就是下面這行代碼中寫的:
*/
要點程序:
基本矩陣的構(gòu)造
// 根據(jù)兩關(guān)鍵幀的姿態(tài)計算兩個關(guān)鍵幀之間的基本矩陣
cv::Mat LocalMapping::ComputeF12(KeyFrame *&pKF1, KeyFrame *&pKF2) {
// 先構(gòu)造兩幀之間的R12,t12
cv::Mat R1w = pKF1->GetRotation();
cv::Mat t1w = pKF1->GetTranslation();
cv::Mat R2w = pKF2->GetRotation();
cv::Mat t2w = pKF2->GetTranslation();
cv::Mat R12 = R1w * R2w.t();
/*
* 這里可以這樣理解:世界坐標(biāo)系原點記為W珠移,關(guān)鍵幀1和關(guān)鍵幀2的相機光心分別記為O1
* O2. 根據(jù)Frame類中的有關(guān)說明,在世界坐標(biāo)系下 這兩幀相機光心的坐標(biāo)可以記為:
* O1=-Rw1*t1w
* O2=-RW2*t2w
* 那么 t12 本質(zhì)上描述的是從O2 ->
* O1相機光心所產(chǎn)生的位移末融,當(dāng)在世界坐標(biāo)系下的時候可以寫成: t12(w) = O2-O1 =
* -Rw2*t2w+Rw1*t1w
* 要放在O1坐標(biāo)系下表示的話钧惧,需要進行一個旋轉(zhuǎn)變換(注意不要有平移變換,這個是對點才用的滑潘,如果對向量也應(yīng)用的話很明顯t12的長度都變了)
* t12(1) = R1w*t12(w)
* = -R1w*Rw2*t2w+Rw1*R1w*t1w
* = -R1w*Rw2+t2w+t1w
* 就是下面這行代碼中寫的:
*/
cv::Mat t12 = -R1w * R2w.t() * t2w + t1w;
// 得到 t12 的反對稱矩陣
cv::Mat t12x = SkewSymmetricMatrix(t12);
const cv::Mat &K1 = pKF1->mK;
const cv::Mat &K2 = pKF2->mK;
// Essential Matrix: t12叉乘R12
// Fundamental Matrix: inv(K1)*E*inv(K2)
return K1.t().inv() * t12x * R12 * K2.inv();
}
void Initializer::FindFundamental(vector<bool> &vbMatchesInliers, float &score,
cv::Mat &F21)
//F21:從參考幀到當(dāng)前幀的基礎(chǔ)矩陣
//從F恢復(fù)R t
bool Initializer::ReconstructF(
vector<bool> &vbMatchesInliers, //匹配好的特征點對的Inliers標(biāo)記
cv::Mat &F21, //從參考幀到當(dāng)前幀的基礎(chǔ)矩陣
cv::Mat &K, //相機的內(nèi)參數(shù)矩陣
cv::Mat &R21, //計算好的相機從參考幀到當(dāng)前幀的旋轉(zhuǎn)
cv::Mat &t21, //計算好的相機從參考幀到當(dāng)前幀的平移
vector<cv::Point3f> &vP3D, //三角化測量之后的特征點的空間坐標(biāo)
vector<bool> &vbTriangulated, //某個特征點是否被三角化了的標(biāo)記
float minParallax, //認(rèn)為三角化測量有效的最小視差角
int minTriangulated) //認(rèn)為使用三角化測量進行數(shù)據(jù)判斷的最小測量點數(shù)量
=========================================================================
題目:如何利用極線約束進行特征點匹配
參考:
int ORBmatcher::SearchForTriangulation(
KeyFrame *pKF1, KeyFrame *pKF2, cv::Mat F12,
vector<pair<size_t, size_t> > &vMatchedPairs, const bool bOnlyStereo)
思路:
1.思路:
PS:我認(rèn)為是像素垢乙。
// 檢查極線距離是否符合要求,用在初始化時根據(jù)兩個初始關(guān)鍵幀計算地圖點的時候
bool ORBmatcher::CheckDistEpipolarLine(const cv::KeyPoint &kp1,
const cv::KeyPoint &kp2,
const cv::Mat &F12,
const KeyFrame *pKF2)
越上層追逮,分辨率越低,不確定性范圍越大粹舵。
總結(jié):將pKF1圖像的每個特征點與pKF2圖像同一node節(jié)點的所有特征點依次檢測钮孵,判斷是否滿足對極幾何約束(點到極線的距離,小于設(shè)定的閾值)眼滤,滿足約束就是匹配的特征點巴席,找到滿足對極約束并且描述子之間的距離最小的建立匹配對。然后利用旋轉(zhuǎn)直方圖去除誤匹配诅需。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
=========================================================================
題目: 如何三角化建立地圖點呢漾唉?
參考:
第6講 視覺前端(切題 Done) TODO
思路:
1.思路:
射線公式:
兩條射線的夾角大于3.6度
三角化知識荧库,參考第6講 視覺前端(切題 Done) TODO
一個用的是投影矩陣,一個是用變換矩陣赵刑,一模一樣分衫。
[1]生成的3D點是否在2幀前方,不在的話就放棄這個點
[2]計算3D點在當(dāng)前關(guān)鍵幀下的重投影誤差
[3]計算3D點在另一個關(guān)鍵幀下的重投影誤差
[4]計算距離的連續(xù)性,(沒有太明白般此,經(jīng)驗吧蚪战,TODO)
[5]增加地圖點,計算地圖點最佳描述子铐懊,計算地圖點平均方向和最大最小距離邀桑。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
五、[背][w1]通俗易懂理解地圖點融合LocalMapping::SearchInNeighbors()
關(guān)鍵是:地圖點和特征點匹配上了科乎,地圖點添加觀測和關(guān)鍵幀添加地圖點壁畸。
=========================================================================
題目:創(chuàng)建地圖點之后,如何進行地圖點融合喜喂?
參考:
思路:
1.思路:
[1]找到當(dāng)前關(guān)鍵幀共視程度最強的20幀相鄰幀
// Extend to some second neighbors
const vector<KeyFrame *> vpSecondNeighKFs =
pKFi->GetBestCovisibilityKeyFrames(5);
[2]Extend to some second neighbors
存入一級和對應(yīng)的二級相鄰幀(就是一級的共視關(guān)鍵幀5幀)瓤摧。
[3]對于當(dāng)前幀的地圖點和每一個關(guān)鍵幀。
將MapPoints往當(dāng)前幀投影玉吁,
投影的步驟:
地圖點是不是在該關(guān)鍵幀前面,地圖點是不是在該關(guān)鍵幀視野范圍內(nèi)腻异,是否在地圖點的最大最小范圍內(nèi)进副,是否和平均觀測方向夾角小于60度
匹配的步驟:
根據(jù)地圖點的尺度確定在關(guān)鍵幀上的搜索范圍,獲取地圖點的匹配集合悔常,距離小于閾值的前提下描述子距離最小得到匹配點影斑。
如果地圖點和當(dāng)前幀的特征點匹配上了:
<1>如果地圖點和當(dāng)前關(guān)鍵幀的特征點匹配上的話,那就那就先看這個特征點對應(yīng)的地圖點是不是為空
<2>如果關(guān)鍵幀的特征點有地圖點的話机打,那么看那個地圖點的觀測次數(shù)較多矫户,多的替換少的。
<3>如果關(guān)鍵幀的特征點對應(yīng)的地圖點為NULL的話残邀,那么地圖點添加觀測皆辽,關(guān)鍵幀添加地圖點。
[4]上面是當(dāng)前幀的地圖點和每一個關(guān)鍵幀進行融合芥挣。
現(xiàn)在是每一個關(guān)鍵幀的地圖點和當(dāng)前幀進行融合驱闷。
[5]更新當(dāng)前幀MapPoints的描述子,深度空免,觀測方向和最大最小距離空另。
[6]更新當(dāng)前幀的covisibility圖。更新共視的關(guān)鍵幀和對應(yīng)的權(quán)重蹋砚。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
其他:
=========================================================================
題目:地圖點進行替換扼菠,替換的信息包含什么呢摄杂?
參考:
int ORBmatcher::Fuse(KeyFrame *pKF, const vector<MapPoint *> &vpMapPoints,
const float th)
思路:
1.思路:
[1]如果地圖點和當(dāng)前關(guān)鍵幀的特征點匹配上的話,那就那就先看這個特征點對應(yīng)的地圖點是不是為空
[2]如果關(guān)鍵幀的特征點有地圖點的話循榆,那么看那個地圖點的觀測次數(shù)較多析恢,多的替換少的。
<1>如果要的地圖點不包含該幀的觀測冯痢,那么該幀替換地圖點,地圖點添加該幀觀測
<2>如果要的地圖點包含該幀的觀測氮昧,那么就有沖突了,那么把該幀的地圖點置為NULL浦楣。
[3]如果關(guān)鍵幀的特征點對應(yīng)的地圖點為NULL的話袖肥,那么地圖點添加觀測,關(guān)鍵幀添加地圖點振劳。
=========================================================================
題目:local BA做了什么椎组,具體流程是什么
參考:
思路:
1.思路:
當(dāng)前幀相連的局部關(guān)鍵幀和對應(yīng)局部地圖點的LocalBA
lLocalKeyFrames:當(dāng)前關(guān)鍵幀和當(dāng)前關(guān)鍵幀的共視關(guān)鍵幀。
lLocalMapPoints:當(dāng)前關(guān)鍵幀和當(dāng)前關(guān)鍵幀的共視關(guān)鍵幀對應(yīng)的地圖點历恐。
對于有一些關(guān)鍵幀寸癌,能觀測到該地圖點lLocalMapPoints,但是不屬于lLocalKeyFrames弱贼,把它設(shè)置為lFixedCameras蒸苇。
[1]添加位姿頂點,其中第一關(guān)鍵幀不優(yōu)化
[2]添加不優(yōu)化的位姿頂點
[3]添加地圖點,對地圖點進行邊緣化吮旅,對于每一個地圖點的觀測溪烤,建立邊
<1>設(shè)置信息矩陣,權(quán)重為地圖點對應(yīng)金字塔層尺度因子權(quán)重的倒數(shù)庇勃,進行去量綱
<2>使用魯棒核函數(shù)去除外點
<3>添加邊
[4]第一階段優(yōu)化槐壳,迭代5次
[5]對于誤差太大酸舍,不優(yōu)化呼畸。第二階段屬于精求解嘿期,所以不使用魯棒核函數(shù)。
[6]第二階段罕拂,優(yōu)化10次揍异。
[7]對于誤差太大的,去除關(guān)鍵幀和地圖點的邊聂受。關(guān)鍵幀移除地圖點蒿秦,地圖點移除關(guān)鍵幀的觀測。
[8]更新關(guān)鍵幀的位姿蛋济,更新地圖點的位置和平均觀測方向棍鳖、最大最小距離。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
其他:
=========================================================================
題目:初始關(guān)鍵幀,要鎖住位姿不優(yōu)化渡处,為什么?
參考:第 5 講 后端優(yōu)化實踐:逐行手寫求解器 要點(切題 Done)
思路:
1.思路:
為了限定優(yōu)化值不亂飄镜悉,那么代碼如何實現(xiàn),添加超強先驗医瘫,H矩陣巨大侣肄,使得
為0,或者讓雅克比矩陣為0醇份,那么
稼锅,所以
為0。
六僚纷、[背][w1]通俗易懂理解LocalMapping::LocalBundleAdjustment
=========================================================================
題目:local BA做了什么矩距,具體流程是什么
參考:
思路:
1.思路:
當(dāng)前幀相連的局部關(guān)鍵幀和對應(yīng)局部地圖點的LocalBA
lLocalKeyFrames:當(dāng)前關(guān)鍵幀和當(dāng)前關(guān)鍵幀的共視關(guān)鍵幀。
lLocalMapPoints:當(dāng)前關(guān)鍵幀和當(dāng)前關(guān)鍵幀的共視關(guān)鍵幀對應(yīng)的地圖點怖竭。
對于有一些關(guān)鍵幀锥债,能觀測到該地圖點lLocalMapPoints,但是不屬于lLocalKeyFrames痊臭,把它設(shè)置為lFixedCameras哮肚。
[1]添加位姿頂點,其中第一關(guān)鍵幀不優(yōu)化
[2]添加不優(yōu)化的位姿頂點
[3]添加地圖點,對地圖點進行邊緣化广匙,對于每一個地圖點的觀測允趟,建立邊
<1>設(shè)置信息矩陣,權(quán)重為地圖點對應(yīng)金字塔層尺度因子權(quán)重的倒數(shù)鸦致,進行去量綱
<2>使用魯棒核函數(shù)去除外點
<3>添加邊
[4]第一階段優(yōu)化拼窥,迭代5次
[5]對于誤差太大,不優(yōu)化蹋凝。第二階段屬于精求解,所以不使用魯棒核函數(shù)总棵。
[6]第二階段鳍寂,優(yōu)化10次。
[7]對于誤差太大的情龄,去除關(guān)鍵幀和地圖點的邊迄汛。關(guān)鍵幀移除地圖點,地圖點移除關(guān)鍵幀的觀測骤视。
[8]更新關(guān)鍵幀的位姿鞍爱,更新地圖點的位置和平均觀測方向、最大最小距離专酗。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
其他:
=========================================================================
題目:初始關(guān)鍵幀睹逃,要鎖住位姿不優(yōu)化,為什么?
參考:第 5 講 后端優(yōu)化實踐:逐行手寫求解器 要點(切題 Done)
思路:
1.思路:
為了限定優(yōu)化值不亂飄,那么代碼如何實現(xiàn)沉填,添加超強先驗疗隶,H矩陣巨大,使得為0翼闹,或者讓雅克比矩陣為0斑鼻,那么
,所以
為0猎荠。
七坚弱、[背誦][w1]通俗易懂理解關(guān)鍵幀刪除LocalMapping::KeyFrameCulling
=========================================================================
題目:關(guān)鍵幀刪除的原則
參考:
思路:
1.思路:
進來很容易,要留下來就很難关摇。[寬進嚴(yán)留]
[1]得到當(dāng)前關(guān)鍵幀對應(yīng)的共視關(guān)鍵幀荒叶。
[2]對于每一個共視關(guān)鍵幀。某個關(guān)鍵幀對應(yīng)的地圖點拒垃,該地圖點的觀測次數(shù)大于3次停撞,這樣的地圖點,它的數(shù)量若大于該幀對應(yīng)的地圖點數(shù)量的90%悼瓮,那么這個關(guān)鍵幀就是冗余的戈毒,可以刪除該關(guān)鍵幀。
PS:ORBSLAM中加了一些策略横堡,但是整體是這樣的埋市。
策略是:當(dāng)前關(guān)鍵幀對應(yīng)的特征點有一個層數(shù),要求地圖點的其他觀測命贴,它對應(yīng)的特征點的金字塔層數(shù)應(yīng)該小于當(dāng)前關(guān)鍵幀對應(yīng)的特征點的層數(shù)道宅,也就是說要遠一點。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
=========================================================================
題目:如何刪除關(guān)鍵幀
參考:
通俗易懂理解KeyFrame類問題 要點(切題 Done)
思路:
1.思路:
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
八胸蛛、[w1]通俗易懂理解KeyFrame類問題 要點(要點切題 Done)
參考
主要有3大類函數(shù):
管理關(guān)鍵幀和MapPoint之間關(guān)系的函數(shù)
管理共視關(guān)系的函數(shù)
管理生成樹的函數(shù)
=========================================================================
題目:什么叫共視圖
參考:void KeyFrame::UpdateConnections()
思路:
1.思路:
KeyFrame為關(guān)鍵幀污茵,關(guān)鍵幀之所以存在是因為優(yōu)化需要,所以關(guān)鍵幀所有的內(nèi)容都是為優(yōu)化服務(wù)的葬项。
圖優(yōu)化需要構(gòu)建節(jié)點和邊泞当,節(jié)點有關(guān)鍵幀的位姿,邊民珍,第一種邊是關(guān)鍵幀和MapPoint之間的襟士,第二種邊是和其他關(guān)鍵幀之間的,他們之間需要通過MapPoint產(chǎn)生聯(lián)系嚷量,兩幀能共同觀測到一定數(shù)量的MapPoint可以在他倆之間建立邊陋桂,這種通過共視關(guān)系建立的模型叫 covisibility graph。
covisibility graph:每個關(guān)鍵幀是一個節(jié)點蝶溶,如果兩個關(guān)鍵幀之間的共視地圖點數(shù)量大于15嗜历,則在這兩個節(jié)點之間建立邊,邊的權(quán)重是共視地圖點的數(shù)量。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
map<KeyFrame*, int> KFCounter;
=========================================================================
題目:什么叫本質(zhì)圖秸脱,為什么存在落包,怎么用?
參考:
思路:
1.思路:
大范圍的話摊唇,計算量會很大,簡版就是essential graph,通過spanning tree來管理關(guān)鍵幀之間的關(guān)系咐蝇。每個幀都有一個父節(jié)點和多個子節(jié)點,節(jié)點為其他關(guān)鍵幀巷查,在構(gòu)建優(yōu)化模型的時候有序,只有具有父子關(guān)系的關(guān)鍵幀之間才建立邊,換句話說岛请,essential graph就是covisibility graph的子集旭寿,大大減小邊的數(shù)量,從而減小計算量崇败。
covisibility graph:每個關(guān)鍵幀是一個節(jié)點盅称,如果兩個關(guān)鍵幀之間的共視地圖點數(shù)量大于15,則在這兩個節(jié)點之間建立邊后室,邊的權(quán)重是共視地圖點的數(shù)量
spanning tree:保留所有的關(guān)鍵幀缩膝,給每一個關(guān)鍵幀找了1個父節(jié)點和多個子節(jié)點,每幀只跟自己的父節(jié)點和子節(jié)點相連岸霹,與其他幀不連接
essential graph:根據(jù)spanning tree建立的圖模型疾层,就是簡版的covisibility graph
spanning tree、essential graph
其中子節(jié)點可能有多個贡避,因為有一個容器mspChildrens痛黎,父節(jié)點只能有一個,因為有一個變量mpParent
當(dāng)前關(guān)鍵幀的父節(jié)點就是和當(dāng)前關(guān)鍵幀共視強度最強的刮吧。
本質(zhì)圖存在的意義是為全局優(yōu)化服務(wù)的湖饱。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
mpParent = mvpOrderedConnectedKeyFrames.front();
// 建立雙向連接關(guān)系
mpParent->AddChild(this);
=========================================================================
題目:local mapping中如何刪除關(guān)鍵幀
參考:void KeyFrame::SetBadFlag()
// 刪除和該幀相關(guān)的所有連接關(guān)系
void KeyFrame::SetBadFlag()
// 刪除當(dāng)前關(guān)鍵幀和指定關(guān)鍵幀之間的共視關(guān)系
void KeyFrame::EraseConnection(KeyFrame *pKF)
思路:
1.思路:
[1]當(dāng)前關(guān)鍵幀有很多共視的關(guān)鍵幀,這些共視關(guān)鍵幀中的每一幀杀捻,從它的共視關(guān)鍵幀中琉历,erase當(dāng)前幀的聯(lián)系。
[2]當(dāng)前幀對應(yīng)的地圖點水醋,這些地圖點把當(dāng)前幀從觀測中erase。如果當(dāng)前幀是地圖點的參考關(guān)鍵幀(即觀測到該地圖點的第一個關(guān)鍵幀)彪置,重新給地圖點指定參考關(guān)鍵幀拄踪。如果地圖點觀測的數(shù)量太少,那么把地圖點給刪除[詳細見通俗易懂理解MapPoint類 要點(切題 Done)]拳魁。
本質(zhì)圖相關(guān)
[3]重新給每個children指定父親惶桐,應(yīng)為自己要死了,這個父親是從children的共視關(guān)鍵幀中選擇,找孩子和共視關(guān)鍵幀中強度最高的作為children的父親姚糊。見下圖贿衍。
[4]如果有的孩子找不到父親,那么孩子的父親等于我的父親救恨。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
=========================================================================
題目:評估當(dāng)前關(guān)鍵幀場景深度贸辈,在哪用呢?
參考:
float KeyFrame::ComputeSceneMedianDepth(const int q)
思路:
1.思路:
相機坐標(biāo)系下地圖點深度的中間值作為場景的平均深度肠槽。
單目地圖點初始化用到擎淤。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
其他:
=========================================================================
題目:共視圖、本質(zhì)圖建立的邊如何在Optimizer中得到體現(xiàn)呢秸仙?有什么關(guān)系呢嘴拢?
參考:
思路:
void Optimizer::LocalBundleAdjustment(KeyFrame* pKF, bool* pbStopFlag,
Map* pMap)
1.思路:
通過一個關(guān)鍵幀,我可以找到他的共視關(guān)鍵幀寂纪,組成lLocalKeyFrames席吴,由lLocalKeyFrames得到lLocalMapPoints, 能夠觀測到lLocalMapPoints但是不屬于lLocalKeyFrames進行fix捞蛋,不優(yōu)化孝冒。
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
九、通俗易懂理解MapPoint類 要點(切題 Done)
參考
題目:如何刪除地圖點襟交?
參考:
// 把這個地圖點給刪掉
SetBadFlag()
思路:
1.思路:
[1]刪除地圖點的觀測
[2]因為地圖點被很多關(guān)鍵幀觀測到迈倍,每個觀測包含關(guān)鍵幀和對應(yīng)的特征點id,把關(guān)鍵幀對應(yīng)的地圖點置空
2.圖解(請用紙):
3.公式推導(dǎo)(請用紙):
要點程序:
問題
MapPoint的id是怎樣的。
這個地圖點被很多關(guān)鍵幀觀測到捣域,地圖點的每一個觀測包含關(guān)鍵幀和對應(yīng)在關(guān)鍵幀中的索引啼染。
主要函數(shù)
void MapPoint::AddObservation(KeyFrame* pKF, size_t idx)
void MapPoint::EraseObservation(KeyFrame* pKF)
void MapPoint::Replace(MapPoint* pMP)
// 把這個地圖點給刪掉
SetBadFlag()
void MapPoint::ComputeDistinctiveDescriptors()
void MapPoint::UpdateNormalAndDepth()
int MapPoint::PredictScale(const float& currentDist, Frame* pF)