本篇对ORB-SLAM3中的图像帧构造进行简单概述,涉及内容较多的模块放在了单独的篇章。
目前ORB-SLAM3
支持4种相机传感器,同时又根据是否与IMU融合分为纯视觉Frame
对象的构造以及VI模式的Frame
对象构造
对于每种传感器,visual和vi模式的Frame
构造共用一个函数
可以在Frame.h
中看到共有3中构造函数,对应单目,双目和RGB-D相机,其中双目相机和双单目相机又共用一个构造函数
在Frame构造过程中,主要完成以下几件事:
在Tracking.cc->ParseORBParamFile
函数中可以看到,ORB-SLAM3为单目的初始化额外创建了一个ORB特征提取器mpIniORBextractor
,和正常模式下的特征提取器相比,区别在与所提取的特征点数量是正常模式下的5倍
,目的就是为了保证较为稳定的初始化结果。
详情戳:ORB-SLAM3算法学习—Frame构造—ORB特征提取和BRIEF描述子计算
UndistortKeyPoints()
对于单目、双目和RGB-D相机,在构造图像帧时,在提取特征点后需要根据图像的情况进行畸变矫正,去畸变的原理比较简单,就是给特征点对应的像素坐标乘以畸变系数即可,ORB-SALM3直接调用的opencv中的去畸变函数。
对应代码在Frame.cc->UndistortKeyPoints()
cv::undistortPoints(mat,mat, static_cast<Pinhole*>(mpCamera)->toK(),mDistCoef,cv::Mat(),mK);
另外就是有些相机可以直接发出去畸变后的图像,这时在配置文件中需要将畸变系数设置为0,去畸变函数检测到畸变系数为0时则会直接返回进入图像帧构造的下一个环节,比如zed相机
、RealSense
相机。
但有的双目相机发出的是带有畸变的图像,但是在进行双目相机标定时可以得到一组双目相机的内外参数,根据内外参数可以直接对双目图像进行remap,这时传输到SLAM系统的也是一组无畸变的图像,比如EuRoC
数据集。
对于针孔相机模型,(如TUM RGBD数据集,EUROC数据集,KITTY数据集,zed相机,Realsense相机等 )畸变系数格式一般为[k1,k2,p1,p2,k3]
,其中k3是可选项
对于鱼眼相机模型,(如TUM的双目+IMU数据集),畸变系数格式一般为[k1,k2,k3,k4]
对于双目相机,作者并没有直接使用相机输出的深度信息,而是基于一种带状搜索的方法,根据左目图像特征点的坐标在右目图像上寻找对应特征点,经过SAD搜索和抛物线拟合获得左目特征点在右目上对应的亚像素级别的坐标,最终计算对应的深度信息。
详情见另一篇文章:ORB-SLAM3算法学习—Frame构造—基于SAD滑窗的双目特征匹配
将图像划分为若干个网格,记录每个网格中特征点的索引,目的主要是用于特征匹配搜索。
void Frame::AssignFeaturesToGrid()
{
// Fill matrix with points
// 定义网格数量,这里网格数量是定值,但是图像的分辨率会有变化,是否应该跟随图像大小变化????
const int nCells = FRAME_GRID_COLS*FRAME_GRID_ROWS;
// 初始化网格mGrid的大小
int nReserve = 0.5f*N/(nCells);
for(unsigned int i=0; i<FRAME_GRID_COLS;i++)
for (unsigned int j=0; j<FRAME_GRID_ROWS;j++){
mGrid[i][j].reserve(nReserve);
if(Nleft != -1){
mGridRight[i][j].reserve(nReserve);
}
}
for(int i=0;i<N;i++)
{
// Nleft是双单目鱼眼相机情况下才会被赋值N = Nleft + NRight,对于单目相机,双目立体相机和RGBD相机会一直保持默认值-1
// 这里取特征点:如果不是双单目情况直接取特征点
// 如果是双单目,前[0,Nleft]个点是左目相机的,后[Nleft,N]是右目相机的
const cv::KeyPoint &kp = (Nleft == -1) ? mvKeysUn[i]
: (i < Nleft) ? mvKeys[i]
: mvKeysRight[i - Nleft];
int nGridPosX, nGridPosY;
if(PosInGrid(kp,nGridPosX,nGridPosY))// 判断下特征点对应的网格坐标是否超过了边界
{
// 将特征点的索引个网格坐标进行绑定
if(Nleft == -1 || i < Nleft)
mGrid[nGridPosX][nGridPosY].push_back(i);
else
mGridRight[nGridPosX][nGridPosY].push_back(i - Nleft);
}
}
}