矩阵旋转-Eigen应用(QTCreator编辑器)
* { font-family: "Tibetan Machine Uni", "sans-serif", STFangSong; outline: none }
一、概述
旋转变换的核心思想
在不同坐标系下,虽然坐标不同,但是同一个向量还是一样的。这句话有点儿怪怪的,但是可以用数学公式表出:\(\beta_1^T\cdot\alpha_1=\beta_2^T\cdot\alpha_2\),其中\(\beta\)是不同坐标系的标准正交基(行分块),\(\alpha\)是不同坐标系下的坐标(列向量)。
旋转变换的五种表述
- 旋转矩阵;
- 欧式矩阵;
- 旋转向量;
- 欧拉角;
- 四元数;
旋转变换表述的演替
- 旋转矩阵和平移矩阵:有小尾巴累积(非线性)
- 欧式矩阵:n+1维方阵要\((n+1)^2\)个自由度,太多了(线性,但不紧凑且不直观)
- 旋转向量:这是什么呀这一堆数?!看不懂!(紧凑但不直观)
- 欧拉角:这会看懂了…等等,这转个90\(^\circ\)咋就膈屁了呢?!(紧凑直观但奇异)
- 四元数:爱咋转咋转…等等不对!咋1个\(R\)冒俩\(q\)呢?\(q\)咋还内讧了呢?(紧凑非奇异,但不唯一且不稳定)
在Eigen库中它们四个大哥(欧式矩阵对不起,现在我们只考虑旋转)的转换关系
旋转向量和四元数先初始化(默认定义为‘单位阵’,不能赋值为nullptr或者直接使用)!!!
旋转矩阵
初始化旋转矩阵
Eigen::Matrix3d rotation_matrix;
// 通过标准输入设备(标准输入流)键入赋值
rotation_matrix << x_00,x_01,x_02,x_10,x_11,x_12,x_20,x_21,x_22;
旋转矩阵 \(\Longrightarrow\) 旋转向量
// 第一种:通过构造函数(传入一个旋转矩阵)
Eigen::AngleAxisd rotation_vector(rotation_matrix);
// 第二种:首先初始化,然后通过旋转矩阵直接赋值(重载了赋值运算符)
Eigen::AngleAxisd rotation_vector;
rotation_vector = rotation_matrix;
// 第三种:首先初始化,然后from函数直接作用于this对象(rotation_vector)
Eigen::AngleAxisd rotation_vector;
rotation_vector.fromRotationMatrix(rotation_matrix);
旋转矩阵 \(\Longrightarrow\) 欧拉角
// (2, 1, 0)表示旋转顺序ZYX,数字越小表示优先级越高
Eigen::Vector3d euler_angle = rotation_matrix.eulerAngles(2, 1, 0);
旋转矩阵 \(\Longrightarrow\) 四元数
// 第一种:通过构造函数(传入一个旋转矩阵)
Eigen::Quaterniond quaternion(rotation_matrix);
// 第二种:首先初始化,然后通过旋转矩阵直接赋值(重载了赋值运算符)
Eigen::Quaterniond quaternion;
quaternion = rotation_matrix;
旋转向量
初始化旋转向量
// 通过构造函数
Eigen::AngleAxisd rotation_vector(alpha, Vector3d(x,y,z));
旋转向量 \(\Longrightarrow\) 旋转矩阵
// 第一种方法:通过构造方法传入旋转向量
Eigen::Matrix3d rotation_matrix(rotation_vector);
// 第二种方法:首先初始化,然后通过旋转向量直接赋值(重载了赋值运算符)
Eigen::Matrix3d rotation_matrix;
rotation_matrix = rotation_vector;
// 第三种方法:通过matrix方法
Eigen::Matrix3d rotation_matrix = rotation_vector.matrix();
// 第四种方法:通过toRotationMatrix方法
Eigen::Matrix3d rotation_matrix = rotation_vector.toRotationMatrix();
旋转向量 \(\Longrightarrow\) 欧拉角
// 不能直接转换,需要通过旋转矩阵搭桥
Eigen::Vector3d euler_angles = rotation_vector.matrix().eulerAngles(2, 1, 0);
旋转向量 \(\Longrightarrow\) 四元数
// 第一种方法:通过构造函数传入旋转向量
Eigen::Quaterniond quaterniond(rotation_vector);
// 第二种方法:首先初始化,然后用旋转向量赋值
Eigen::Quaterniond quaterniond;
quaterniond = rotation_vector;
欧拉角
初始化欧拉角
Eigen::Vector3d euler_angles(yaw, pitch, roll);
欧拉角 \(\Longrightarrow\) 旋转矩阵
// 初始化三个旋转角的旋转向量
Eigen::AngleAxisd rollAngle(AngleAxisd(euler_angles(2),Eigen::Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(euler_angles(1),Eigen::Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(euler_angles(0),Eigen::Vector3d::UnitZ()));
// 先初始化旋转矩阵为单位矩阵,然后这三个旋转向量相乘得到旋转矩阵(运算符重载)
Eigen::Matrix3d rotation_matrix;
rotation_matrix = yawAngle * pitchAngle * rollAngle;
欧拉角 \(\Longrightarrow\) 旋转向量
// 初始化三个旋转角的旋转向量
Eigen::AngleAxisd rollAngle(AngleAxisd(euler_angles(0), Eigen::Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(euler_angles(1), Eigen::Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(euler_angles(2), Eigen::Vector3d::UnitZ()));
// 先初始化旋转向量,然后这三个旋转向量相乘得到旋转向量(运算符重载)
Eigen::AngleAxisd rotation_vector;
rotation_vector = yawAngle * pitchAngle * rollAngle;
欧拉角 \(\Longrightarrow\) 四元数
// 初始化三个旋转角的旋转向量
Eigen::AngleAxisd rollAngle(AngleAxisd(euler_angles(2),Eigen::Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(euler_angles(1),Eigen::Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(euler_angles(0),Eigen::Vector3d::UnitZ()));
// 先初始化四元数,然后这三个旋转向量相乘得到旋转向量(运算符重载)
Eigen::Quaterniond quaterniond;
quaterniond = yawAngle * pitchAngle * rollAngle;
四元数
初始化四元数
Eigen::Quaterniond quaterniond(w, x, y, z);
四元数 \(\Longrightarrow\) 旋转矩阵
// 第一种方法:通过构造方法传入四元数
Eigen::Matrix3d rotation_matrix(quaterniond);
// 第二种方法:首先初始化,然后通过四元数直接赋值(重载了赋值运算符)
Eigen::Matrix3d rotation_matrix;
rotation_matrix = quaterniond;
// 第三种方法:通过matrix方法
Eigen::Matrix3d rotation_matrix = quaterniond.matrix();
// 第四种方法:通过toRotationMatrix方法
Eigen::Matrix3d rotation_matrix = quaterniond.toRotationMatrix();
四元数 \(\Longrightarrow\) 旋转向量
// 第一种方法:通过构造函数传入一个四元数
Eigen::AngleAxisd rotation_vector(quaterniond);
// 第二种方法:通过四元数直接赋值(运算符重载)
Eigen::AngleAxisd rotation_vector;
rotation_vector = quaterniond;
四元数 \(\Longrightarrow\) 欧拉角
// 不能直接转换,需要靠旋转矩阵搭桥
Eigen::Vector3d euler_angles = quaterniond.matrix().eulerAngles(2, 1, 0);
在Eigen中的转换——总结篇

- 旋转矩阵到旋转向量的FRM()方法是fromRotationMatrix();
- 四元数和旋转向量到旋转矩阵用的同一套体系,其中TRM()方法是toRotationMatrix();
- 只有旋转矩阵才能直接转换为欧拉角,其EA()方法为eulerAngles();
- 欧拉角转换成其他旋转表述形式用的同一套体系:RPY相乘。先初始化三个旋转角(RPY)的旋转向量,然后初始化所需旋转表述形式,最后这三个旋转向量相乘得到相应旋转表述形式(运算符重载);
旋转表述的使用
旋转矩阵
Eigen::Vector3d v( 1,0,0 );
v_rotated = rotation_matrix * v;
欧式矩阵
Eigen::Vector3d v( 1,0,0 );
Eigen::Isometry3d T=Eigen::Isometry3d::Identity();
// 为欧式矩阵设置旋转矩阵
T.rotate(rotation_vector);
// 为欧式矩阵设置平移矩阵
T.pretranslate(Eigen::Vector3d(1, 3, 4));
Eigen::Vector3d v_transformed = T * v;
旋转向量
Eigen::Vector3d v( 1,0,0 );
Eigen::Vector3d v_rotated = rotation_vector * v;
欧拉角
Eigen::Vector3d v( 1,0,0 );
Eigen::Vector3d euler_angles(M_PI / 4, M_PI / 4, M_PI / 4);
// 通过上述转换:rotation_matrix !!!
Eigen::Vector3d v_rotated = rotation_matrix * v;
四元数
Eigen::Vector3d v( 1,0,0 );
Eigen::Quaterniond q = Eigen::Quaterniond(rotation_vector);
// 注意数学上的表达式是:qvq^{-1}
Eigen::Vector3d v_rotated = q * v;
二、详述
旋转矩阵
旋转矩阵的定义
\[\begin{aligned}
&由旋转的本质方程:\beta_1^T\alpha_1=\beta_2^T\alpha_2,
又由于\beta是标准正交基,所以\beta\beta^T = E;
\\
&所以两边同时乘上\beta_1,故而可得\alpha_1=\beta_1\beta_2^T\alpha_2,记旋转矩阵R=\beta_1\beta_2^T;
\end{aligned}
\]旋转矩阵各个参数的意义
\(\beta\)是标准正交基,\(\alpha\)是相应坐标系下的坐标。
旋转矩阵各个参数的计算
\(R=\beta_1\beta_2^T\)。
欧式矩阵
欧式矩阵的定义
\[T =
\left[
\begin{matrix}
R&t\\
\it{0}^T&1
\end{matrix}
\right]
\]欧式矩阵各个参数的意义
\(R\)是旋转矩阵,\(t\)是平移向量,\(\it{0}^T\)是0列向量。
欧式矩阵各个参数的计算
不用计算,直接就有!!!
旋转向量
旋转向量的定义
\[\overrightarrow{n}与旋角\theta
\]旋转向量各个参数的意义
任何一个向量(或称为点)【1】的旋转都是绕着一个特定的轴来旋转,我们可以用这个轴的长度保存旋转角的大小\(\theta\)。故而旋转角被定义为:\(\theta\overrightarrow{n}\)。
【注】【1】:这里本来是坐标系的旋转,但是我们用相对的眼光看问题,我们如果聚焦于坐标系的话就相当与是向量在旋转。一个向量绕着一个轴在转可能比坐标系绕着一个轴在转好理解一点,这俩本质一样。
旋转向量各个参数的计算
旋转轴\(\overrightarrow{n}\)的计算
旋转轴在旋转的时候是不会变化的,所以有:\(R\overrightarrow{n}=\overrightarrow{n}\),即有\(\overrightarrow{n}\)为\(R\)的特征值为1的特征向量。
旋转角\(\theta\)的计算
罗德格里斯指出了旋转向量到旋转矩阵的法则:\(R=\cos{\theta}I+(1-\cos{\theta})\overrightarrow{n}\overrightarrow{n}^T+\sin{\theta}\overrightarrow{n}^{\wedge}\)。
同时取迹可得:\(\mathbf{tr}(R)=1+2\cos{\theta}\)。所以就计算出了\(\theta=\arccos{\frac{\mathbf{tr}(R)-1}{2}}\)。
欧拉角
欧拉角的定义
每个轴旋转一个特定的角度,但是有顺序要求,我们一般使用ZYX的顺序(称为RPY)。
欧拉角各个参数的意义
R:Roll,偏航角
P:Pitch,翻滚角
Y:Yaw,俯仰角
欧拉角各个参数的计算
通过传感器或者人为给出。不是吧不是吧,不会真有人用欧拉角吧?!【1】
【注】【1】:万向锁问题(奇异性)问题——只要我们想用3个实数来表达3维旋转时,都会不可避免地碰到奇异性问题。所以很少用这样的旋转表述方式,一般用也只是用于人机交互中传入旋转角度,或者验证系统的算法,因为这样的表述对于人类来说是非常直观的。
四元数
四元数的定义
\[q=(s,\overrightarrow{v})^{T}=(s,x,y,z)^{T}=s+xi+yj+zk
\]四元数各个参数的意义
实部\(s\)表示旋转程度:\(s=f(\theta)\);
虚部\(\overrightarrow{v}\)表示旋转轴:\(\overrightarrow{v}=k\overrightarrow{n}\);
虚部\(\overrightarrow{v}\)的定义为某个点在三维直角系下的坐标,由于四元数表示对一个向量(或称为点)的旋转,用数学公式可以严谨地证明,当对\(\overrightarrow{v}\)进行\(q=(s,\overrightarrow{v})^{T}\)旋转时不变,所以\(\overrightarrow{v}\)表示旋转轴。
四元数各个参数的计算(利用旋转向量)
实部\(s\)的计算
四元数 \(\Longrightarrow\) 旋转矩阵
\[\begin{aligned}
R& = \overrightarrow{v}\overrightarrow{v}^{T}+s^2I+2s\overrightarrow{v}^{\wedge}+(\overrightarrow{v})^2
\\\\
\mathbf{tr}(R)&=4s^2-1
\end{aligned}
\]旋转矩阵 \(\Longrightarrow\) 旋转向量
\[\begin{aligned}
\theta& = \arccos(\frac{\mathbf{tr}(R)-1}{2})=\arccos(2s^2-1)
\\\\
\theta& = 2\arccos{s}
\\\\
s& = \cos{\frac{\theta}{2}}
\end{aligned}
\]
虚部\(\overrightarrow{v}\)的计算
得到旋转轴
旋转轴就是四元数的虚部\(\overrightarrow{v}\)。
将四元数单位化
我们已经知道了实部\(s=\cos{\frac{\theta}{2}}\),所以虚部向量就只用除以一个\(\sin{\frac{\theta}{2}}\)就行了。
矩阵旋转-Eigen应用(QTCreator编辑器)的更多相关文章
- [LeetCode]Rotate Image(矩阵旋转)
48. Rotate Image Total Accepted: 69437 Total Submissions: 198781 Difficulty: Medium You are give ...
- 计蒜客模拟赛D1T1 蒜头君打地鼠:矩阵旋转+二维前缀和
题目链接:https://nanti.jisuanke.com/t/16445 题意: 给你一个n*n大小的01矩阵,和一个k*k大小的锤子,锤子只能斜着砸,问只砸一次最多能砸到多少个1. 题解: 将 ...
- c++刷题(43/100)矩阵旋转打印
题目1:矩阵旋转打印 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则 ...
- 利用neon技术对矩阵旋转进行加速
一般的矩阵旋转操作都是对矩阵中的元素逐个操作,假设矩阵大小为m*n,那么时间复杂度就是o(mn).如果使用了arm公司提供的neon加速技术,则可以并行的读取多个元素,对多个元素进行操作,虽然时间复杂 ...
- C++矩阵库 Eigen 快速入门
最近需要用 C++ 做一些数值计算,之前一直采用Matlab 混合编程的方式处理矩阵运算,非常麻烦,直到发现了 Eigen 库,简直相见恨晚,好用哭了. Eigen 是一个基于C++模板的线性代数库, ...
- C++矩阵库 Eigen 简介
最近需要用 C++ 做一些数值计算,之前一直采用Matlab 混合编程的方式处理矩阵运算,非常麻烦,直到发现了 Eigen 库,简直相见恨晚,好用哭了. Eigen 是一个基于C++模板的线性代数库, ...
- leetcode48:矩阵旋转
题目链接 输入一个N×N的方阵,要求不开辟新空间,实现矩阵旋转. 将点(x,y)绕原点顺时针旋转90度,变为(y,-x).原来的(-y,x)变为(x,y) class Solution(object) ...
- 洛谷P3933 Chtholly Nota Seniorious 【二分 + 贪心 + 矩阵旋转】
威廉需要调整圣剑的状态,因此他将瑟尼欧尼斯拆分护符,组成了一个nnn行mmm列的矩阵. 每一个护符都有自己的魔力值.现在为了测试圣剑,你需要将这些护符分成 A,B两部分. 要求如下: 圣剑的所有护符, ...
- 2018 Multi-University Training Contest 4 Problem J. Let Sudoku Rotate 【DFS+剪枝+矩阵旋转】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6341 Problem J. Let Sudoku Rotate Time Limit: 2000/100 ...
随机推荐
- Java 树结构实际应用 四(平衡二叉树/AVL树)
平衡二叉树(AVL 树) 1 看一个案例(说明二叉排序树可能的问题) 给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在. 左边 BST 存在的问题分析: ...
- 模拟实现AMD模块化规范
目录 引子 再谈什么是闭包(闭包的产生)? 词法作用域 回到闭包 利用闭包编写模块 实现AMD模块化规范 写在最后 引子 本文最后的目的是模拟实现AMD模块化规范,而写下本文的原因是今天阅读到了< ...
- Git 在解决冲突的时候文件覆盖
更新代码导致被还原或覆盖的场景:1.触发冲突的必要条件是修改同一个文件且修改的位置非常近,否则Git会自动合并其内容避免更新代码导致被还原或覆盖的解决方案1.少修改的地方(生产环境.公网测试环境):推 ...
- java例题_22 用递归求阶乘 5!
1 /*22 [程序 22 递归求阶乘] 2 题目:利用递归方法求 5!. 3 程序分析:递归公式:fn!=fn*4! 4 */ 5 6 /*分析 7 * 递归:如果其中每一步都要用到前一步或前几步的 ...
- PAT (Advanced Level) Practice 1027 Colors in Mars (20 分) 凌宸1642
PAT (Advanced Level) Practice 1027 Colors in Mars (20 分) 凌宸1642 题目描述: People in Mars represent the c ...
- LamPiao靶机work_through
前言 oscp靶机系列的第二篇.只追求做出来的话,这靶机蛮简单的.但是为了提升难度,尽量避免使用msf--毕竟考试只准用一次嘛,自己写了个exp. 正文 主机发现 nmap -sP 192.168.2 ...
- 【2020.8.23NOIP模拟赛】失落
[ 2020.8.23 N O I P 模 拟 赛 ] 失 落 [2020.8.23NOIP模拟赛]失落 [2020.8.23NOIP模拟赛]失落 题目描述 出题人心情很失落,于是他直接告诉你让你求出 ...
- 问题笔记-vueCli3.0打包路径出错
需求:vueCli3.0打包路径出错.解决办法:vueCli3.0打包,新版本更新脚手架做出精简,webpack配置文件需要手动配置.在文件根目录创建一个vue.config.js配置文件.基本版: ...
- SAP QM 检验批跳号解决
SAP QM 检验批跳号解决 在生产系统中,发现存在检验批规则或不规则跳号问题. 首先,查看事务代码SNRO编号范围对象QLOSE中BUFFER字段值,将其设置为NO BUFFER(无缓冲) 如果还存 ...
- 记一次metasploitable2内网渗透之samba服务的攻击
80端口中对应一些web靶场,在这里不记录 111端口的利用是向rpcbind服务的UDP套接字发送60字节载荷,便可填充目标内存,搞崩主机系统.在这里也不记录 Samba服务简介 Samba是在Li ...