ORB-SLAM2源码学习:ORBextractor.cc:ORBextractor::operator()主入口函数
前言
主入口函数直接调用了ComputePyramid()、ComputeKeyPointsOctTree()、computeDescriptors()三大核心函数,间接调用了这三大核心函数所调用的函数,可以说是覆盖了所有的函数。
1.函数声明
/*
用仿函数(重载括号运算符)方法来计算图像特征点
*
_image 输入原始图的图像
_mask 掩膜mask
_keypoints 存储特征点关键点的向量
_descriptors 存储特征点描述子的矩阵
*/
void ORBextractor::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _keypoints,
OutputArray _descriptors)
{
....
}
2.函数定义
步骤:
1.接收输入图像(_image)(另一个输入图像矩阵暂时用不到)提取图像的矩阵数据并检查是否是单通道。
if(_image.empty())
return;
//获取图像的大小
Mat image = _image.getMat();// 获取图像的矩阵数据。
//判断图像的格式是否正确,要求是单通道灰度值
assert(image.type() == CV_8UC1 );//每个像素值是一个8位无符号整数,三通道。
// assert是一种断言语句,用于在程序中进行条件检查。
2.调用ComputePyramid() 函数生成图像金字塔。
ORB-SLAM2源码学习:ORBextractor.cc:ComputePyramid构建图像金字塔①
// Pre-compute the scale pyramid
ComputePyramid(image);
3.调用ComputeKeyPointsOctTree()函数(传统的方法采用ComputeKeyPointsOld(),这里并未采用)来计算关键(Keypoints)点并存储在 allKeypoints 中。
ORB-SLAM2源码学习:ORBextractor.cc :ComputeKeyPointsOctTree计算并分配特征点②
// 存储所有的特征点,注意此处为二维的vector,第一维存储的是金字塔的层数,第二维存储的是那一层金字塔图像里提取的所有特征点
vector < vector<KeyPoint> > allKeypoints;
//使用四叉树的方式计算每层图像的特征点并进行分配
ComputeKeyPointsOctTree(allKeypoints);
4.根据每层的特征点数量计算总特征点数量,并为描述子(Descriptors)分配内存。
5. 遍历金字塔的每一层。
a.对当前层图像应用高斯模糊GaussianBlur(),得到workingMat。
b.调用 computeDescriptors() 函数计算当前层的描述子(Descriptors)。
ORB-SLAM2源码学习:ORBextractor.cc:computeOrbDescriptor 计算描述子
c.根据层级缩放特征点坐标,并将其添加到输出的 _keypoints 向量中。
//因为遍历是一层一层进行的,但是描述子那个矩阵是存储整个图像金字塔中特征点的描述子,所以在这里设置了Offset变量来保存“寻址”时的偏移量,
//辅助进行在总描述子mat中的定位
int offset = 0;
//开始遍历每一层图像
for (int level = 0; level < nlevels; ++level)
{
//获取在allKeypoints中当前层特征点容器的句柄
vector<KeyPoint>& keypoints = allKeypoints[level];
//本层的特征点数
int nkeypointsLevel = (int)keypoints.size();
//如果特征点数目为0,跳出本次循环,继续下一层金字塔
if(nkeypointsLevel==0)
continue;
// preprocess the resized image
// 深拷贝当前金字塔所在层级的图像
Mat workingMat = mvImagePyramid[level].clone();
// 注意:提取特征点的时候,使用的是清晰的原图像;这里计算描述子的时候,为了避免图像噪声的影响,使用了高斯模糊
GaussianBlur(workingMat, //源图像
workingMat, //输出图像
Size(7, 7), //高斯滤波器kernel大小,必须为正的奇数
2, //高斯滤波在x方向的标准差
2, //高斯滤波在y方向的标准差
BORDER_REFLECT_101);//边缘拓展点插值类型
// Compute the descriptors 计算描述子
// desc存储当前图层的描述子
Mat desc = descriptors.rowRange(offset, offset + nkeypointsLevel);
computeDescriptors(workingMat, //高斯模糊之后的图层图像
keypoints, //当前图层中的特征点集合
desc, //存储计算之后的描述子
pattern); //随机采样模板
// 更新偏移量的值
offset += nkeypointsLevel;
// Scale keypoint coordinates
// 对于第0层的图像特征点,他们的坐标就不需要再进行恢复了
if (level != 0)
{
// 获取当前图层上的缩放系数
float scale = mvScaleFactor[level];
// 遍历本层所有的特征点
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
// 特征点本身直接乘缩放倍数就可以了
keypoint->pt *= scale;
}
// And add the keypoints to the output
// 将keypoints中内容插入到_keypoints 的末尾
// keypoint其实是对allkeypoints中每层图像中特征点的引用,这样allkeypoints中的所有特征点在这里被转存到输出的_keypoints
_keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());
}
结束语
以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。