標籤:觀察 距離 ati script set 索引 記憶體 繪圖 調整
地圖點可以通過主要畫面格來構造,也可以通過普通幀構造,但是最終,必須是和主要畫面格對應的,通過普通幀構造的地圖點只是臨時被Tracking用來追蹤用的。
建構函式(地圖點3D座標及其參考幀):
// 參考幀是主要畫面格,該地圖點將於許多幀主要畫面格對應,建立主要畫面格之間的共視關係MapPoint::MapPoint(const cv::Mat &Pos, KeyFrame *pRefKF, Map* pMap)// 參考幀是普通幀,該地圖點只與當前普通幀的特徵點對應MapPoint::MapPoint(const cv::Mat &Pos, Map* pMap, Frame* pFrame, const int &idxF)
地圖點和主要畫面格之間的觀測關係是最重要的,參考主要畫面格是哪一幀,該地圖點被哪些主要畫面格觀測到,對應的哪個(idx)特徵點?通過兩個成員維護:
std::map<KeyFrame*,size_t> mObservations;// 觀測到該地圖點的相機數int nObs;
添加地圖點觀測:能夠觀測到同一個地圖點的主要畫面格之間存在共視關係
void MapPoint::AddObservation(KeyFrame* pKF, size_t idx);
刪除地圖點觀測:從當前地圖點的mObservation和nObs成員中刪掉對應主要畫面格觀測關係,若該主要畫面格恰好是參考幀,則需要重新指定。當觀測相機數小於等於2時,該地圖點需要剔除。刪掉觀測關係,和刪掉地圖點(以及替換地圖點),需要區分開!
void MapPoint::EraseObservation(KeyFrame* pKF);
剔除MapPoint不僅需要刪掉地圖點中維護的主要畫面格觀測關係,還需要刪掉對應關鍵中對應的地圖點,以及Map中該地圖點的記憶體:
void KeyFrame::EraseMapPointMatch(const size_t &idx){ unique_lock<mutex> lock(mMutexFeatures); mvpMapPoints[idx]=static_cast<MapPoint*>(NULL);}mpMap->EraseMapPoint(this);
下面是一個重要的函數:
void MapPoint::Replace(MapPoint* pMP);
將當前地圖點(this),替換成pMp。主要使用在閉環時,調整地圖點和主要畫面格,建立新的關係:
主要畫面格將聯絡的this替換成pMap:
pKF->ReplaceMapPointMatch(mit->second, pMP);// KeyFrame中mit->second索引對應的地圖點,用pMP替換掉原來的thispMP->AddObservation(pKF,mit->second);// pMp地圖點添加觀測主要畫面格
// 刪掉Map中該地圖點
mpMap->EraseMapPoint(this);
無論是SetBadFlag()還是Replace(),當前地圖點的mbBad標誌都被記為true,表明當前地圖點是個壞點。
visible和found的區別:該地圖點在視野範圍內,該地圖點有對應特徵點的幀數。通常來說,found的地圖點一定是visible的,但是visible的地圖點很可能not found
float MapPoint::GetFoundRatio(){ unique_lock<mutex> lock(mMutexFeatures); return static_cast<float>(mnFound)/mnVisible;}
GetFoundRatio低表示該地圖點在很多主要畫面格的視野範圍內,但是沒有匹配上很多特徵點。
最後是MapPoint中幾個比較重要的函數:
void MapPoint::ComputeDistinctiveDescriptors();void MapPoint::UpdateNormalAndDepth();int MapPoint::PredictScale(const float ¤tDist, KeyFrame* pKF);
1. 計算地圖點描述子:
從mObservations中擷取觀察到當前地圖點的主要畫面格及對應描述子,描述子放入vDescriptor描述子向量組成的向量中。在這些描述子中,選擇距離(類似hamming距離)其他描述子最近的(中值距離最小,看代碼去體會一下是什麼意思)作為地圖點的描述子mDescriptor。
2. 計算地圖點平均觀測方向和深度
地圖點到所有觀測到的主要畫面格相機中心向量,歸一化後相加。
深度範圍:地圖點到參考幀(只有一幀)相機中心距離,乘上參考幀中描述子擷取時金字塔放大尺度,得到最大距離mfMaxDistance;最大距離除以整個金字塔最高層的放大尺度得到最小距離mfMinDistance。通常來說,距離較近的地圖點,將在金字塔層數較高的地方提取出,距離較遠的地圖點,在金字塔層數較低的地方提取出(金字塔層數越低,解析度越高,才能識別出遠點)。因此通過地圖點的資訊(主要是對應描述子),我們可以獲得該地圖點對應的金字塔層級:
const int level = pRefKF->mvKeysUn[observations[pRefKF]].octave;
從而預測該地圖點在什麼距離範圍內能夠被觀測到!
3. int MapPoint::PredictScale(const float ¤tDist, KeyFrame* pKF)
注意金字塔ScaleFactor和距離的關係:當前特徵點對應ScaleFactor為1.2的意思是:圖片解析度下降1.2倍後,可以提取出該特徵點(解析度更高時,肯定也可以提取出,這裡取金字塔中能夠提取出該特徵點最高層級作為該特徵點的層級)
同時,由當前特徵點的距離,可以推測所在層級。
Map則比較簡單,主要負責維護其中主要畫面格和地圖點容器,設定參考地圖點用於繪圖:
std::set<MapPoint*> mspMapPoints;std::set<KeyFrame*> mspKeyFrames;
ORB-SLAM(六)MapPoint與Map