1. 构造Frame
(1)大致流程
- 更新帧ID
- 获取图像金字塔参数
- ExtractORB:提取ORB特征点
- UndistortKeyPoints:对提取到的特征点进行去畸变
- mbInitialComputations(可选):计算去畸变后的图像边界,一般是在第一帧或者相机标定参数发生变化之后进行
- AssignFeaturesToGrid:分配特征点到图像网格中
(2)代码实现
/**
* @brief 单目帧构造函数
*
* @param[in] imGray // 灰度图
* @param[in] timeStamp // 时间戳
* @param[in & out] extractor // ORB特征点提取器的句柄
* @param[in] voc // ORB字典的句柄
* @param[in] K // 相机的内参数矩阵
* @param[in] distCoef // 相机的去畸变参数
* @param[in] bf // baseline*f
* @param[in] thDepth // 区分远近点的深度阈值
*/
Frame::Frame(const cv::Mat &imGray, const double &timeStamp,
ORBextractor* extractor,ORBVocabulary* voc, cv::Mat &K,
cv::Mat &distCoef, const float &bf, const float &thDepth)
:mpORBvocabulary(voc),mpORBextractorLeft(extractor),
mpORBextractorRight(static_cast<ORBextractor*>(NULL)),
mTimeStamp(timeStamp), mK(K.clone()), mDistCoef(distCoef.clone()),
mbf(bf), mThDepth(thDepth)
{
// Step 1 更新帧的ID(自增) 注意:Frame ID(nNextId)是一个静态变量,作用域为全局
mnId=nNextId++;
// Step 2 获取图像金字塔的参数 (在构造SLAM系统时已计算出)
// 获取图像金字塔的层数
mnScaleLevels = mpORBextractorLeft->GetLevels();
// 获取每层的缩放因子
mfScaleFactor = mpORBextractorLeft->GetScaleFactor();
// 计算每层缩放因子的自然对数
mfLogScaleFactor = log(mfScaleFactor);
// 获取各层图像的缩放因子
mvScaleFactors = mpORBextractorLeft->GetScaleFactors();
// 获取各层图像的缩放因子的倒数
mvInvScaleFactors = mpORBextractorLeft->GetInverseScaleFactors();
// 获取sigma^2
mvLevelSigma2 = mpORBextractorLeft->GetScaleSigmaSquares();
// 获取sigma^2的倒数
mvInvLevelSigma2 = mpORBextractorLeft->GetInverseScaleSigmaSquares();
// Step 3 对这个单目图像提取ORB特征点, 第一个参数0-左图, 1-右图
// 对于单目而言只有左图,对于双目而言,在初始化时使用左右图,在跟踪时只使用左图
ExtractORB(0,imGray);
// 求出特征点的个数
N = mvKeys.size();
// 如果没有能够成功提取出特征点,那么就直接返回了
if(mvKeys.empty())
return;
// Step 4 用OpenCV的矫正函数、内参对提取到的特征点进行矫正(VINS-Mono中是采用逐次逼近的方法进行矫正)
// 因为如果镜头的视场角较大的话,提取到的特征点是带畸变的
UndistortKeyPoints();
// 设置双目信息
// 由于单目相机无法直接获得立体信息,所以这里要给右图像对应点和深度赋值-1表示没有相关信息
mvuRight = vector<float>(N,-1);
mvDepth = vector<float>(N,-1);
// 初始化当前帧的地图点(初始为空)
mvpMapPoints = vector<MapPoint*>(N,static_cast<MapPoint*>(NULL));
// 记录地图点是否为外点,初始化均为外点false
mvbOutlier = vector<bool>(N,false);
/*
Step 5 前面的UndistortKeyPoints()主要是对提取到的特征点进行去畸变,这里主要是对输入图像的4个边界角点进行去畸变. 然后计算去畸变后的图像边界,这个过程一般是在第一帧或者是相机标定参数发生变化之后进行
即mbInitialComputations = true的情况下进行,否则直接进行特征点分配
*/
if(mbInitialComputations)
{
// 计算去畸变后原始图像的边界(此时不存在图像金字塔) [(mnMinX, mnMaxX), (mnMinY, mnMaxY)]
ComputeImageBounds(imGray);
// 表示一个图像像素相当于多少个图像网格列(宽)
mfGridElementWidthInv=static_cast<float>(FRAME_GRID_COLS)/static_cast<float>(mnMaxX-mnMinX);
// 表示一个图像像素相当于多少个图像网格行(高)
mfGridElementHeightInv=static_cast<float>(FRAME_GRID_ROWS)/static_cast<float>(mnMaxY-mnMinY);
// 给类的静态成员变量复制
fx = K.at<float>(0,0);
fy = K.at<float>(1,1);
cx = K.at<float>(0,2);
cy = K.at<float>(1,2);
// 猜测是因为这种除法计算需要的时间略长,所以这里直接存储了这个中间计算结果
invfx = 1.0f/fx;
invfy = 1.0f/fy;
// 特殊的初始化过程完成,标志复位
mbInitialComputations=false;
}
//计算 basline
mb = mbf/fx;
// 将特征点分配到图像网格中
AssignFeaturesToGrid();
}