ORBSLAM2之单目初始化(1)

本文介绍ORB_SLAM2单目模式初始化流程,包括选取两帧进行匹配、计算位姿、构建初始地图及BA优化等步骤。重点在于特征点匹配与位姿估算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ORB_SLAM2单目初始化步骤

ORB_SLAM2单目模式的初始化过程可以分为以下阶段:

1 通过匹配选取两个可以作为起始两帧的初始帧

2 根据匹配计算两帧之间的位姿,获得初始位姿

3 三角化测量得到初始的特征点深度,包装成MapPoint,构建初始地图

4 BA优化初始化结果

第一阶段:通过匹配选取起始两帧

这一阶段做的工作是:选取是两个特征点数目大于100的两个连续帧,并进行匹配,

只有当前后帧匹配点对>100,才认为这两帧可以进行初始化并记录下来两帧的匹配关系,

接下来开始尝试求取两帧之间的位姿。否则如果当前帧特征点太少,重新构造初始器。

**此阶段输入条件:**单目图像

**此阶段目标:**得到初始两帧的匹配点(大于100对)

1.如果是单目初始器mpInitializer为空,即第一次进行初始化,并且特征点数>100,得到用于初始化的第一帧:

ORB_SLAM2/src/Tracking.cpp--void Tracking::MonocularInitialization()
...
// 单目初始器Initializer* mpInitializer
if(!mpInitializer)
    {
        // Set Reference Frame
        // 单目初始帧的特征点数必须大于100
        if(mCurrentFrame.mvKeys.size()>100)
        {
            // 得到用于初始化的第一帧,初始化需要两帧
            mInitialFrame = Frame(mCurrentFrame);
            // 记录最近的一帧
            mLastFrame = Frame(mCurrentFrame);
            //std::vector<cv::Point2f> mvbPrevMatched;
            //mvbPrevMatched最大的情况就是所有特征点都被跟踪上
            //mvKeysUn:校正mvKeys后的特征点std::vector<cv::KeyPoint> mvKeysUn;
            mvbPrevMatched.resize(mCurrentFrame.mvKeysUn.size());
            for(size_t i=0; i<mCurrentFrame.mvKeysUn.size(); i++)
                //记录匹配的特征点的位置
                mvbPrevMatched[i]=mCurrentFrame.mvKeysUn[i].pt;


            if(mpInitializer)
                delete mpInitializer;

            // 由当前帧构造初始器 sigma:1.0 iterations:200
            mpInitializer =  new Initializer(mCurrentFrame,1.0,200);
			//std::vector<int> mvIniMatches;用于跟踪初始化时前两帧之间的匹配
            //std::fill()
            fill(mvIniMatches.begin(),mvIniMatches.end(),-1);

            return;
        }
    }

...

cv::keyPoint

Opencv中KeyPoint类中的默认构造函数如下:
CV_WRAP KeyPoint() : pt(0,0), size(0), angle(-1), response(0), octave(0), class_id(-1) {}
现分析各项属性
pt(x,y):关键点的点坐标;
size():该关键点邻域直径大小;
angle:角度,表示关键点的方向,值为[,三百六十),负值表示不使用。
response:响应强度
octacv:从哪一层金字塔得到的此关键点。
class_id:当要对图片进行分类时,用class_id对每个关键点进行区分,默认为-1

单目初始器mpInitializer

ORB_SLAM2/src/Initializer.cpp
/**
 * @brief 给定参考帧构造Initializer
 * 
 * 用reference frame来初始化,这个reference frame就是SLAM正式开始的第一帧
 * @param ReferenceFrame 参考帧
 * @param sigma          测量误差
 * @param iterations     RANSAC迭代次数
 */
Initializer::Initializer(const Frame &ReferenceFrame, float sigma, int iterations)
{
    mK = ReferenceFrame.mK.clone();

    mvKeys1 = ReferenceFrame.mvKeysUn;

    mSigma = sigma;
    mSigma2 = sigma*sigma;
    mMaxIterations = iterations;
}

...

std::fill

std::fill函数的作用是:将一个区间的元素都赋予指定的值,即在[first, last)范围内填充指定值

#include <algorithm>
#include <vector>
#include <iostream>
 
int main()
{
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
    std::fill(v.begin(), v.end(), -1);
 
    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";
}

2.如果当前帧特征点数大于100,则得到用于单目初始化的第二帧:

ORB_SLAM2/src/Tracking.cpp--void Tracking::MonocularInitialization()
 ...
    
// mvbPrevMatched为前一帧的特征点,存储了mInitialFrame中哪些点将进行接下来的匹配
 // mvIniMatches存储mInitialFrame,mCurrentFrame之间匹配的特征点
