解读《视觉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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

MySQL之InnoDB存储页的独立表空间解读

《MySQL之InnoDB存储页的独立表空间解读》:本文主要介绍MySQL之InnoDB存储页的独立表空间,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、独立表空间【1】表空间大小【2】区【3】组【4】段【5】区的类型【6】XDES Entry区结构【

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

MySQL主从复制与读写分离的用法解读

《MySQL主从复制与读写分离的用法解读》:本文主要介绍MySQL主从复制与读写分离的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、主从复制mysql主从复制原理实验案例二、读写分离实验案例安装并配置mycat 软件设置mycat读写分离验证mycat读

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

Python的端到端测试框架SeleniumBase使用解读

《Python的端到端测试框架SeleniumBase使用解读》:本文主要介绍Python的端到端测试框架SeleniumBase使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录SeleniumBase详细介绍及用法指南什么是 SeleniumBase?SeleniumBase