这次主要介绍一些刚体运动中需要的数学知识以及Eigen库的基本使用。
什么是刚体运动?运动过程中不会发生形变。所以实际上刚体的运动也就只有两种:旋转和平移。
对于三维空间的旋转平移表示,之前的计算机图形学中介绍的比较清楚了。不过还有一些别的概念没有接触,在这里做个补充。
旋转向量
之前的旋转使用的是旋转矩阵,旋转矩阵是单位正交矩阵(行列式为1)。实际上会有个问题:旋转操作只需要3个自由度,但是却用了9个量来表示。这说明使用旋转矩阵是有冗余的。因此这里介绍旋转向量。
我们知道任何旋转都可以使用一个旋转轴和旋转角来描述。旋转向量是一个非常聪明的做法。它的方向代表了旋转轴,而它的长度代表了旋转的角度。
那么旋转向量与旋转矩阵如何转换呢?如果旋转轴(单位向量)为,旋转角度为,那么旋转向量为,旋转矩阵可以使用Rodrigues公式来计算出来:
为向量的对偶矩阵。这个公式也在之前的图形学博客中做过介绍了。
如何从旋转矩阵得到旋转向量?
首先,对于旋转角:
所以根据上式可以很简单求得:
至于,由于旋转轴的向量旋转后不会发生变化,因此.
所以为矩阵R特征值为1的对应的特征向量。
欧拉角
旋转向量以及旋转矩阵对于人的角度来说都不够直观。因此有了欧拉角的诞生。其实欧拉角就是将一个旋转转化为3个绕坐标轴的转动。因此这个转动的顺序就不唯一了。在航空里可能经常听到“偏航-俯仰-滚转”(yam-pitch-roll),实际上就是欧拉角的一种,等价与ZYX轴的旋转。
因此欧拉角就是用一个向量(3个角度)来表示一个旋转。但是欧拉角有个著名的万能锁问题。如果pitch转动了,则最后一个转动绕的轴实际上和z轴一样,这就使得损失了一个自由度,这被称为奇异性问题(?)。因此欧拉角不适用与插值和迭代,往往用于人工交互。
四元数
旋转矩阵用9个量描述,有冗余,而旋转向量和欧拉角却具有奇异性。实际上我们找不到不带奇异性的三维向量描述方式。
因此在这里再介绍一个四元数。它用四个量来描述旋转足够紧凑同时也没有奇异性。
一个四元数,有一个实部,3个虚部。其中虚部满足下面的一组式子:
有时候也使用一个标量和一个向量来表示四元数:
$ = [ s, ],s = q_0 , = [ q_1,q_2,q_3 ]^T ^3 $.
如果实部为0,称为虚四元数,如果虚部为0称为实四元数。
我们能用单位四元数表示三维空间中的任意旋转。不过由于复数的引入,它的表示是有点反直觉的。假如旋转向量为,则对应的四元数为:
因此从单位四元数中也很容易得到对应的旋转轴和旋转角度:
这个式子确实反直觉,给我们赚了一般的感觉。如果对$$加上,相当于没有转动,但是他们对应的四元数却变成原来的相反数了。因此,互为四元数的相反数表示同一个旋转。
四元数的概念的话现在还很懵比,不知道为什么要这样来表示一个旋转。但是能发展到现在还留下来的一定是有自己的道理。因为四元数每个值都是经过处理的轴和角结合,因此它方便进行插值。听说四元数在游戏开发里应用广泛。具体这些以后再去弄明白,先看一看四元数的基本运算吧。
加减
$_a _b = [ s_a s_b ,_a _b] $ ### 乘法 ###
乘法就是各项轮着相称,最后相加,虚部要按照虚部的规则来乘,最后得到结果:
如果写成向量形式:
由于最后一项存在,四元数的乘法通常是不可交换的。 ### 共轭 ###
可以看到四元数和共轭相称得到一个实数。 ### 模长 ###
可以验证:.
这保证了单位四元数的乘积依然为单位四元数。
逆
同时可以知道,单位四元数的逆就是单位四元数的共轭,因为.
乘积的逆和矩阵的逆有同样的性质:
数乘和点乘
用四元数表示旋转
对于一个三维点,绕着转轴旋转,变为.我们知道使用矩阵的话,可以这样描述:.但是使用四元数如何描述呢?
我们把空间的点用虚四元数来描述,则.
用来表示旋转:
.
则:.
可以验证的是经过计算的实部为0,虚部对应的就是的坐标点。
可以看到使用四元数来旋转的话也是非常方便的。
四元数和旋转矩阵的转换
四元数与旋转矩阵的转换,我们可以想到的是利用旋转向量来做中间的桥梁。不过其中有个arccos函数代价较大,但是实际上可以通过一定的技巧绕过。在这里直接给出四元数到旋转矩阵的转换结果(省略推导过程):
设四元数为:,则:
如果知道了旋转矩阵,想要得到四元数:
这里面表示的第i行j列。在计算过程中,如果接近于0,则其他3个量就会很大,这是很需要考虑别的方式来表示旋转。
## 相似,仿射,射影变换 ##
相似变换
相似变换比之前的欧式变换多了一个自由度:
这个s允许我们对物体进行均匀缩放。
仿射变换
仿射变换不要求A为正交矩阵,只要可逆即可。仿射变换又叫正交投影变换。 ###
射影变换 ### 射影变换是最易般的变换。
左上角可逆,右上角为平移t,左下角为缩放
从真实世界到相机照片的变换可以看作为一个射影变换。如果焦距为无限远,则为仿射变换。
Eigen
最后介绍一些Eigen库相关的东西。Eigen是一个C++开源线性代数库.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<eigen/core> #include<eigen/dense>
Eigen::Matrix<float,3,3,> matrix_33;
Eigen::Vector3d v_3d;
v_3d<<1,2,3;
cout<<v_3d<<endl;
cout<<v_3d(1,0);
matrix_33.transpose();
matrix_33.sum();
matrix_33.trace();
matrix_33.inverse();
matrix_33.determinant();
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(matrix_33*matrix_33.transpose()); cout << eigen_solver.eigenvalues() << endl; cout<< eigen_solver.eigenvectors() << endl;
|
| Module |
Header file |
Contents |
| Core |
#include < Eigen/Core > |
Matrix和Array类,基础的线性代数运算和数组操作 |
| Geometry |
#include< Eigen/Geometry > |
旋转、平移、缩放、2维和3维的各种变换 |
| LU |
#include< Eigen/LU > |
求逆,行列式,LU分解 |
| Cholesky |
#include < Eigen/Cholesky > |
LLT和LDLT Cholesky分解 |
| Householder |
#include< Eigen/Householder > |
豪斯霍尔德变换,用于线性代数运算 |
| SVD |
#include< Eigen/SVD > |
SVD分解 |
| QR |
#include< Eigen/QR > |
QR分解 |
| Eigenvalues |
#include< Eigen/Eigenvalues > |
特征值,特征向量分解 |
| Sparse |
#include< Eigen/Sparse > |
稀疏矩阵的存储和一些基本的线性运算 |
| 稠密矩阵 |
#include< Eigen/Dense > |
包含Core/Geometry/LU/Cholesky/SVD/QR/Eigenvalues模块 |
| 矩阵 |
#include< Eigen/Eigen > |
包括Dense和Sparse(整合库) |
这些东西都被整合在dense模块中。
eigen几何模块:
旋转矩阵直接使用 Matrix3d 或 Matrix3f:
Eigen::Matrix3d
rotationMatrix=Eigen::Matrix3d::Identity();//初始化为一个单位阵。
旋转向量使用 AngleAxis:
Eigen::AngleAxisd rotationVector(M_PI/4,Eigen::Vector3d(0,0,1));
//角+轴:沿 Z 轴旋转 45 度
欧拉角:
Eigen::Vector3d ea0(yaw,pitching,droll);
旋转向量->旋转矩阵:rotationMatrix=rotation_vector.toRotationMatrix();
旋转向量->四元数:Eigen::Quaterniond q = Eigen::Quaterniond (
rotation_vector );
旋转矩阵->四元数:Eigen::Quaterniond q = Eigen::Quaterniond (
rotation_matrix );
四元素->旋转矩阵:Eigen::Matrix3d Rx = q.toRotationMatrix();
旋转向量->欧拉角:Eigen::Vector3d
eulerAngle=rotationVector.matrix().eulerAngles(0,1,2);
旋转矩阵->欧拉角:Eigen::Vector3d euler_angles =
rotation_matrix.eulerAngles ( 2,1,0 ); // ZYX顺序,即roll pitch
yaw顺序
Note
这一讲最后说明了世界坐标和相机坐标的转换。世界坐标下的坐标为,相机坐标下的坐标为,则二者转换为:
值得注意的是,它提到了一般更常用的是从世界坐标到相机坐标的转换,但是从相机坐标到世界坐标的转换却更直观。因为如果相机坐标下为0,则世界坐标就是相机在世界坐标的位置:
上式中正是相机的位置。也是平移向量。
所以从相机坐标到世界坐标的转换可以直接看到相机位置。这也是因为从相机坐标到世界坐标的转换是先旋转后平移的特性。先旋转后平移,则平移向量是不用改变的。