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 更新之后就被系统销毁了。

相关推荐
我搞slam2 天前
Cartographer源码理解
算法·slam·cartographer
杀生丸学AI15 天前
【三维重建】近期进展(完善中)
3d·aigc·slam·三维重建·nerf·视觉大模型
WHAT81620 天前
【Orb-Slam3学习】 特征匹配函数的目的与分类
c++·人工智能·算法·slam
Chris·Bosh23 天前
intel RealSense D435i自制数据集跑SLAM
linux·slam
Johaden1 个月前
视觉SLAM ch3补充——在Linux中配置VScode以及CMakeLists如何添加Eigen库
linux·c++·ide·vscode·编辑器·slam
风与铃的约定1 个月前
2.2 视觉SLAM 实践:Eigen
c++·机器人·slam·视觉slam·eigen·机器人运动学
Johaden2 个月前
在C++程序中新建并使用库
linux·运维·服务器·c++·slam
WHAT8162 个月前
【视觉SLAM】 G2O库编写步骤介绍
算法·slam·g2o
什么都不会的小澎友2 个月前
(秋招复习)自动驾驶与机器人中的SLAM技术(一)
自动驾驶·秋招·slam
sinat_164231712 个月前
alike-cpp 编译
slam