自动驾驶-机器人-slam-定位面经和面试知识系列05之常考公式推导(02)

news2024/9/20 14:43:50

这个博客系列会分为C++ STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。在知乎和牛客(牛客上某些文章上会附上内推码)也会同步更新,全网同号(lonely-stone或者lonely_stone)。
关于高频面试题和C++ STL面经,每次我会更新10个问题左右,每次更新过多,害怕大家可能看了就只记住其中几个点。(在个人秋招面试过程中,面试到后面,发现除了个人项目和实习经历外,个人所记录的内容基本能涵盖面试官能问到的)
(另外个人才疏学浅,如果所分享知识中出现错误,请大家指出,避免误导其他人)

1. 对极约束+H-E-F

如果求职岗位与定位、SLAM这些相关,那对极约束相关的这三个矩阵肯定是必会的,并且推导流程也是要烂熟于心才行。
在这里插入图片描述

以上是我个人习惯的推导示意,大家可以自己手动推一下,然后最后记下来,这样印象要深刻一些。

其中基础矩阵秩只有2,因此F的自由度为7。它自由度比本质矩阵多的原因是多了两个内参矩阵
下面是单应矩阵:p2 = H * p1
在这里插入图片描述

先说结论,基础矩阵F有7个自由度,本质矩阵E有5个自由度,单应性矩阵H有8个自由度。

  • 本质矩阵E=t^R:6-1=5,尺度等价性。怎么理解这里的尺度等价性?本质矩阵是由对极约束定义的。由于对极约束是等式为零的约束,所以对E乘以任意非零常数后,对极约束依然满足。我们把这件事情称为E在不同尺度下是等价的。此外,本质矩阵E的奇异值是[σ,σ,0]T的形式,这是本质矩阵的内在性质。
  • 单应性矩阵H:9-1=8,单应矩阵Homography,通常我们说它都是说二维平面到二维平面的映射,其实Homography是n维射影空间之间最通常的变换的统称,这类变换的一个特征是在齐次坐标的基础上进行,因此它的维数是(n+1)2,它是最通常的,所以我们能想到自由度就是(n+1)2,而齐次坐标存在尺度模糊,所以要在此基础上减掉1,放在2维空间的话就是(2+1)^2 - 1 = 8。
  • 基础矩阵F:9-2=7,尺度等价性 + 秩为2(不满秩),
    在这里插入图片描述

  其中p是像素点坐标。一般解释F是有7个自由度,是说它有个约束秩为2即行列式为0,所以在单应基础上再减1。

2. 多层优化模式的求导

求导这些也可以推一推写一写,看网上其实关于这些比较细节的还不是很多。下面这个推导过程自己可以多熟悉熟悉,具体的代码实现可以看看ORBSLAM3里面的无imu版本实现。
在这里插入图片描述

3. 坐标转换基础

接下来是在坐标系变换里面很重要也是很基础的部分,自己在刚开始实习或者做项目时,总是对坐标转换有些懵圈,有时候感觉可简单了,有时候又感觉不太对。后来就好好理了一下,发现如下图所示的(用向量的方式理解)方法会特别清楚。在后续关于坐标系和位姿的变换时都比较得心应手。(这些可能对有些人来说比较基础简单,之所以把这些也写了出来,是因为自己当初刚开始的时候会有这些麻烦,所以如果能对一两个人有用也可以)
在这里插入图片描述

4. 手写高斯牛顿迭代优化

如果说上面的两点只是有助于自己基础SLAM能力的话(可能面试中不会问的多),那关于手写高斯牛顿迭代优化的基本很多都会问了。
在这里插入图片描述

#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <chrono>

using namespace std;
using namespace Eigen;
using namespace cv;

