目录
1 特征点检测的基本步骤
输入图像----图像金字塔----计算每层FAST关键点----计算FAST关键点描述子
先列出这个类里面关键的函数和变量
//创建图像金字塔,这里每层只是降采样
void ComputePyramid(cv::Mat image);
//计算每一层的关键点
void ComputeKeyPointsOctTree(std::vector<std::vector<cv::KeyPoint> >& allKeypoints);
//控制关键点个数
std::vector<cv::KeyPoint> DistributeOctTree(const std::vector<cv::KeyPoint>& vToDistributeKeys, const int &minX,const int &maxX, const int &minY, const int &maxY, const int &nFeatures, const int &level);
//计算描述子多需要的点的位置
std::vector<cv::Point> pattern;
//需要提取的总的特征点个数
int nfeatures;
//尺度因子
double scaleFactor;
//金字塔层数
int nlevels;
//初始FAST阈值
int iniThFAST;
//最小FAST阈值
int minThFAST;
//每层关键点个数
std::vector<int> mnFeaturesPerLevel;
下面来看看每个步骤对应的代码
代码有些地方也没有完全搞明白,欢迎交流!
1.1 输入图像
特征点检测的入口是ORBextractor类,其中最主要的是
void operator()( cv::InputArray image, cv::InputArray mask,
std::vector<cv::KeyPoint>& keypoints,
cv::OutputArray descriptors);
参数包括输入图像image、输入模板mask(好像没有用到)、存储关键点的向量keypoints、存储描述子的数组descriptors
1.2 图像金字塔
这里使用的是简化版的图像金字塔,每一层大小被改变,都是上一层*尺度因子,函数是
void ORBextractor::ComputePyramid(cv::Mat image)
输入参数image,主要目的是计算每层图像,并且处理边界
主要的语句如下:
//每层缩放系数
float scale = mvInvScaleFactor[level];
//计算图像大小
Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
//将图像进行缩放(双线性插值)
resize(mvImagePyramid[level-1], mvImagePyramid[level], sz, 0, 0, cv::INTER_LINEAR);
//处理边界
copyMakeBorder(mvImagePyramid[level], temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,BORDER_REFLECT_101+BORDER_ISOLATED);
1.3 计算每层FAST关键点
void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoints)
输入参数allKeypoints,用来存储每层关键点
步骤:
将每层图像分成多个30*30的小格子(cell)
在每个小格子里面找FAST关键点(如果第一次没找到,就减小阈值再找,里面包括非极大值抑制)
根据事先给定的每层图像中特征点的多少(根据尺度,按等比数列的方式给出)来进行局部关键点剔除
//给定总特征点个数,根据等比数列求出最下面图像特征点个数
float nDesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels))
//记录每层特征点个数
mnFeaturesPerLevel[level] = cvRound(nDesiredFeaturesPerScale); //四舍五入
//计算上面一层特征点个数
nDesiredFeaturesPerScale *= factor;
进行局部关键点剔除的函数是(这个函数最多将图像分成长/宽*16块,在每块中选取一个响应值最大的保留)//todo 是不是有点少 //参数:每层找到的关键点、有效区域、每层允许的最多关键点个数、金字塔层数
vector<cv::KeyPoint> ORBextractor::DistributeOctTree(const vector<cv::KeyPoint>& vToDistributeKeys, const int &minX,const int &maxX, const int &minY, const int &maxY, const int &N, const int &level)
最后计算每个关键点-质心向量的夹角(里面计算灰度质心的公式有点变形)
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)
1.4 计算FAST关键点的描述子
首先对每层图像进行高斯滤波,然后计算256维描述子,计算描述子函数如下:
//输入参数:关键点位置 kpt、操作图像 img、要比较的位置pattern、描述子输出地址
static void computeOrbDescriptor(const KeyPoint& kpt,const Mat& img, const Point* pattern,uchar* desc)
计算步骤是:
先进行坐标变换(原来的基底乘以过渡矩阵,这里的过渡矩阵是旋转矩阵,旋转角为质心与关键点连线与原来X轴的夹角)
然后按照原来定义的比较点位置进行比较,输出描述向量
1.5 计算特征点的尺度坐标
未完待续......