您的位置:首页 > 其它

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

2016-08-07 05:12 483 查看
这一部分相对比较简单,主要用到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<float>(i), 0);
ni.UR_ = cv::Point2i(interval_x*static_cast<float>(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;
}


至此,第一阶段完成。

效果:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  slam-orb