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

相关推荐
那雨倾城2 小时前
PiscCode:基于OpenCV的前景物体检测
图像处理·python·opencv·计算机视觉
何须至远2 小时前
机器人市场:犹如一颗深水核弹
stm32·单片机·机器人
eve杭3 小时前
解锁数据主权与极致性能:AI本地部署的全面指南
大数据·人工智能·5g·ai
幽络源小助理3 小时前
基于Napcat+Koshi的QQ群AI大模型机器人部署-幽络源
机器人·napcat·koshi·qqai机器人
数字时代全景窗3 小时前
商业航天与数字经济(一):从4G、5G得与失,看6G时代商业航天如何成为新经济引擎?
大数据·人工智能·5g
L_09074 小时前
【Algorithm】双指针算法与滑动窗口算法
c++·算法
F_D_Z4 小时前
【一文理解】下采样与上采样区别
人工智能·深度学习·计算机视觉
CiLerLinux4 小时前
第三十五章 ESP32S3 摄像头实验
图像处理·人工智能·计算机视觉
小龙报4 小时前
《构建模块化思维---函数(下)》
c语言·开发语言·c++·算法·visualstudio·学习方法