ORB-SLAM2-学习记录1-ORB特征提取
代码注释参考
代码讲解参考
主要针对ORB-SLAM2中视觉里程计部分学习记录
函数运行顺序:
1. ORBextractor
2. operator()
3. ComputePyramid
4. ComputeKeyPointsOctTree
5. DistributeOctTree
6. DivideNode
7. computeOrientation
8. computeDescriptors
处理单张图像效果,只做特征提取部分:
程序调用:
ORB_SLAM2::ORBextractor* mpORBextractor;
mpORBextractor = new ORB_SLAM2::ORBextractor(nFeatures,scaleFactor,nLevels,iniThFAST,minThFAST);
std::vector<cv::KeyPoint> mvKeys;
cv::Mat mDescriptors;
(*mpORBextractor)(mImGray,cv::Mat(),mvKeys,mDescriptors);
1.ORBextractor
特征点提取器的构造函数
难点:
LOG_INFO("This is for orientation");
//This is for orientation
//下面的内容是和特征点的旋转计算有关的
// pre-compute the end of a row in a circular patch
//预先计算圆形patch中行的结束位置
//+1中的1表示那个圆的中间行
umax.resize(HALF_PATCH_SIZE + 1);
//cvFloor返回不大于参数的最大整数值,cvCeil返回不小于参数的最小整数值,cvRound则是四舍五入
int v, //循环辅助变量
v0, //辅助变量
vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1); //计算圆的最大行号,+1应该是把中间行也给考虑进去了
//NOTICE 注意这里的最大行号指的是计算的时候的最大行号,此行的和圆的角点在45°圆心角的一边上,之所以这样选择
//是因为圆周上的对称特性
//这里的二分之根2就是对应那个45°圆心角
int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);
//半径的平方
const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;
//*通过对称计算umax,0<=v<=vmax*//
//利用圆的方程计算每行像素的u坐标边界(max)
for (v = 0; v <= vmax; ++v)
umax[v] = cvRound(sqrt(hp2 - v * v)); //结果都是大于0的结果,表示x坐标在这一行的边界
// Make sure we are symmetric
//这里其实是使用了对称的方式计算上四分之一的圆周上的umax,目的也是为了保持严格的对称(如果按照常规的想法做,由于cvRound就会很容易出现不对称的情况,
//同时这些随机采样的特征点集也不能够满足旋转之后的采样不变性了)
//*通过对称计算umax,vmin<=v<=HALF_PATCH_SIZE*//
for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
{
while (umax[v0] == umax[v0 + 1])
++v0;
umax[v] = v0;
++v0;
}
2.operator()
用仿函数(重载括号运算符)方法来计算图像特征点,这个函数是该部分的流程化函数,负责整个特征提取计算流程的调用
3.ComputePyramid
构建图像金字塔
将图像进行“补边”,EDGE_THRESHOLD区域外的图像不进行FAST角点检测
//把源图像拷贝到目的图像的中央,四面填充指定的像素。图片如果已经拷贝到中间,只填充边界
//这样做是为了能够正确提取边界的FAST角点
//EDGE_THRESHOLD指的这个边界的宽度,由于这个边界之外的像素不是原图像素而是算法生成出来的,所以不能够在EDGE_THRESHOLD之外提取特征点
copyMakeBorder(mvImagePyramid[level],//源图像
temp,//目标图像(此时其实就已经有大了一圈的尺寸了)
EDGE_THRESHOLD, EDGE_THRESHOLD, //top & bottom 需要扩展的border大小
EDGE_THRESHOLD, EDGE_THRESHOLD, //left & right 需要扩展的border大小
BORDER_REFLECT_101+BORDER_ISOLATED); //扩充方式,opencv给出的解释:
if(level == 1)
{
cv::imshow("Result.jpg", temp);
}
扩充像素后图像
else
{
//对于第0层未缩放图像,直接将图像深拷贝到temp的中间,并且对其周围进行边界扩展。此时temp就是对原图扩展后的图像
copyMakeBorder(image,//这里是原图像
temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
BORDER_REFLECT_101);
cv::imshow("Result.jpg", temp);//只是对原图拓展
}
第0层图像,拓展后
4.ComputeKeyPointsOctTree
以八叉树分配特征点的方式,计算图像金字塔中的特征点,分布均匀
4.ComputeKeyPointsOld
使用传统的方法提取并平均分配图像的特征点,虽然分布不均匀,但是颜色变化明显的地方较多
效果
5.DistributeOctTree
对于某一图层,分配其特征点,通过八叉树的方式
6.DivideNode
在八叉树分配特征点的过程中,实现一个节点分裂为4个节点的操作
7.computeOrientation
这个函数用于计算特征点的方向,这里是返回角度作为方向
8.computeDescriptors
计算某层金字塔图像上特征点的描述子