在视觉 SLAM 领域,ORB-SLAM2 以其出色的性能和鲁棒性而备受关注。然而,单目 SLAM 的初始化一直是一个挑战。Tracking::MonocularInitialization() 函数是 ORB-SLAM2 中处理单目初始化的关键环节。如果初始化失败,整个 SLAM 系统都无法正常工作。经常有开发者反馈,在光照变化剧烈或者运动模糊的场景下,系统容易初始化失败,导致定位精度大幅下降,甚至直接崩溃。本文将深入探讨 Tracking::MonocularInitialization() 函数的原理和代码实现,并提供实战经验,帮助开发者避坑。
Tracking::MonocularInitialization() 函数底层原理
Tracking::MonocularInitialization() 的核心目标是从两帧图像中恢复出初始的相机姿态和场景结构。它主要依赖于以下几个步骤:
- 特征点提取与匹配:首先,利用 ORB 特征提取算法在两帧图像中提取特征点,并使用 Hamming 距离进行特征匹配。为了保证匹配质量,通常会进行一些过滤操作,例如去除距离过大的匹配点。
- H矩阵和F矩阵计算:根据匹配的特征点,分别计算 H(Homography,单应性矩阵)和 F(Fundamental,基础矩阵)矩阵。H 矩阵描述了在平面场景下的两帧图像之间的变换关系,而 F 矩阵则适用于非平面场景。
- 模型选择:通过 RANSAC 算法,分别优化 H 矩阵和 F 矩阵。然后,通过比较 H 矩阵和 F 矩阵的重投影误差来选择更合适的模型。通常情况下,如果场景接近平面,则选择 H 矩阵;否则,选择 F 矩阵。
- 运动恢复:根据选择的模型(H 或 F),恢复相机的运动姿态和场景结构。如果选择 H 矩阵,则直接分解 H 矩阵得到旋转矩阵和平移向量。如果选择 F 矩阵,则需要使用奇异值分解(SVD)来恢复相机姿态,并进行三角化计算特征点的三维坐标。
- 尺度恢复:由于单目 SLAM 固有的尺度不确定性,需要通过一些方法来恢复尺度。ORB-SLAM2 中,通常是将初始的基线长度设置为一个固定值。
关键算法细节:RANSAC 与八点法
RANSAC(Random Sample Consensus)是一种迭代的随机采样算法,用于估计数学模型的参数,尤其是在数据包含大量噪声和外点时。在 MonocularInitialization() 中,RANSAC 被用来鲁棒地估计 H 矩阵和 F 矩阵。它通过随机选择若干个样本点(例如,八点法需要 8 个匹配点),计算模型的参数,然后评估所有数据点与模型的符合程度。重复这个过程多次,选择最佳的模型参数。
八点法(Eight-Point Algorithm)是计算 F 矩阵的经典算法。它利用 8 个或更多匹配点的像素坐标,建立线性方程组,求解 F 矩阵。由于线性方程组的解不唯一,通常需要进行奇异值分解(SVD)来得到最优解。此外,F 矩阵还必须满足秩为 2 的约束,因此需要对 SVD 的结果进行修正。
代码解析与实战
bool Tracking::MonocularInitialization(const Frame &FirstFrame, const Frame &CurrentFrame, vector<cv::Point3f> &Points3D,
cv::Mat &Rcw, cv::Mat &Tcw, vector<bool> &vbTriangulated)
{
// 1. 特征点匹配
vector<cv::Point2f> mvKeys1u, mvKeys2u;
vector<int> mvMatches12;
ORBmatcher matcher(0.9,true); // 创建匹配器,设置匹配阈值
int nmatches = matcher.SearchForInitialization(FirstFrame,CurrentFrame,mvKeys1u,mvKeys2u,mvMatches12,100); //匹配特征点,限定最大匹配数量
if(nmatches<100) // 匹配点数量过少,初始化失败
return false;
// 2. 计算 H 矩阵和 F 矩阵
cv::Mat H = FindHomography(mvKeys1u, mvKeys2u, cv::RANSAC, 1.0, mvbOutlier, 10000); // 使用 RANSAC 算法计算 H 矩阵
cv::Mat F = FindFundamentalMat(mvKeys1u, mvKeys2u, cv::FM_RANSAC, 1.0, 0.99, mvbOutlier); // 使用 RANSAC 算法计算 F 矩阵
// 3. 模型选择 (简化版,实际代码更复杂)
float SH = CheckHomography(H, mvKeys1u, mvKeys2u, mvbOutlier, 5.0); // 计算 H 矩阵的重投影误差
float SF = CheckFundamental(F, mvKeys1u, mvKeys2u, mvbOutlier, 5.0); // 计算 F 矩阵的重投影误差
if(SH>SF*1.2) // 重投影误差的比例判断,选择模型
{
// 选择 H 矩阵
// ... (代码省略,分解 H 矩阵,恢复运动)
} else {
// 选择 F 矩阵
// ... (代码省略,分解 F 矩阵,恢复运动)
}
// 4. 三角化
// ... (代码省略,三角化特征点)
return true;
}
代码解读:
SearchForInitialization()函数用于进行特征点匹配。其中,参数0.9表示匹配阈值,100表示最大匹配数量。根据实际场景调整这两个参数可以提高匹配质量。FindHomography()和FindFundamentalMat()函数分别用于计算 H 矩阵和 F 矩阵。cv::RANSAC参数表示使用 RANSAC 算法。CheckHomography()和CheckFundamental()函数用于计算重投影误差。重投影误差是判断模型好坏的重要指标。可以根据实际情况调整重投影误差的阈值。
实战避坑经验:
- 光照变化:光照变化会导致特征点提取和匹配的困难。可以尝试使用对光照变化鲁棒的特征描述子,例如 AKAZE 或 BRISK。
- 运动模糊:运动模糊会降低图像的清晰度,影响特征点提取。可以尝试提高相机的曝光时间或使用图像去模糊算法。
- 低纹理区域:在低纹理区域,特征点数量较少,容易导致初始化失败。可以尝试使用更多的特征点提取算法或增加特征点的数量。
- 匹配错误:错误的特征点匹配会导致 H 矩阵和 F 矩阵的估计错误。可以尝试使用更严格的匹配策略或增加 RANSAC 的迭代次数。
- 参数调优:ORB-SLAM2 中有很多参数可以调整,例如特征点数量、匹配阈值、重投影误差阈值等。根据实际场景进行参数调优可以提高初始化成功率。
总结
Tracking::MonocularInitialization() 函数是 ORB-SLAM2 单目初始化的关键。深入理解其原理和代码实现,并结合实战经验,可以有效地提高初始化成功率,从而提升整个 SLAM 系统的性能。对于在复杂环境下,例如涉及边缘计算,需要部署轻量化 ORB-SLAM2 的场景,理解单目初始化至关重要。可以通过降低特征点数量,适当放宽匹配阈值,以满足算力约束。
冠军资讯
HelloWorld狂魔