解读《视觉SLAM十四讲》,带你一步一步入门视觉SLAM—— 第 3 讲 三维刚体运动 (下)

2024-06-05 17:38

本文主要是介绍解读《视觉SLAM十四讲》,带你一步一步入门视觉SLAM—— 第 3 讲 三维刚体运动 (下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

陪女朋友为期五天的农村调研终于结束,终于可以回到大魔都享受城市生活了。在高铁上闲来无事再写点吧!(由于我肩部肌肉劳损,太疼了,所以本篇博客是我口述,女朋友代写的,感谢她的鼎力相助)
  
  在上一篇博客中我们介绍了三维刚体运动的旋转矩阵和变换矩阵,下面我要带你解读这一讲的下半部分内容:

  • 旋转向量、欧拉角、四元数;

解读

这一讲中的很多概念都比较抽象,我尽量给大家总结的通俗一些,但是大家还是要自己仔细去理解和体会这些几何变换的意义,有些东西如果实在难以理解,你也别着急,咱们先学会用,慢慢的就理解了。
  
  前面我们介绍了旋转矩阵和变换矩阵,它们的矩阵描述分别为:
R = [ a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 ] (0) R = \left[\begin{matrix}a_{11}&a_{12}&a_{13}\\ a_{21}&a_{22}&a_{23}\\a_{31}&a_{32}&a_{33} \end{matrix}\right] \tag0 R=a11a21a31a12a22a32a13a23a33(0)

T = [ R 3 ∗ 3 t 3 ∗ 1 0 T 1 ] (1) T = \left[\begin{matrix}R_{3*3}&t_{3*1}\\ 0^T&1\end{matrix}\right] \tag1 T=[R330Tt311](1)
  我们观察(0)式可以发现,在旋转矩阵中一共有9个变量,也就是说旋转矩阵有9个自由度,而实际上我们空间当中的一次旋转变换只需要3个自由度,也就是3个变量,所以我们使用旋转矩阵表示旋转变换时,额外引入了6个变量,就会造成表达的冗余。
  
  我们再观察(1)式,在变换矩阵中一共有16个量,实际上一次変换只有6个自由度,也就只需要6个变量,那么变换矩阵实际也是冗余的。
  
  另外一方面,旋转矩阵和变换矩阵都是正交矩阵,并且行列式的值为1,这在运算和优化中就会引入额外的限制,因为我们的优化结果必须要满足旋转矩阵和变换矩阵的形式。
  
  于是我们就想能不能有更好的表达方法去表达旋转和变换,能够一方面变量很紧凑,另一方面不会引入额外的约束。那么我们就要探索下面的一些方法。

旋转向量

因为前面所述的问题,所以作者在书中提出了旋转向量。旋转向量实际上并不难理解的,一个旋转轴 n ⃗ = [ a 1 , a 2 , a 3 ] \vec n=[a_1,a_2,a_3] n =[a1,a2,a3]加上一个旋转角度 θ \theta θ就可以达到旋转的效果。关于旋转向量,它和旋转矩阵一样也表示一种旋转变换,那么它们之间一定可以相互转换,转换可以使用罗德里格斯公式:
R = c o s θ I ⃗ + ( 1 − c o s θ ) n ⃗ n ⃗ T + s i n θ [ 0 − a 3 a 2 a 3 0 − a 1 − a 2 a 1 0 ] R = cos\theta \vec I +(1-cos\theta)\vec n \vec n^T+sin\theta \left[\begin{matrix}0&-a_3&a_{2}\\ a_{3}&0&-a_{1}\\-a_{2}&a_{1}&0 \end{matrix}\right] R=cosθI +(1cosθ)n n T+sinθ0a3a2a30a1a2a10
同样,旋转矩阵也可以转换为旋转向量,转换公式大家可以参考书中的公式。
  
  尽管旋转向量已经比旋转矩阵直观了很多,但是还是不够直观,于是又提出了欧拉角。

欧拉角

我们可以想象一下:对于一个三维坐标系,变换它的姿态,我们可以分为三步,第一步,我们先选择任意一个轴,以它为旋转轴进行旋转,第二步,在剩下的两个轴中选择一个轴作为旋转轴,然后旋转一定的角度,第三步,再以最后一根轴为旋转轴进行旋转,这样的过程就可以把一个坐标系旋转为另外的姿态。
  
  欧拉角虽然很直观,但是有很大的局限性,它常常会发生万向锁问题,也称为奇异性问题。当我们选择XYZ轴不同顺序进行依次旋转时常常发生万向锁问题,所以在SLAM中欧拉角的应用并不多,这里不再细说,大家看书就可以。关于万向锁问题大家可以参考这个视频了解一下《“欧拉角旋转”产生“万向锁”的来源,以及如何避免万向锁》
  
  我们不妨总结一下前面说的几种表示旋转的方法:欧拉角虽然直观,但是会导致万向锁问题,它很可能就不可用了,所以它在SLAM问题中很少使用;旋转矩阵参数冗余而且还会引入额外的约束,虽然使用会带来一些麻烦,但是至少不会失效;旋转向量使用旋转轴加上旋转角,好像还挺好的,没有带来什么不便和问题。那么还有更好的表示旋转的方法吗?答案是有的!

四元数

我是在学习SLAM的时候,才第一次接触到四元数,当时第一次接触也是一头雾水,尽管现在也没有完全理解,但是算是会用了。
  
  前面我们说到的一些表示旋转的方法,或多或少都存在一些问题,所以为了解决这些问题,就有人想到了四元数。这个东西我确实没有深入的去了解,所以靠我现在的理解,还是很难讲清楚,大家还是以《十四讲》为主要去理解四元数。
  
  我有一些认识在这里和大家分享一下:我们在学习一些几何的时候总是想直观的去理解一些定理或概念,多数情况下这样是行得通的,但是在四元数上若想直观的理解它的旋转还是有些困难的,如果你实在不能理解四元数,那就暂且将它放一边,就把它当做一个工具使用就行,记住它的一些性质和用法,对于它的理解你就边用边深入。关于四元数我推荐一个英文教程你可以阅读一下《四元数数学基础》提取码:q2x3

最后,无论是四元数、旋转矩阵还还是旋转向量,它们都可以用来描述同一个旋转。我们应该在实际中选择最为方便的形式,而不必拘泥于某种特定的形式。《视觉SLAM十四讲 从理论到实践》

扩展阅读:关于的旋转矩阵、旋转向量(轴角)、欧拉角、四元数的优缺点,可以看一下这篇博客:《矩阵、欧拉角、轴-角对、四元数随笔》

实践

我建议你按照书中的代码把实践部分内容多打几遍,不要嫌麻烦,一开始写代码都是这样先重复,再模仿,最后就能自己写了。

代码部分有两个地方还是值得你去注意的:

  • 注意四元数在Eigen中的表示顺序,在书本理论部分四元数的实部在前,形式是(w, x, y, z),而在Eigen库中形式是(x, y, z, w)。你要注意一下。我在公司实习的时候,有一个工程师就因为这个顺序搞反了,导致一个BUG找了一星期。
  • 有一行代码v_rotated = q*v;,这个是用四元数计算旋转,而书上理论部分使用的计算公式是: p ′ = q p q − 1 p'=qpq^{-1} p=qpq1,但是在代码中直接用q*v,因为Eigen库重载了*号,所以你以后使用的时候,直接用*就能表示四元数的旋转了。

无论你犯了多少错,或者进步得有多慢,你都走在了那些不曾尝试的人的前面。

这篇关于解读《视觉SLAM十四讲》,带你一步一步入门视觉SLAM—— 第 3 讲 三维刚体运动 (下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1033729

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al