orb_slam2源码分析与优化(1)——角点检测与描述子计算

这一部分相对比较简单,主要用到opencv的cv::FAST()函数。

文件:ORBextractor.cc

初始化过程除了必要的赋值以外,还主要做了3件事,(1)将总的特征数在不同的金字塔曾进行分配,而分配依据是尺度因子(作者默认为1.2,并不知道为什么是这个),然后层数越高特征数越少。所有层加起来就是指定的特征数。(2)将代码里面的sample复制。(3)计算patch里面的v的最大u,这里变量为umax。后两者都是为计算描述子做准备。

然后是计算金字塔,对尺度因子累乘就行了。

接下来角点检测。循环检测每一层金字塔,划分一定大小的patch,对每个patch进行角点检测,这里直接采用的cv::FAST。需要注意的是,代码里有两个FAST阈值,当大阈值检测不出来时换小阈值。其实,可以考虑自适应。

// 如果检测到的fast特征为空,则降低阈值再进行检测
    if (vec_keys_cell.empty())
    {
        cv::FAST(vec_image_pyramid_[level].rowRange(ini_y, max_y).colRange(ini_x, max_x),
            vec_keys_cell, min_fast_threshold_, true);
    }

很多时候图像的容易集中在某个局部,另外有很大一部区域角点很稀疏,这样计算出来的描述子很不理想,为了让角点分布更均匀合理,这里运用四叉树算法对角点进行再分布。将图像以中点为远点划分为四个象限:

ni.UL_ = cv::Point2i(interval_x*static_cast(i), 0);
ni.UR_ = cv::Point2i(interval_x*static_cast(i + 1), 0);
ni.BL_ = cv::Point2i(ni.UL_.x, max_y - min_y);
ni.BR_ = cv::Point2i(ni.UR_.x, max_y - min_y);

然后分别查看每个象限里面包含的特征点数,如果特征点数大于1,则在该象限继续划分,直到特征点数为1,这样自然会有很多没有特征点的叶子,直接去掉,然后将特征点重新进行分配:

for (size_t i = 0; i < vec_keys_.size(); i++)
{
        const cv::KeyPoint &kp = vec_keys_[i];
        if (kp.pt.x < n1.UR_.x)
        {
                if (kp.pt.y < n1.BR_.y)
                        n1.vec_keys_.push_back(kp);
                else
                        n3.vec_keys_.push_back(kp);
        }
        else if (kp.pt.y < n1.BR_.y)
                n2.vec_keys_.push_back(kp);
        else
                n4.vec_keys_.push_back(kp);
}

当特征点全部分配之后循环结束。

当然,计算出来的特征点的位置是不准确的,因为之前为了避免计算到图像外面,做了切边保护,重新计算特征点的绝对位置:

// 换算特征点真实位置(添加边界值),添加特征点的尺度信息
    const int nkps = keypoints.size();
    for (int i = 0; i < nkps; i++)
    {
        keypoints[i].pt.x += min_border_x;
        keypoints[i].pt.y += min_border_y;
        keypoints[i].octave = level;
        keypoints[i].size = scaled_patch_size;
    }

然后是质心法计算特征点的角度,这里要用到前面初始化的umax。具体过程参考ORB算法,这里没有做任何改变。
然后是逐金字塔逐特征点地计算描述子,对于单个特征点,其32位描述子由以下计算出来:

for (int i = 0; i < 32; ++i, pattern += 16)
{
    int t0, t1, val;
    t0 = GET_VALUE(0); t1 = GET_VALUE(1);
    val = t0 < t1;
    t0 = GET_VALUE(2); t1 = GET_VALUE(3);
    val |= (t0 < t1) << 1;
    t0 = GET_VALUE(4); t1 = GET_VALUE(5);
    val |= (t0 < t1) << 2;
    t0 = GET_VALUE(6); t1 = GET_VALUE(7);
    val |= (t0 < t1) << 3;
    t0 = GET_VALUE(8); t1 = GET_VALUE(9);
    val |= (t0 < t1) << 4;
    t0 = GET_VALUE(10); t1 = GET_VALUE(11);
    val |= (t0 < t1) << 5;
    t0 = GET_VALUE(12); t1 = GET_VALUE(13);
    val |= (t0 < t1) << 6;
    t0 = GET_VALUE(14); t1 = GET_VALUE(15);
    val |= (t0 < t1) << 7;

    desc[i] = (uchar)val;
}

至此,第一阶段完成。
效果:
orb_slam2源码分析与优化(1)——角点检测与描述子计算_第1张图片

这里写图片描述

你可能感兴趣的:(slam)