int main(int argc, char **argv){
    double ar = 1.0, br = 2.0, cr = 1.0; // 真实参数结果
    double ae = 2.0, be = -1.0, ce = 5.0; //初始参数值
    int N = 100; // 数据点对个数
    double w_sigma = 1.0; // 噪声sigma值
    double inv_sigma = 1.0 / w_sigma; 
    cv::RNG rng;      // opencv随机数产生器

    // step1.产生数据
    vector<double> x_data, y_data;
    for(int i = 0; i < N; ++i){
        double x = i / 100.0;
        x_data.push_back(x);
        double y = exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma);
        y_data.push_back(y);
    }

    // step2.开始Gauss-Newton迭代
    int iteration = 100;
    double cost = 0, lastCost = 0;
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for(int iter = 0; iter < iteration; ++iter){
        Matrix3d H = Matrix3d::Zero();    // H = J^T * W^(-1) * J
        Vector3d b = Vector3d::Zero();    // bias
        cost  = 0;

        for(int i = 0; i < N; ++i){
            double xi = x_data[i], yi = y_data[i]; // 第i个数据点
            double error = yi - exp(ae * xi * xi + be * xi + ce);
            Vector3d J;
            J(0) = - xi * xi * exp(ae * xi * xi + be * xi + ce);
            J(1) = -xi * exp(ae * xi * xi + be * xi + ce);
            J(2) = - exp(ae * xi * xi + be * xi + ce);

            H += inv_sigma * inv_sigma * J * J.transpose();
            b += - inv_sigma * inv_sigma * J * error;

            cost += error * error;
        }

        // 求解线性方程组 Hx = b
        Vector3d dx = H.ldlt().solve(b);
        if(isnan(dx[0])){
            cout << "result is nan!" <<endl;
            break;
        }

        if(iter > 0 && cost >= lastCost){
            cout << "cost:" << cost << ">= last cost" << lastCost << ", break." <<endl;
            break;
        }

        ae += dx[0];
        be += dx[1];
        ce += dx[2];
        
        lastCost = cost;

        cout << "total cost:" << cost << ", \t\t update:" << dx.transpose() << "\t\t estimated params:" << ae << " " << be << " " << ce <<endl;
    }

    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2-t1);
    cout << "solve time cost = " << time_used.count() << " seconds." << endl;
    cout << "estimated abc = " << ae << " " <<  be << " " << ce <<endl;


    return 0;
}

5. 手写扩展卡尔曼滤波进行参数估计

利用扩展卡尔曼滤波进行参数估计的问题当时被问的还不多,可能是自己更多是做BA的原因。记得是在面试滴滴提前批的时候就被问了这个题,结果不出意料,答得马马虎虎。后续我补全了一下。

问题:估计方程y=ax+b中的a和b参数
解答:在这个例子中,我们创建了一个 KalmanFilter 类,其中 a_ 和 b_ 是我们要估计的参数,p_ 是估计的协方差,processVariance_ 和 measurementVariance_ 是过程噪声和测量噪声的方差。
我们使用了一些模拟数据(可以替换为实际观测数据),并在每个数据点上调用 update 方法来更新我们对参数 a 和 b 的估计。

#include <iostream>
#include <vector>

class KalmanFilter {
public:
    KalmanFilter(double a, double b, double processVariance, double measurementVariance)
        : a_(a), b_(b), p_(1.0), processVariance_(processVariance), measurementVariance_(measurementVariance) {}

    void update(double x, double y) {
        // Prediction
        double prediction = a_ * x + b_;
        double predictionError = y - prediction;

        // Update
        double gain = p_ * x / (x * x * p_ + measurementVariance_);
        a_ += gain * predictionError;
        b_ += gain * (y - prediction - a_ * x);
        p_ = (1 - gain * x) * p_ + processVariance_;
    }

    double getA() const { return a_; }
    double getB() const { return b_; }

private:
    double a_, b_, p_;
    double processVariance_, measurementVariance_;
};

