ORB-SLAM(五)KeyFrame類


KeyFrame類利用Frame類來構造。對於什么樣的Frame可以認為是關鍵幀以及何時需要加入關鍵幀,是實現在tracking模塊中的。

由於KeyFrame中一部分數據會被多個線程訪問修改,因此需要在這些成員中加線程鎖,保證同一時間只有一個線程有訪問權。涉及線程安全的有:

關鍵幀位姿的設置(lock(mMutexPose));

關鍵幀間連接關系的設置(lock(mMutexConnections));

關鍵幀對應地圖點的操作(lock(mMutexFeatures)),包括通過地圖點計算相連關鍵幀之間的權重。

1. 設置相機位姿參數:設置KeyFrame中成員變量mTcw,mTwc,Ow(左目相機中心坐標),和Cw(雙目相機baseline中點坐標),相機坐標Z朝北,X朝東,Y朝地。

並給出了get函數獲取姿態參數。

注意

  • 這里的Ow等價於twc,表示當前相機光心在世界坐標系下的三維坐標
  • Tcw直接求逆計算量比較大,一般矩陣求逆在實現時都會用等價的矩陣表達式去表示,這里Ow就對應Tcw-1中的平移向量-RTt.
void KeyFrame::SetPose(const cv::Mat &Tcw_)
{
    unique_lock<mutex> lock(mMutexPose);
    Tcw_.copyTo(Tcw);
    cv::Mat Rcw = Tcw.rowRange(0,3).colRange(0,3);
    cv::Mat tcw = Tcw.rowRange(0,3).col(3);
    cv::Mat Rwc = Rcw.t();
    Ow = -Rwc*tcw;
    
    Twc = cv::Mat::eye(4,4,Tcw.type());
    Rwc.copyTo(Twc.rowRange(0,3).colRange(0,3));
    Ow.copyTo(Twc.rowRange(0,3).col(3));
    cv::Mat center = (cv::Mat_<float>(4,1) << mHalfBaseline, 0 , 0, 1);
    Cw = Twc*center;
}

2. 為關鍵幀之間添加連接,通過關鍵幀之間的weight連接,weight指的是兩個關鍵幀之間共同觀測到的地圖點:(注意這里都是接口函數,真實的建立連接關系使用的是void KeyFrame::UpdateConnections()函數)

使用的數據結構是:

std::map<KeyFrame*,int> mConnectedKeyFrameWeights

每一個關鍵幀都會維護一個自己的map,其中記錄了與其他關鍵幀之間的weight。每次為當前關鍵幀添加新的連接關鍵幀后,都需要根據weight對map結構重新排序,

UpdateBestCovisibles();

並更新這兩個向量:

mvpOrderedConnectedKeyFrames
mvOrderedWeights

由於map結構沒有sort函數,需要將元素取出放入一個pair組成的vector中,排序后放入上面這兩個向量中

vector<pair<int,KeyFrame*> > vPairs;
vPairs.reserve(mConnectedKeyFrameWeights.size());
for(map<KeyFrame*,int>::iterator mit=mConnectedKeyFrameWeights.begin(), mend=mConnectedKeyFrameWeights.end(); mit!=mend; mit++)
    vPairs.push_back(make_pair(mit->second,mit->first));

sort(vPairs.begin(),vPairs.end());
list<KeyFrame*> lKFs; // keyframe
list<int> lWs; // weight
for(size_t i=0, iend=vPairs.size(); i<iend;i++)
{
    lKFs.push_front(vPairs[i].second);
    lWs.push_front(vPairs[i].first);
}

mvpOrderedConnectedKeyFrames = vector<KeyFrame*>(lKFs.begin(),lKFs.end());
mvOrderedWeights = vector<int>(lWs.begin(), lWs.end());

還有幾個相關的API:

set<KeyFrame*> KeyFrame::GetConnectedKeyFrames();
vector<KeyFrame*> KeyFrame::GetVectorCovisibleKeyFrames();

vector<KeyFrame*> KeyFrame::GetBestCovisibilityKeyFrames(const int &N);
vector<KeyFrame*> KeyFrame::GetCovisiblesByWeight(const int &w);

int KeyFrame::GetWeight(KeyFrame *pKF);

都是返回連接的關鍵幀;

前兩個返回所有連接的關鍵幀,區別在於一個未排序(set),一個排序(vector)。// set是關聯容器 vector是順序容器

中間兩個返回滿足一定閾值(前N個,權重大於等於w)的關鍵幀,最后一個返回指定幀與當前幀間的權重。

3. 當前幀對應的地圖點的指針均存放在mvpMapPoints(mvp代表:member、vector、pointer)向量中,通過對mvpMapPoints操作封裝,可以得到以下API:

void KeyFrame::AddMapPoint(MapPoint *pMP, const size_t &idx);
void KeyFrame::EraseMapPointMatch(const size_t &idx);
void KeyFrame::EraseMapPointMatch(MapPoint* pMP);
void KeyFrame::ReplaceMapPointMatch(const size_t &idx, MapPoint* pMP);

// 注意區別下面兩個
set<MapPoint*> KeyFrame::GetMapPoints();
vector<MapPoint*> KeyFrame::GetMapPointMatches();
MapPoint* KeyFrame::GetMapPoint(const size_t &idx);

// 返回高質量MapPoints(被至少minObs個關鍵幀觀察到)的數量,其中會判斷MapPoint的Observations()屬性,對比給出的閾值
int KeyFrame::TrackedMapPoints(const int &minObs);

mvpMapPoints初始化在Frame.cpp中:

mvpMapPoints = vector<MapPoint*>(N,static_cast<MapPoint*>(NULL)); 

其中有N個空指針,因此有的位置上的MapPoint並沒有指向實際的地圖點(雖然對應有特征點,有索引idx,但是是外點),獲取時需要注意。

4. UpdateConnections()函數:建立關鍵幀之間的連接關系

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM