ORB-SLAM2源码学习:Initializer.cc:Initializer::CheckFundamental地图初始化——检查基础矩阵F并评分

前言

这部分函数是要对所有的基础矩阵F进行一个打分,比较得分,得分最高(误差最小)的选为最优的基础矩阵。

1.函数声明

cpp 复制代码
float Initializer::CheckFundamental(
    const cv::Mat &F21,             
    vector<bool> &vbMatchesInliers, 
    float sigma)            

2.函数定义

用特征点到对应极线的距离来衡量当前基础矩阵的好坏。

由对极约束得出基础矩阵恒等式:

其中:

由极线定义:

设置误差为点到对应极线的距离:

利用得分公式计算得分:

其中:thScore表示自由度为2的卡方分布在显著性水平为0.05时对应的临界域值。

cpp 复制代码
/*
 对给定的Fundamental matrix打分 与对给定的单应矩阵进行打分的方法一致(套路一致但评分机制不同)
 F21                       当前帧和参考帧之间的基础矩阵
 vbMatchesInliers          匹配的特征点对属于inliers的标记
 sigma                     方差,默认为1
 return float                        返回得分
 */
float Initializer::CheckFundamental(
    const cv::Mat &F21,             //当前帧和参考帧之间的基础矩阵
    vector<bool> &vbMatchesInliers, //匹配的特征点对属于inliers的标记
    float sigma)                    //方差
{
	// 获取匹配的特征点对的总对数
    const int N = mvMatches12.size();

	// Step 1 提取基础矩阵中的元素数据
    const float f11 = F21.at<float>(0,0);
    const float f12 = F21.at<float>(0,1);
    const float f13 = F21.at<float>(0,2);
    const float f21 = F21.at<float>(1,0);
    const float f22 = F21.at<float>(1,1);
    const float f23 = F21.at<float>(1,2);
    const float f31 = F21.at<float>(2,0);
    const float f32 = F21.at<float>(2,1);
    const float f33 = F21.at<float>(2,2);

	// 预分配空间
    vbMatchesInliers.resize(N);

	// 设置评分初始值(因为后面需要进行这个数值的累计)
    float score = 0;

    // 基于卡方检验计算出的阈值
	// 自由度为1的卡方分布,显著性水平为0.05,对应的临界阈值
    // 在点到直线距离的计算中,只涉及一个独立的几何变量------距离
    // 每次判断的是单个点是否满足极线约束,距离的分布统计符合卡方分布,且只有一个变量影响统计结果。
    const float th = 3.841;

    // 自由度为2的卡方分布,显著性水平为0.05,对应的临界阈值
    const float thScore = 5.991;

	// 信息矩阵,或 协方差矩阵的逆矩阵
    const float invSigmaSquare = 1.0/(sigma*sigma);


    // Step 2 计算img1 和 img2 在估计 F 时的score值
    for(int i=0; i<N; i++)
    {
		//默认为这对特征点是Inliers
        bool bIn = true;

	    // Step 2.1 提取参考帧和当前帧之间的特征匹配点对
        const cv::KeyPoint &kp1 = mvKeys1[mvMatches12[i].first];
        const cv::KeyPoint &kp2 = mvKeys2[mvMatches12[i].second];

		// 提取出特征点的坐标
        const float u1 = kp1.pt.x;
        const float v1 = kp1.pt.y;
        const float u2 = kp2.pt.x;
        const float v2 = kp2.pt.y;

        // Reprojection error in second image
        // Step 2.2 计算 img1 上的点在 img2 上投影得到的极线 l2 = F21 * p1 = (a2,b2,c2)
		const float a2 = f11*u1+f12*v1+f13;
        const float b2 = f21*u1+f22*v1+f23;
        const float c2 = f31*u1+f32*v1+f33;
    
        // Step 2.3 计算误差 e = (a * p2.x + b * p2.y + c) /  sqrt(a * a + b * b)
        const float num2 = a2*u2+b2*v2+c2;
        const float squareDist1 = num2*num2/(a2*a2+b2*b2);
        // 带权重误差
        const float chiSquare1 = squareDist1*invSigmaSquare;
		
        // Step 2.4 误差大于阈值就说明这个点是Outlier 
        // ? 为什么判断阈值用的 th(1自由度),计算得分用的thScore(2自由度)
        // ? 可能是为了和CheckHomography 得分统一?
        if(chiSquare1>th)
            bIn = false;
        else
            // 误差越大,得分越低
            score += thScore - chiSquare1;

        // 计算img2上的点在 img1 上投影得到的极线 l1= p2 * F21 = (a1,b1,c1)
        const float a1 = f11*u2+f21*v2+f31;
        const float b1 = f12*u2+f22*v2+f32;
        const float c1 = f13*u2+f23*v2+f33;

        // 计算误差 e = (a * p2.x + b * p2.y + c) /  sqrt(a * a + b * b)
        const float num1 = a1*u1+b1*v1+c1;
        const float squareDist2 = num1*num1/(a1*a1+b1*b1);

        // 带权重误差
        const float chiSquare2 = squareDist2*invSigmaSquare;

        // 误差大于阈值就说明这个点是Outlier 
        if(chiSquare2>th)
            bIn = false;
        else
            score += thScore - chiSquare2;
        
        // Step 2.5 保存结果
        if(bIn)
            vbMatchesInliers[i]=true;
        else
            vbMatchesInliers[i]=false;
    }
    //  返回评分
    return score;
}

结束语

以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。

相关推荐
泡泡以安8 分钟前
Unidbg学习笔记(一):为什么需要用户态模拟器
笔记·学习
蜡笔小马9 分钟前
05.C++设计模式-适配器模式
c++·设计模式·适配器模式
code_pgf12 分钟前
Python `asyncio` 与 C++ Fiber 的原理与逻辑分析
c++·人工智能·python
小张成长计划..17 分钟前
【C++】30:C++11之lambda,新的类功能和包装器
c++
fengenrong18 分钟前
APIO2026游记
c++
会开花的二叉树19 分钟前
从 C++ 转向 AI 应用工程:我的 Python 基础第一阶段复盘
c++·人工智能·python
Cx330❀20 分钟前
从零实现一个 C++ 轻量级日志系统:原理与实践
大数据·linux·运维·服务器·开发语言·c++·搜索引擎
电子科技圈20 分钟前
XMOS将亮相台北国际电脑展并演示其在边缘AI和创新音频与互联等领域内的新方案
人工智能·游戏·计算机视觉·视觉检测·音视频·语音识别·实时音视频
程序leo源21 分钟前
Linux深度理解
linux·运维·服务器·c语言·c++·青少年编程·c#
Quinn2723 分钟前
正点原子 RK3562 Android14 Ubuntu 编译 SDK 环境准备:依赖、repo 与 Swap 配置一次搞定
linux·运维·ubuntu·mpu·正点原子·rk3562·arm linux