int main() {
    // Simulate some data
    std::vector<std::pair<double, double>> data = {
        {1, 2},
        {2, 4},
        {3, 6},
        {4, 8},
        // Add more data points as needed
    };

    KalmanFilter kf(0, 0, 0.01, 0.1); // Initial guesses for a, b and variances

    for (const auto& point : data) {
        double x = point.first;
        double y = point.second;

        kf.update(x, y);

        std::cout << "Estimated a: " << kf.getA() << ", Estimated b: " << kf.getB() << std::endl;
    }

    return 0;
}

这个题仅做参考,个人水平有限。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【运维自动化-配置平台】模型及模型关联最小化实践

蓝鲸智云配置平台&#xff0c;以下简称配置平台 我们知道主机是配置平台最常见的管控资源对象&#xff0c;在业务拓扑里可以通过划分模块来清晰的可视化管理&#xff1b;那其他资源如何通过配置平台来纳管呢&#xff0c;比如网络设备交换机。场景需求&#xff1a;如何把交换机…

怎么培养政府机关的公文写作能力?

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量 公文写作千万不能零起步&#xff0c;你有时间慢慢学习&#xff0c;但领导哪有时间等你慢慢进步啊。 如果问写公文有什么捷径&#xff0c;那就不得不靠「AI写作工具…

Study--Oracle-07-ASM相关参数(四)

一、ASM主要进程 1、ASM主要后台进程 ASM实例除了传统的DBWn、LGWR、CKPT、SMON和PMON等进程还包含如下几个新后台进程: 2、牛人笔记 邦德图文解读ASM架构,超详细 - 墨天轮 二、数据库实例于ASM实例之间的交互关系 数据库实例与ASM实例之间的交互关系涉及多个步骤和过程,…

联想教育电脑硬盘保护同传EDU系统使用简明教程

目录 一、原理概述 二、简明使用方法 1、软件下载 2、开机引导 3、开始安装 4、使用 &#xff08;1&#xff09;进入底层 &#xff08;2&#xff09;进行分区设置 &#xff08;3&#xff09;系统设置 &#xff08;4&#xff09;安装硬盘保护驱动 &#xff08;5&…

Android Studio导入源码

在有源码并且编译环境可用的情况下&#xff1a; 1.生成导入AS所需的配置文件 在源码的根目录执行以下命令&#xff1a; source build/ensetup.sh lunch 要编译的项目 make idegen //这一步会生成out/host/linux-x86/framework/idegen.jar development/tools/idegen/idegen.sh…

若依框架 : 生成代码

6.生成代码 6.1.配置生成设置 ruoyi-generator -> src -> main -> resources -> generator.yml 由于 案例中 表都有 前缀 为 tta_ , 这里设置去掉 6.2.生成代码 6.2.1.导入数据库中的表 6.2.2.修改设置 6.2.2.1.设置生成信息 点击 编辑 -> 生成信息 特别…

【数据结构-前缀和】力扣3152.特殊数组II

如果数组的每一对相邻元素都是两个奇偶性不同的数字&#xff0c;则该数组被认为是一个 特殊数组 。 周洋哥有一个整数数组 nums 和一个二维整数矩阵 queries&#xff0c;对于 queries[i] [fromi, toi]&#xff0c;请你帮助周洋哥检查子数组 nums[fromi…toi] 是不是一个 特殊…

19 Python常用内置函数——range()

range() 是 Python 开发中非常常用的一个内置函数。该函数返回具有惰性求值特点的 range 对象&#xff0c;其中包含左闭右开区间 [start, end) 内以 step 为步长的整数。 参数 start 默认为 0&#xff0c;step 默认为 1。 print(range(5)) print(list(range(5))) print(list(r…

科研绘图系列:R语言山脊图(Ridgeline Chart)

介绍 山脊图(Ridge Chart)是一种用于展示数据分布和比较不同类别或组之间差异的数据可视化技术。它通常用于展示多个维度或变量之间的关系,以及它们在不同组中的分布情况。山脊图的特点: 多变量展示:山脊图可以同时展示多个变量的分布情况,允许用户比较不同变量之间的关…

在MATLAB中使用importrobot导入机械臂刚体树时没有找到模型文件,只显示坐标;改为使用loadrobot

