【ORB_SLAM2源码解读】计算umax(4)

视频讲解

逐个函数功能详细讲解ORB_SLAM2源码|计算umax

原理讲解

/**
 * 1. 加载 Euroc 数据集 QQ交流群 925533821 
 * 2. 加载 Euroc 数据集参数 对图像进行去畸变 
 * 3. 创建 ORB_SLAM2::System 对象, 初始化 System Tracking Frame ORBextractor 
 * 4. 执行 ORBextractor 构造函数 a.金字塔每层图像缩放系数 b.金字塔每层图像提取特征点数量 c.计算umax 
 */
ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels, int _iniThFAST, int _minThFAST):
    nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels), iniThFAST(_iniThFAST), minThFAST(_minThFAST)
{
    mvScaleFactor.resize(nlevels);
    mvLevelSigma2.resize(nlevels);
    // 存储缩放系数的vector
    mvScaleFactor[0]=1.0f;
    // 存储缩放系数平方的vector
    mvLevelSigma2[0]=1.0f;
    /**
     * mvScaleFactor[0]: 1.0
     * mvScaleFactor[1]: 1.2
     * mvScaleFactor[2]: 1.44
     * mvScaleFactor[3]: 1.728
    * mvScaleFactor[4]: 2.0736
    * mvScaleFactor[5]: 2.48832
    * mvScaleFactor[6]: 2.98598
    * mvScaleFactor[7]: 3.58318
    */
    for(int i=1; i<nlevels; i++)
    {
        mvScaleFactor[i]=mvScaleFactor[i-1]*scaleFactor;
        mvLevelSigma2[i]=mvScaleFactor[i]*mvScaleFactor[i];
    }
    /**
     * mvLevelSigma2[0]: 1.0
     * mvLevelSigma2[1]: 1.44
     * mvLevelSigma2[2]: 2.0736
     * mvLevelSigma2[3]: 2.98598
     * mvLevelSigma2[4]: 4.29982
     * mvLevelSigma2[5]: 6.19174
     * mvLevelSigma2[6]: 8.9161
     * mvLevelSigma2[7]: 12.8392
     */
    mvInvScaleFactor.resize(nlevels);
    mvInvLevelSigma2.resize(nlevels);
    for(int i=0; i<nlevels; i++)
    {
        // 存储缩放系数倒数的vector
        mvInvScaleFactor[i]=1.0f/mvScaleFactor[i];
        // 存储缩放系数平方倒数的vector
        mvInvLevelSigma2[i]=1.0f/mvLevelSigma2[i];
    }

    mvImagePyramid.resize(nlevels);
    mnFeaturesPerLevel.resize(nlevels);
    // 图像缩放系数的倒数 double scaleFactor;
    float factor = 1.0f / scaleFactor;
    // 第一层:nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels))
    // 第二层:nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels))*factor
    // 第三层:nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels))*factor*factor
    //  .........
    // 第nlevels层:nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels))*q^nlevels
    // 那么前nlevels层的和为总的特征点数量nfeatures等比数列的前n相和
    // 参考大佬讲解
    // https://zhuanlan.zhihu.com/p/61738607
    // https://blog.csdn.net/qq_30356613/article/details/75231440
    /**
     * 层需要提取的特征点数目
     * 第1层 261
     * 第2层 217
     * 第3层 181
     * 第4层 151
     * 第5层 126
     * 第6层 105
     * 第7层 87
     * 第8层 0
     */
    float nDesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels));
    int sumFeatures = 0;
    for( int level = 0; level < nlevels-1; level++ )
    {
        // std::vector mnFeaturesPerLevel; 这个vector存储图像金字塔每层需要提取的特征点个数
        // 第1层提取到的特征点数目取整然后存储到vector->mnFeaturesPerLevel
        mnFeaturesPerLevel[level] = cvRound(nDesiredFeaturesPerScale);
        // 特征点数目累加,这个变量的用途是为了计算第8层图像需要提取的特征点数目.
        sumFeatures += mnFeaturesPerLevel[level];
        nDesiredFeaturesPerScale *= factor;
    }
    // 从给定的两个值中查找最大值,上面只是计算前七层,这句代码是计算第8层需要提取特征点数目.
    mnFeaturesPerLevel[nlevels-1] = std::max(nfeatures - sumFeatures, 0);

    // https://zhuanlan.zhihu.com/p/61738607 4. 计算Rotation-Aware BRIEF rBRIEF
    // "static int bit_pattern_31_[256 * 4] = {" 是一个1024维的数组,数组数据类型是int,是特征点keypoint为中心周围256对点的坐标
    // 强制转换成 cv::Point 类型的 512个点.
    const int npoints = 512;
    const Point* pattern0 = (const Point*)bit_pattern_31_;
    /**
     * 8, -3, 9,  5
     * 4,  2, 7, -12
     * [8, -3]
     * [9, 5]
     * [4, 2]
     * [7, -12]
     */
    // copy [pattern0, pattern0+npoints] 到 std::vector pattern
    // pattern0是数据的首地址, 数据的尾地址是首地址加上偏移量.
    std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern));


    // This is for orientation pre-compute the end of a row in a circular patch
    // 以特征点keypoint像素坐标点为中心的patch圆内计算关键点keypoint的方向,直径为PATCH_SIZE=31,半径为HALF_PATCH_SIZE=15
    // 参考大佬讲解 https://blog.csdn.net/liu502617169/article/details/89423494
    // 参考大佬讲解 https://zhuanlan.zhihu.com/p/61738607 3. Oriented FAST,旋转角度计算
    // 参考大佬链接:http://the7.net/news/show-44083.html#!
    // cvRound() 即四舍五入返回跟参数最接近的整数值
    // cvFloor() 即向下取整返回不大于参数的最大整数值
    // cvCeil()  即向上取整返回不小于参数的最小整数值

    // "sqrt(" 返回一个数字的平方根 根号2对应45°圆心角
    // 1. 最大行数vmax初始化为R*sin45°(根号2/2)+1, +1是为了vmax和vmin边界值在遍历的过程中产生交叉,因为做了取整操作防止漏掉.
    // 2. 最大行数vmax单纯是0-45°这个过程的最大行数,而不是这个圆的最大行数.
    // 3. vmin为最小行数向上取整,是45-90°过程中的最小行数
    int v, v0, vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);// 11
    int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);
    // 半径R的平方 圆的半径取为15, 整个patch圆是31×31的
    const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;
    // std::vector umax;, ".resize(" 调整容器的大小
    umax.resize(HALF_PATCH_SIZE + 1);
    // umax 16个数值依次是:15 15 15 15 14 14 14 13 13 12 11 10 9 8 6 3
    // 图像坐标系,四分之一圆
    /**
     * ------------------------------------>X
     * | * * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * * *
     * | * * * * * * * * * * * * *
     * | * * * * * * * * * * * * *
     * | * * * * * * * * * * * *
     * | * * * * * * * * * * *
     * | * * * * * * * * * *
     * | * * * * * * * * *
     * | * * * * * * * *
     * | * * * * * *
     * | * * *
     * |
     * |
     * Y
     */
    for (v = 0; v <= vmax; ++v){
        // 利用三角函数定理计算 umax[v]平方 = HALF_PATCH_SIZE平方- v * v
        umax[v] = cvRound(sqrt(hp2 - v * v));
    }
    // Make sure we are symmetric
    // 计算v = vmin至HALF_PATCH_SIZE时的umax[v],v从11到15之间的值依次是: 10, 9, 8, 6, 3
    for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
    {
        while (umax[v0] == umax[v0 + 1])
            ++v0;
        umax[v] = v0;
        ++v0;
    }
}

你可能感兴趣的:(从零开始学习SLAM,ORB_SLAM2,ORB_SLAM3)