ORB_SLAM2中特徵提取之圖像金字塔尺度不變性理解

本文參考:泡泡機器人提供的帶註釋的ORB_SLAM2源代碼
轉載本文請註明出處:
https://blog.csdn.net/RobotLife/article/details/87194017

在這裏插入圖片描述
在orb_slam2中,爲了實現特徵尺度不變性採用了圖像金字塔,金字塔的縮放因子爲1.2,。其思路就是對原始圖形(第0層)依次進行1/1.2縮放比例進行降採樣得到共計8張圖片(包括原始圖像),然後分別對得到的圖像進行特徵提取,並記錄特徵所在金字塔的第幾層,這樣得到一幀圖像的特徵點,如圖1所示。
在這裏插入圖片描述
現在假設在第二層中有一特徵點F,爲了避免縮放帶來特徵點F在縱向的移動,爲簡化敘述,選擇的特徵點F位於圖像中心,如圖2所示。根據相機成像“物近像大,物遠像小”的原理,如圖2所示爲相機成像的示意圖。假設圖1中攝像機原始圖像即金字塔第0層對應圖2中成像視野I0 ,則圖1中圖像金字塔第2層圖像可以相應對應於圖2中成像視野I2


其中特徵點F所在patch的相應關係如圖3所示。根據圖2可以得到 結論1: d2 / d0 = 1.22


有了以上鋪墊現在,來說說,尺度不變性,這裏不直接說明,而是看看對於第m層上的一個特徵點,其對應尺度不變時相機與特徵點對應空間位置之間距離(簡稱物距)的範圍。


假設第m層上有一特徵點Fm,其空間位置與拍攝時相機中心的位置爲dm ,顯然這是原始圖像縮放1/1.2m 倍後得到的特徵點patch,考慮“物遠像小”的成像特點,要使得該第m層特徵點對應patch變爲圖像金字塔第0層中同樣大小的patch,其相機與空間點的距離d=dm * 1.2m ,即尺度不變的最大物距dmax = dm*1.2m


要求尺度不變的最小物距則這樣考慮:根據“物近像大”的成像特點,使得當前第m層的特徵點移到第7層上則,真實相機成像圖像得放大1.27-m倍,故對應最小物距dmin=dm *1.2m-7


orb_slam2中原始代碼如下:
注意:上面變量與代碼中變量的對應關係:
7 <–> nLevels-1
m <–> level
1.2m <–> levelScaleFactor
dmax <–> mfMaxDistance
dmin <–> mfMinDistance

void MapPoint::UpdateNormalAndDepth()
{
    map<KeyFrame*,size_t> observations;
    KeyFrame* pRefKF;
    cv::Mat Pos;
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        if(mbBad)
            return;

        observations=mObservations; // 獲得觀測到該3d點的所有關鍵幀
        pRefKF=mpRefKF;             // 觀測到該點的參考關鍵幀
        Pos = mWorldPos.clone();    // 3d點在世界座標系中的位置
    }

    if(observations.empty())
        return;

    cv::Mat normal = cv::Mat::zeros(3,1,CV_32F);
    int n=0;
    for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    {
        KeyFrame* pKF = mit->first;
        cv::Mat Owi = pKF->GetCameraCenter();
        cv::Mat normali = mWorldPos - Owi;
        normal = normal + normali/cv::norm(normali); // 對所有關鍵幀對該點的觀測方向歸一化爲單位向量進行求和
        n++;
    } 

    cv::Mat PC = Pos - pRefKF->GetCameraCenter(); // 參考關鍵幀相機指向3D點的向量(在世界座標系下的表示)
    const float dist = cv::norm(PC); // 該點到參考關鍵幀相機的距離
    const int level = pRefKF->mvKeysUn[observations[pRefKF]].octave;
    const float levelScaleFactor =  pRefKF->mvScaleFactors[level];
    const int nLevels = pRefKF->mnScaleLevels; // 金字塔層數

    {
        unique_lock<mutex> lock3(mMutexPos);
        // 另見PredictScale函數前的註釋
        mfMaxDistance = dist*levelScaleFactor;                           // 觀測到該點的距離下限
        mfMinDistance = mfMaxDistance/pRefKF->mvScaleFactors[nLevels-1]; // 觀測到該點的距離上限
        mNormalVector = normal/n;                                        // 獲得平均的觀測方向
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章