ORB_SLAM2原理及代码解析:Tracking::MonocularInitialization() 函数

目录

[1 作用](#1 作用)

[2 参数及含义说明](#2 参数及含义说明)

[3 代码逻辑](#3 代码逻辑)

[4 代码](#4 代码)

[5 代码解析](#5 代码解析)

[5.1 检查是否有初始化器](#5.1 检查是否有初始化器)

[5.1.1 随机采样一致性算法:RANdom SAmple Consensus(RANSAC)](#5.1.1 随机采样一致性算法:RANdom SAmple Consensus(RANSAC))

(1)作用

(2)原理

[5.2 初始化](#5.2 初始化)

[5.3 当前帧和参考帧中找匹配点](#5.3 当前帧和参考帧中找匹配点)

[5.3.1 最近邻比值阈值(nnratio)](#5.3.1 最近邻比值阈值(nnratio))

[5.3.2 参数说明](#5.3.2 参数说明)

[5.4 调用初始化器估计R、t,三角化](#5.4 调用初始化器估计R、t,三角化)

[5.5 设置位姿、建立初始化地图](#5.5 设置位姿、建立初始化地图)

1 作用

单目相机初始化:

(1)找到合适的两帧(参考帧 + 当前帧)、估计相机的初始运动(R, t);

(2)三角化生成第一批 3D 地图点;

(3)构建初始地图。

2 参数及含义说明

3 代码逻辑

(1)第一次检测到足够特征点(>100) → 保存为 mInitialFrame,并构造初始化器Initializer

(2)后续帧进入初始化阶段

ORBmatchermInitialFramemCurrentFrame 之间找匹配点。

如果匹配数不足 100 → 初始化失败,清空。

如果匹配足够 → 用 Initializer->Initialize() 估计 Rcwtcw,并三角化得到初始 3D 点。

设置初始帧和当前帧的位姿,调用 CreateInitialMapMonocular() 建图。

4 代码

cpp 复制代码
void Tracking::MonocularInitialization()
{

    if(!mpInitializer)
    {
        // Set Reference Frame
        if(mCurrentFrame.mvKeys.size()>100)
        {
            mInitialFrame = Frame(mCurrentFrame);
            mLastFrame = Frame(mCurrentFrame);
            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;

            mpInitializer =  new Initializer(mCurrentFrame,1.0,200);

            fill(mvIniMatches.begin(),mvIniMatches.end(),-1);

            return;
        }
    }
    else
    {
        // Try to initialize
        if((int)mCurrentFrame.mvKeys.size()<=100)
        {
            delete mpInitializer;
            mpInitializer = static_cast<Initializer*>(NULL);
            fill(mvIniMatches.begin(),mvIniMatches.end(),-1);
            return;
        }

        // Find correspondences
        ORBmatcher matcher(0.9,true);
        int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);

        // Check if there are enough correspondences
        if(nmatches<100)
        {
            delete mpInitializer;
            mpInitializer = static_cast<Initializer*>(NULL);
            return;
        }

        cv::Mat Rcw; // Current Camera Rotation
        cv::Mat tcw; // Current Camera Translation
        vector<bool> vbTriangulated; // Triangulated Correspondences (mvIniMatches)

        if(mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated))
        {
            for(size_t i=0, iend=mvIniMatches.size(); i<iend;i++)
            {
                if(mvIniMatches[i]>=0 && !vbTriangulated[i])
                {
                    mvIniMatches[i]=-1;
                    nmatches--;
                }
            }

            // Set Frame Poses
            mInitialFrame.SetPose(cv::Mat::eye(4,4,CV_32F));
            cv::Mat Tcw = cv::Mat::eye(4,4,CV_32F);
            Rcw.copyTo(Tcw.rowRange(0,3).colRange(0,3));
            tcw.copyTo(Tcw.rowRange(0,3).col(3));
            mCurrentFrame.SetPose(Tcw);

            CreateInitialMapMonocular();
        }
    }
}

5 代码解析

5.1 检查是否有初始化器
cpp 复制代码
    if(!mpInitializer)
    {
        // Set Reference Frame
        if(mCurrentFrame.mvKeys.size()>100)
        {
            mInitialFrame = Frame(mCurrentFrame);
            mLastFrame = Frame(mCurrentFrame);
            //分配存储空间,另mvbPrevMatched空间大小等于当前帧去畸变后的特征点数量
            mvbPrevMatched.resize(mCurrentFrame.mvKeysUn.size());
            for(size_t i=0; i<mCurrentFrame.mvKeysUn.size(); i++)
            //.pt二维像素坐标,将当前帧归一化去畸变后的像素坐标存储在mvbPrevMatched
                mvbPrevMatched[i]=mCurrentFrame.mvKeysUn[i].pt;

            if(mpInitializer)
                delete mpInitializer;
            
            //RANSAC 的噪声阈值 (1.0 像素) ,迭代次数 (200)
            mpInitializer =  new Initializer(mCurrentFrame,1.0,200);

            //将mvIniMatches中所有元素全部置为-1
            fill(mvIniMatches.begin(),mvIniMatches.end(),-1);

            return;
        }
    }
5.1.1 随机采样一致性算法:RANdom SAmple Consensus(RANSAC)
(1)作用

从数据里"挖出"一组可靠的内点(inliers),用它们来拟合正确的模型,并自动剔除外点。

(2)原理

求解对极几何E矩阵为例:

随机采样,

从匹配点集中随机选取最小数量的点(比如 8 点法 → 取 8 对点);

拟合模型,

用这组点计算一个候选的E矩阵;

验证一致性,

用这个E矩阵检查所有匹配点,看有多少点满足约束(误差 < 阈值)。符合约束的点称为内点 ;

记录最佳结果,

如果内点数比之前的最好结果还多 → 更新最佳模型;

迭代多次,

重复 1~4(比如 200 次),最终选出包含最多内点的模型。

5.2 初始化
cpp 复制代码
    else
    {
        // Try to initialize
        if((int)mCurrentFrame.mvKeys.size()<=100)
        {
            delete mpInitializer;
            mpInitializer = static_cast<Initializer*>(NULL);
            fill(mvIniMatches.begin(),mvIniMatches.end(),-1);
            return;
        }

5.1、5.2综合起来看,如果没有初始化器则找到一帧特征点大于100的作为初始化器的建立,如果有初始化器但当前帧特征点数小于100,则删除重新找。

5.3 当前帧和参考帧中找匹配点
cpp 复制代码
        // Find correspondences
        //根据ORB描述子在两帧图像之间寻找对应点,最近邻比值阈值0.9,检查特征点方向是否一致
        ORBmatcher matcher(0.9,true);
        int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);

        // Check if there are enough correspondences
        if(nmatches<100)
        {
            delete mpInitializer;
            mpInitializer = static_cast<Initializer*>(NULL);
            return;
        }
5.3.1 最近邻比值阈值(nnratio)

(1)对一个特征点找出在另一帧中的最近邻(距离 d1)和次近邻(距离 d2),该距离即汉明距离(Hamming Distance)

(2)如果 d1 < nnratio * d2,就认为匹配有效。

5.3.2 参数说明

(1)mInitialFrame

参考帧,保存了参考帧的关键点、ORB描述子

(2)mCurrentFrame

当前帧,要和参考帧匹配

(3)mvbPrevMatched

参考帧中特征点在上一帧的位置,初始化时将当前帧的关键点位置给mvbPrevMatched,连续跟踪mvbPrevMatched是参考帧的关键点在当前帧中的预测位置,由运动模型计算。

(4)mvIniMatches

参考帧在当前帧中的匹配情况

(5)100

匹配的范围,在附近 100 像素范围内搜索可能的匹配点

PS.SearchForInitialization() 函数详见:

https://blog.csdn.net/weixin_45728280/article/details/152455350?sharetype=blogdetail&sharerId=152455350&sharerefer=PC&sharesource=weixin_45728280&spm=1011.2480.3001.8118

5.4 调用初始化器估计R、t,三角化
cpp 复制代码
        cv::Mat Rcw; // Current Camera Rotation
        cv::Mat tcw; // Current Camera Translation
        vector<bool> vbTriangulated; // Triangulated Correspondences (mvIniMatches)

        //用参考帧 + 当前帧 → 估计相机运动(R,t)并恢复初始 3D 点云
        if(mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated))
        {
            for(size_t i=0, iend=mvIniMatches.size(); i<iend;i++)
            {
                if(mvIniMatches[i]>=0 && !vbTriangulated[i])
                {
                    mvIniMatches[i]=-1;
                    nmatches--;
                }
            }

PS.Initialize() 函数详见:

https://blog.csdn.net/weixin_45728280/article/details/152455699?sharetype=blogdetail&sharerId=152455699&sharerefer=PC&sharesource=weixin_45728280&spm=1011.2480.3001.8118

5.5 设置位姿、建立初始化地图
cpp 复制代码
            // Set Frame Poses
            mInitialFrame.SetPose(cv::Mat::eye(4,4,CV_32F));
            cv::Mat Tcw = cv::Mat::eye(4,4,CV_32F);
            Rcw.copyTo(Tcw.rowRange(0,3).colRange(0,3));
            tcw.copyTo(Tcw.rowRange(0,3).col(3));
            mCurrentFrame.SetPose(Tcw);

            CreateInitialMapMonocular();
        }
    }

CreateInitialMapMonocular() 函数详见:

https://blog.csdn.net/weixin_45728280/article/details/152511800?sharetype=blogdetail&sharerId=152511800&sharerefer=PC&sharesource=weixin_45728280&spm=1011.2480.3001.8118

相关推荐
猿小猴子5 小时前
主流 AI IDE 之一的「DeepSeek-Reasonix 」介绍
人工智能·ai·deepseek·reasonix
装不满的克莱因瓶5 小时前
链式法则如何传递参数误差 —— 深入理解神经网络中的梯度传播
人工智能·python·深度学习·神经网络·数学·机器学习·ai
Anastasiozzzz5 小时前
从有限状态机到智能体图:传统 FSM 与 Agent Graph的演进
java·人工智能·python·ai
程序员cxuan11 小时前
为每个任务配一套 harness:Claude Code 里的动态工作流
人工智能
程序员cxuan11 小时前
Claude Fable 5 来了
人工智能·后端·程序员
云边云科技_云网融合11 小时前
云边云科技亮相 2026 WOD 制造业数智化博览会 云网融合赋能制造焕新
人工智能·科技·安全·制造
小欣加油11 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
Σίσυφος190011 小时前
激光三角 光平面标定-多高度误差分析
人工智能·计算机视觉·平面
JS菌11 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
lqqjuly11 小时前
前沿算法深度解析(二)
人工智能·算法·机器学习