没有mesh文件夹&#xff0c;所以找不到模型文件 改为使用loadrobot,直接加载刚体树数据

深度解析Linux-C——结构体(初始化,结构体数组,结构体大小,位段操作,联合体,内存对齐,C的预处理,宏和带参宏,条件编译)

目录 结构体的三种初始化 结构体的两种引用 结构体数组 结构体大小 结构体实现位段操作 联合体 内存对齐 C的预处理 带参宏 条件编译 结构体的三种初始化 定义如下结构体 struct student {char name[100]; int age; float height; } ; 1、定义变量时初始化 s…

unity 实现图片的放大与缩小(根据鼠标位置拉伸放缩)

1创建UnityHelper.cs using UnityEngine.Events; using UnityEngine.EventSystems;public class UnityHelper {/// <summary>/// 简化向EventTrigger组件添加事件的操作。/// </summary>/// <param name"_eventTrigger">要添加事件监听的UI元素上…

Memcached开发(十四):常见问题与故障排除

目录 1. 内存使用问题 1.1 内存不足 1.2 内存泄漏 2. 连接问题 2.1 连接超时 2.2 连接断开 3. 数据一致性问题 3.1 缓存穿透 3.2 缓存雪崩 3.3 缓存击穿 4. 性能问题 4.1 响应时间过长 4.2 吞吐量不足 5. 安全问题 5.1 未授权访问 5.2 数据泄露 6. 版本兼容问…

驾驭代码的无形疆界:动态内存管理揭秘

目录 1.:为什么要有动态内存分配 2.malloc和free 2.1:malloc 2.2:free 3.calloc和realloc 3.1:calloc 3.1.1:代码1(malloc) 3.1.2:代码2(calloc) 3.2:realloc 3.2.1:原地扩容 3.2.2:异地扩容 3.2.3:代码1(原地扩容) 3.2.3:代码2(异地扩容) 4:常见的动态内存的错误…

AR 眼镜之-充电动画定制-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 充电动画 1. &#x1f531; 技术方案 1.1 方案介绍 1.2 实现方案 关机充电动画 亮屏/锁屏充电动画 2. &#x1f4a0; 关机充电动画 2.1 关机充电动画核心处理类与路径 2.2 实现细节 步骤一&#xff1a;1&#xff09;定制 …

Javascript前端面试基础5【每日更10】

let与var的区别 let命令不存在变量提升&#xff0c;如果在let前使用&#xff0c;会导致报错&#xff08;var存在变量提升&#xff09;如果块区中存在let和const命令&#xff0c;就会形成封闭作用域不允许重复声明&#xff0c;因此&#xff0c;不能在函数内部重新声明参数 m…

Pcl读取stl文件,并转换成pcd文件,同时显示stl模型和pcd点云

由于不同版本的pcl兼容范围不一样&#xff0c;这里有2个版本的代码&#xff0c;里面的文件路径需要实际情况修改即可&#xff0c;希望对您有所参考或帮助 pcl1.8.1和vs2015版本代码 #include <iostream> #include <pcl/io/io.h> #include <pcl/io/pcd_io.h>…

序列化与反序列化的本质

1. 将对象存储到本地 假如有一个student类&#xff0c;我们定义了好几个对象&#xff0c;想要把这些对象存储下来&#xff0c;该怎么办呢 from typing import List class Student:name: strage: intphones: List[str] s1 Student("xiaoming",10,["huawei&quo…

大模型微调部署实战及类GPT工具的高效使用

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委&#xff0c;编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二…

《RMT: Retentive Networks Meet Vision Transformers》CVPR2024

论文&#xff1a;RMT: Retentive Networks Meet Vision Transformers - AMiner 摘要 这篇论文探讨了将Retentive Network&#xff08;RetNet&#xff09;的概念引入到计算机视觉领域&#xff0c;并与Vision Transformer结合&#xff0c;提出了一种新的模型RMT&#xff08;Ret…