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;
}

结束语

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

相关推荐
以卿a1 小时前
C++ 模板初阶
开发语言·c++
StickToForever4 小时前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
勤奋的凯尔森同学5 小时前
webmin配置终端显示样式,模仿UbuntuDesktop终端
linux·运维·服务器·ubuntu·webmin
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
莫忘初心丶6 小时前
在 Ubuntu 22 上使用 Gunicorn 启动 Flask 应用程序
python·ubuntu·flask·gunicorn
黑不溜秋的7 小时前
C++ 设计模式 - 策略模式
c++·设计模式·策略模式
leegong231117 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
Moonnnn.8 小时前
51单片机学习——动态数码管显示
笔记·嵌入式硬件·学习·51单片机
Dream it possible!9 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
南宫生9 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode