地圖點能夠經過關鍵幀來構造,也能夠經過普通幀構造,可是最終,必須是和關鍵幀對應的,經過普通幀構造的地圖點只是臨時被Tracking用來追蹤用的。函數
構造函數(地圖點3D座標及其參考幀):this
// 參考幀是關鍵幀,該地圖點將於許多幀關鍵幀對應,創建關鍵幀之間的共視關係 MapPoint::MapPoint(const cv::Mat &Pos, KeyFrame *pRefKF, Map* pMap) // 參考幀是普通幀,該地圖點只與當前普通幀的特徵點對應 MapPoint::MapPoint(const cv::Mat &Pos, Map* pMap, Frame* pFrame, const int &idxF)
地圖點和關鍵幀之間的觀測關係是最重要的,參考關鍵幀是哪一幀,該地圖點被哪些關鍵幀觀測到,對應的哪一個(idx)特徵點?經過兩個成員維護:spa
std::map<KeyFrame*,size_t> mObservations; // 觀測到該地圖點的相機數 int nObs;
添加地圖點觀測:可以觀測到同一個地圖點的關鍵幀之間存在共視關係code
void MapPoint::AddObservation(KeyFrame* pKF, size_t idx);
刪除地圖點觀測:從當前地圖點的mObservation和nObs成員中刪掉對應關鍵幀觀測關係,若該關鍵幀剛好是參考幀,則須要從新指定。當觀測相機數小於等於2時,該地圖點須要剔除。刪掉觀測關係,和刪掉地圖點(以及替換地圖點),須要區分開!orm
void MapPoint::EraseObservation(KeyFrame* pKF);
剔除MapPoint不只須要刪掉地圖點中維護的關鍵幀觀測關係,還須要刪掉對應關鍵中對應的地圖點,以及Map中該地圖點的內存:blog
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:ip
pKF->ReplaceMapPointMatch(mit->second, pMP);// KeyFrame中mit->second索引對應的地圖點,用pMP替換掉原來的this pMP->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;