04 帧 Frame

文章目录

    • [04 帧 Frame](#04 帧 Frame)
      • [4.1 相机相关信息](#4.1 相机相关信息)
      • [4.2 特征点提取](#4.2 特征点提取)
      • [4.2.1 特征点提取 ExtractORB()](#4.2.1 特征点提取 ExtractORB())
      • [4.3 ORB-SLAM2对双目/RGBD特征点的预处理](#4.3 ORB-SLAM2对双目/RGBD特征点的预处理)
        • [4.3.1 双目视差公式](#4.3.1 双目视差公式)
        • [4.3.2 双目图像特征点匹配 ComputeStereoMatches()](#4.3.2 双目图像特征点匹配 ComputeStereoMatches())
        • [4.3.3 根据深度信息构造虚拟右目图像:`ComputeStereoFromRGBD()`](#4.3.3 根据深度信息构造虚拟右目图像:ComputeStereoFromRGBD())
      • [4.4 畸变矫正:`UndistortKeyPoints()`](#4.4 畸变矫正:UndistortKeyPoints())
      • [4.5 特征点分配:`AssignFeaturesToGrid()`](#4.5 特征点分配:AssignFeaturesToGrid())
      • [4.5 构造函数 `Frame()`](#4.5 构造函数 Frame())
      • [4.6 `Frame` 类的用途](#4.6 Frame 类的用途)

04 帧 Frame

4.1 相机相关信息

Frame 类与相机相关的参数大部分都设为 static 类型,系统内所有的 Frame 对象共享一份相机参数。

成员函数/变量 访问控制 意义
static bool mbInitialComputations public static 是否需要为 Frame 类的相机参数赋值
初始化为 true,第一次为相机参数赋值后变为 false
static float fx fy static float cx cy static float invfx invfy public static 相机内参
cv::Mat mK public 相机内参矩阵
float mb public 双目相机基线
float mbf public 相机基线与焦距的乘积

这些参数首先由 Tracking 对象从 yaml 配置文件内读入,再传给 Frame 类的构造函数,第一次调用 Frame 的构造函数时为这些成员变量赋值.

4.2 特征点提取

Frame 类构造函数中调用成员变量 mpORBextractorLeftmpORBextractorRight 进行特征点提取。

成员函数/变量 访问控制 意义
ORBextractor* mpORBextractorLeft ORBextractor* mpORBextractorRight public 左右目特征点提取器
cv::Mat mDescriptors cv::Mat mDescriptorsRight public 左右目图像特征点描述子
std::vector<cv::KeyPoint> mvKeys std::vector<cv::KeyPoint> mvKeysRight public 畸变矫正前的左右目特征点
std::vector<cv::KeyPoint> mvKeysUn public 矫正后的左目 特征点(对应mvKeys
std::vector<float> mvuRight public 左目特征点在右目中匹配特征点的横坐标(左右目匹配特征点的纵坐标相同)
std::vector<float> mvDepth public 特征点深度
float mThDepth public 判断单目特征点和双目特征点的阈值 深度低于该值得特征点被认为是双目特征点 深度低于该值得特征点被认为是单目特征点

mvKeysmvKeysUnmvuRightmvDepth 的坐标索引是对应的,也就是说对于第 i 个图像特征点:

  • 其矫正前的左目特征点是 mvKeys[i]

  • 矫正后的左目特征点是 mvKeysUn[i]

  • 其在右目中对应的特征点的横坐标为 mvuRight[i],纵坐标与 mKeys[i] 相同;

  • 特征点深度为 mvDepth[i]

对于单目特征点(单目相机输入的特征点或没有找到右目匹配的左目图像特征点),其 mvuRightmvDepth 均为 -1。

4.2.1 特征点提取 ExtractORB()

成员函数/变量 访问控制 意义
void ExtractORB(int flag, const cv::Mat &im) public 直接调用 orbExtractor 提取特征点
cpp 复制代码
void Frame::ExtractORB(int flag, const cv::Mat &im)
{
    if(flag==0)
        (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);
    else
        (*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight);
}

4.3 ORB-SLAM2对双目/RGBD特征点的预处理

双目/RGBD 相机可以得到特征点的立体信息,包括右目特征点信息(mvuRight)、特征点深度信息(mvDepth):

  • 对于双目相机,通过双目特征点匹配关系计算特征点的深度值;
  • 对于 RGBD 相机,根据特征点深度构造虚拟的右目图像特征点。
成员函数/变量 访问控制 意义
void ComputeStereoMatches() public 双目图像特征点匹配,用于双目相机输入图像预处理
void ComputeStereoFromRGBD(const cv::Mat &imDepth) public 根据深度信息构造虚拟右目图像,用于RGBD相机输入图像预处理
cv::Mat UnprojectStereo(const int &i) public 根据深度信息将第 i 个特征点反投影成 MapPoint

通过这种预处理,在后面 SLAM 系统的其他部分中不用再区分双目特征点和 RGBD 特征点,它们都会以双目特征点的形式被处理(仅通过判断 mvuRight[idx] 判断某特征点是否有深度)。

4.3.1 双目视差公式

根据三角形相似关系

z − f z = b − u L + u R b \frac{z-f}{z}=\frac{b-u_L+u_R}{b} zz−f=bb−uL+uR

整理,得

z = f b d , d = u L − u R z=\frac{f b}{d}, \quad d=u_L-u_R z=dfb,d=uL−uR

其中, z z z 为观测距离(深度), b b b 为基线, f f f 为焦距, d d d 为视差。

4.3.2 双目图像特征点匹配 ComputeStereoMatches()

双目相机分别提取到左右目特征点后对特征点进行双目匹配,并通过双目视差估计特征点深度。双目特征点匹配步骤:

(1)粗匹配:根据特征点描述子距离和金字塔层级判断匹配.粗匹配关系是按行寻找的,对于左目图像中每个特征点,在右目图像对应行上寻找匹配特征点。

(2)精匹配: 根据特征点周围窗口内容相似度判断匹配。

(3)亚像素插值: 将特征点相似度与匹配坐标之间拟合成二次曲线,寻找最佳匹配位置(得到的是一个小数)。

(4)记录右目匹配 mvuRight 和深度 mvDepth 信息。

(5)离群点筛选: 以平均相似度的 2.1 倍为标准,筛选离群点。

4.3.3 根据深度信息构造虚拟右目图像:ComputeStereoFromRGBD()

对于 RGBD 特征点,根据深度信息构造虚拟右目图像(视差公式)。这样在就可以将 RGBD 图像和双目图像归为一类,便于程序处理。

4.4 畸变矫正:UndistortKeyPoints()

成员函数/变量 访问控制 意义
cv::Mat mDistCoef public 相机的畸变矫正参数
std::vector<cv::KeyPoint> mvKeys std::vector<cv::KeyPoint> mvKeysRight public 原始左/右目图像提取出的特征点(未校正)
std::vector<cv::KeyPoint> mvKeysUn public 畸变矫正后的左目特征点
void UndistortKeyPoints() public 矫正特征点(仅对单目和RGBD)
static float mnMinX,mnMaxX static float mnMinY,mnMaxY public 畸变矫正后的图像边界
void ComputeImageBounds(const cv::Mat &imLeft) private 计算畸变矫正后的图像边界

畸变矫正只对单目和 RGBD 相机输入图像有效,双目相机的畸变矫正参数均为 0,因为双目相机数据集在发布之前已经预先做了 双目矫正

4.5 特征点分配:AssignFeaturesToGrid()

在对特征点进行预处理后,将特征点分配到 48 行 64 列的网格中以加速匹配。

成员函数/变量 访问控制 意义
FRAME_GRID_ROWS=48 FRAME_GRID_COLS=64 #DEFINE 网格行数/列数
static float mfGridElementWidthInv mfGridElementHeightInv public static 每个网格的宽度/高度
std::vector<std::size_t> mGrid[FRAME_GRID_COLS][FRAME_GRID_ROWS] public 每个网格内特征点编号列表
void AssignFeaturesToGrid() private 将特征点分配到网格中
vector<size_t> GetFeaturesInArea(const float &x, const float &y, const float &r, const int minLevel=-1, const int maxLevel=-1) const public 获取半径为r的圆域内的特征点编号列表

为什么要分配特征点呢?

我们将图片分割为 64*48 大小的栅格,并将关键点按照位置分配到相应栅格中。匹配时,按照先粗后精的思想,先搜索栅格,再在栅格内搜索对应的像素点,这样比逐一比较像素点,效率更高。

4.5 构造函数 Frame()

包括默认构造函数、拷贝构造函数、单目/双目/RGBD 模式构造函数。

4.6 Frame 类的用途

成员变量/函数 访问控制 意义
Frame mCurrentFrame public 当前正在处理的帧
Frame mLastFrame private 上一帧

Tracking 线程每收到一帧图像,就调用函数 Tracking::GrabImageMonocular()Tracking::GrabImageStereo()Tracking::GrabImageRGBD() 创建一个 Frame 对象,赋值给 mCurrentFrame

Track() 函数跟踪结束后,将 mCurrentFrame 赋值给 mLastFrame

除了少数被选为 KeyFrame 的帧以外,大部分 Frame 对象的作用仅在于 Tracking 线程内追踪当前帧位姿,不会对 LocalMapping 线程和 LoopClosing 线程产生任何影响,在 mLastFramemCurrentFrame 更新之后就被系统销毁了。

相关推荐
什么都不会的小澎友4 天前
相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“
slam
nevergiveup_202416 天前
ORB-SLAM2 ---- 非线性优化在SLAM中的应用(一)
人工智能·笔记·算法·slam
智驾机器人技术前线1 个月前
近期两篇NeRF/3DGS-based SLAM方案赏析:TS-SLAM and MBA-SLAM
3d·slam·nerf·3dgs
CA7271 个月前
【视觉SLAM】2-三维空间刚体运动的数学表示
slam·三维旋转·四元数
CA7271 个月前
【视觉SLAM】4b-特征点法估计相机运动之PnP 3D-2D
slam
大山同学1 个月前
RA-L开源:Light-LOAM: 基于图匹配的轻量级激光雷达里程计和地图构建
语言模型·机器人·去中心化·slam·感知定位
大山同学1 个月前
DPGO:异步和并行分布式位姿图优化 2020 RA-L best paper
人工智能·分布式·语言模型·去中心化·slam·感知定位
OAK中国_官方1 个月前
OAK相机:纯视觉SLAM在夜晚的应用
人工智能·机器学习·slam
极客代码1 个月前
【计算机视觉】深入浅出SLAM技术原理
人工智能·python·算法·计算机视觉·机器人·slam·地图构建
大山同学1 个月前
最新开源DCL-SLAM:一种用于机器人群体的分布式协作激光雷达 SLAM 框架
人工智能·分布式·机器人·开源·slam·感知定位