ORBmatcher matcher(0.9,true);
//获得匹配点对个数
int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);

...

3.如果当前帧特征点数不大于100,重新初始化:

ORB_SLAM2/src/Tracking.cpp--void Tracking::MonocularInitialization()
 ...
    
if((int)mCurrentFrame.mvKeys.size()<=100)
{
    delete mpInitializer;
    mpInitializer = static_cast<Initializer*>(NULL);
    fill(mvIniMatches.begin(),mvIniMatches.end(),-1);
    return;
}

...

4.如果初始化的两帧之间的匹配点对太少(小于100),重新初始化:

ORB_SLAM2/src/Tracking.cpp--void Tracking::MonocularInitialization()
 ...
    
if(nmatches<100)
 {
     delete mpInitializer;
     mpInitializer = static_cast<Initializer*>(NULL);
     return;
 }

...

参考

https://www.zhihu.com/question/50385799/answer/120902345

https://blog.youkuaiyun.com/zhubaohua_bupt/article/details/78560966

ORB-SLAM: A Versatile and Accurate Monocular SLAM System

http://webdiis.unizar.es/~raulmur/orbslam/

https://github.com/raulmur/ORB_SLAM2

https://en.cppreference.com/w/cpp/algorithm/fill

ORB-SLAM2源码中文注释

ORB-SLAM2源码中文详解

《计算机视觉中的多视图几何》

### ORB-SLAM 中单应矩阵初始化的方法 在ORB-SLAM中,为了实现有效的单目视觉里程计(VO)和同步定位与建图(SLAM),单应矩阵的初始化是一个重要环节。该过程主要发生在两个连续图像帧之间,用于估计相机运动并构建初始的地图。 #### 特征点匹配与筛选 参与初始化的两帧各自需拥有超过100个特征点,并且这两帧间至少有100对成功匹配的特征点[^1]。这些匹配点对于后续的基础矩阵\( F \)或单应矩阵\( H \)计算至关重要。如果场景接近平面,则更倾向于使用单应矩阵来描述这种变换;反之则采用基础矩阵。 #### 基础矩阵 vs 单应矩阵的选择依据 记录当前帧与参考帧间的特征匹配关系,在其中随机选取8组匹配点对尝试建立模型——即分别基于这8对点估算出可能的基础矩阵\( F \)以及单应矩阵\( H \)。通过评估每种假设下其他未被选中的匹配点相对于所提模型的一致程度,可以得出两者各自的得分情况。最终决定是应用基础矩阵还是单应矩阵取决于哪一个选项能够更好地解释数据集内的大多数观测值。 #### 单应矩阵的具体求取流程 一旦选择了单应矩阵路径,接下来便是具体实施: - **坐标归一化**:首先对所有待处理的关键点位置执行标准化操作,使得它们围绕原点分布且平均距离为\(\sqrt{2}\)。 - **迭代优化**:进入循环阶段,每次都挑选不同的8个样本组合重新计算新的候选单应矩阵实例。随后利用剩余测试集合验证新产生的转换效果好坏,累积分数直至遍历完毕全部可能性为止。最后保留那个累计得票最高者作为全局最优解。 ```cpp // 归一化关键点坐标的伪代码示例 void NormalizePoints(std::vector<cv::Point2f>& points, cv::Mat& T){ // 计算质心 double cx = std::accumulate(points.begin(), points.end(), 0.0, [](double sum, const cv::Point2f &p){return sum+p.x;}) / points.size(); double cy = std::accumulate(points.begin(), points.end(), 0.0, [](double sum, const cv::Point2f &p){return sum+p.y;}) / points.size(); // 平移至中心 for(auto& p : points){ p.x -= cx; p.y -= cy; } // 缩放因子s=√2/mean_distance_to_origin double meanDist = ... ; // 计算均方根距离 double s = sqrt(2)/meanDist; // 构造仿射变换T=[s 0 tx; 0 s ty; 0 0 1] } ``` 此部分涉及到了一些具体的数学运算细节,比如如何正确地完成坐标系下的平移缩放动作以达到理想的规范化状态。上述C++片段展示了简化版的操作逻辑框架供参考。 #### 使用OpenCV进行预处理 值得注意的是,在实际编码实践中往往还需要考虑镜头畸变等因素的影响。因此会先调用`Frame::UndistortKeyPoints()`函数对接收到的原始角点做去扭曲校正工作,从而提高后续算法精度[^2]。 #### 非线性最小二乘法求解 当涉及到参数调整时,可能会引入诸如高斯-牛顿(GN), Levenberg-Marquardt (LM), 或 Dogleg 等非线性最优化技术来进行精炼。这类方法通常借助于像g2o这样的图形库辅助完成复杂结构下的高效寻优任务[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值