旋转矩阵、欧拉角、四元数主要用于表示坐标系中的旋转关系,通过三者之间的转换可以减小一些算法的复杂度。
本文主要概述旋转矩阵、欧拉角、四元数的基本理论、三者之间的转换关系以及三者转换在eigen、matlab和pathon上的方法实现。
对于两个三维点p1、p2:
p
1
(
x
1
,
y
1
,
z
1
)
,
p
2
(
x
2
,
y
2
,
z
2
)
p_1\left(x_1, y_1, z_1\right),p_2\left(x_2, y_2, z_2\right)
p1(x1,y1,z1),p2(x2,y2,z2)
由点p1经过旋转矩阵R旋转到p2,则有:
R
=
[
r
11
r
12
r
13
r
21
r
22
r
23
r
31
r
32
r
33
]
,
[
x
2
y
2
z
2
]
=
R
[
x
1
y
1
z
1
]
R=\left[
其中,旋转矩阵为正交矩阵RRT=E。
R
χ
(
θ
)
=
[
1
0
0
0
cos
θ
−
sin
θ
0
sin
θ
cos
θ
]
R_\chi(\theta)=\left[
R
y
(
θ
)
=
[
cos
θ
0
sin
θ
0
1
0
−
sin
θ
0
cos
θ
]
R_y(\theta)=\left[
R
z
(
θ
)
=
[
cos
θ
−
sin
θ
0
sin
θ
cos
θ
0
0
0
1
]
R_z(\theta)=\left[
三维空间内任意一个旋转可表示为依次绕着以上三个旋转轴旋3个角度的组合。这3个角度称为欧拉角。
这三个轴可以指固定的世界坐标系轴,也可以指被旋转的物体坐标系的轴。绕轴旋转次序不同,会导致结果也不同。
对于在三维空间里的一个参考系,任何坐标系的取向,都可以用三个欧拉角来表现。参考系又称为实验室参考系,是静止不动的,而坐标系则固定于刚体,随着刚体的旋转而旋转。
设定xyz-轴为参考系的参考轴。称xy-平面与XY-平面的相交为交线,用英文字母(N)代表。
图中,三个欧拉角分别为:(α,β,γ),其中:
α ∈ [ 0 , 2 π ] , β ∈ [ 0 , Π ] , γ ∈ [ 0 , 2 π ] \alpha \in[0,2 \pi], \beta \in[0, \Pi], \gamma \in[0,2 \pi] α∈[0,2π],β∈[0,Π],γ∈[0,2π]蓝色的轴为:xyz轴。 红色的轴为:XYZ轴。 绿色的线为交线:N。
欧拉角的基本思想是将角位移分解为绕三个互相垂直轴的三个旋转组成的序列。所以,欧拉旋转的三个角,可以对应于Yaw、Pitch和Roll三个旋转矩阵。
三维空间的任意旋转,都可以用绕三维空间的某个轴旋转过某个角度来表示,即所谓的Axis-Angle表示方法。这种表示方法里,Axis可用一个三维向量(x,y,z)来表示,θ可以用一个角度值来表示,直观来讲,一个四维向量(θ,x,y,z)就可以表示出三维空间任意的旋转。注意,这里的三维向量(x,y,z)只是用来表示axis的方向朝向,因此更紧凑的表示方式是用一个单位向量来表示方向axis,而用该三维向量的长度来表示角度值θ。这样以来,可以用一个三维向量(θx,θy,θz)就可以表示出三维空间任意的旋转,前提是其中(x,y,z)是单位向量。这就是旋转向量(Rotation Vector)的表示方式,OpenCV里相机标定部分的rvec就是用这种方法来表示旋转。
单位向量(x,y,z)旋转角度θ后的四元数:
(
cos
θ
2
,
x
∗
sin
θ
2
,
y
∗
sin
θ
2
,
z
∗
sin
θ
2
)
\left(\cos \frac{\theta}{2}, x * \sin \frac{\theta}{2}, y * \sin \frac{\theta}{2}, z * \sin \frac{\theta}{2}\right)
(cos2θ,x∗sin2θ,y∗sin2θ,z∗sin2θ)
对于三维坐标的旋转,可以通过四元数乘法直接操作,与旋转矩阵操作可以等价,但是表示方式更加紧凑,计算量也可以小一些。
q = q 0 + q 1 i + q 2 j + q 3 k = [ s , v ] \mathbf{q}=q_0+q_1 i+q_2 j+q_3 k=[s, \mathbf{v}] q=q0+q1i+q2j+q3k=[s,v]
其中,q0, q1, q2, q3均为实数,s=q0, v=[q1, q2, q3],i2=j2=k2=-1 。
对于i,j,k本身的几何含义可以理解为一种旋转,其中i代表x轴与y轴相交平面中x轴正向向y轴正向的旋转,j旋转代表z轴与x轴相交平面中z轴正向向x轴正向的旋转,k旋转代表y轴与z轴相交平面中y轴正向向z轴正向的旋转,-i,-j,-k分别代表i,j,k的反向旋转。
设三个轴x,y,z的欧拉角分别为θx,θy,θz,正弦值、余弦值分别为sx,cx,sy,cy,sz,cz。那么旋转矩阵为:
R
(
θ
x
,
θ
y
,
θ
z
)
=
R
z
(
θ
z
)
R
y
(
θ
y
)
R
x
(
θ
x
)
=
[
C
y
C
z
C
z
S
x
S
y
−
C
x
S
z
S
x
S
z
+
C
x
C
z
S
y
C
y
S
z
C
x
C
z
+
S
x
S
y
S
z
C
x
S
y
S
z
−
C
z
S
z
−
S
y
C
y
S
x
C
x
C
y
]
R
=
[
r
11
r
12
r
13
r
21
r
22
r
23
r
31
r
32
r
33
]
=
[
C
y
C
z
C
z
S
x
S
y
−
C
x
S
z
S
x
S
z
+
C
x
C
z
S
y
C
y
S
z
C
x
C
z
+
S
x
S
y
S
z
C
x
S
y
S
z
−
C
z
S
z
−
S
y
C
y
S
x
C
x
C
y
]
解方程得:
θ
x
=
atan
2
(
r
32
,
r
33
)
θ
y
=
atan
2
(
−
r
31
,
r
32
2
+
r
33
2
)
θ
z
=
atan
2
(
r
21
,
r
11
)
其中:atan2(y,x)求的是y/x的反正切,其返回值为[-pai, +pai]之间的一个数。
情况1:
将四元数转化为轴角θ与向量(x,y,z):
q
=
(
θ
x
y
z
)
T
\mathbf{q}=\left(
利用Rodrigues公式可以由单位向量旋转角度θ后的四元数求得旋转矩阵R:
R
=
e
ω
θ
=
I
+
ω
×
sin
θ
+
ω
×
2
(
1
−
cos
θ
)
=
[
cos
θ
+
x
2
(
1
−
cos
θ
)
−
z
sin
θ
+
x
y
(
1
−
cos
θ
)
y
sin
θ
+
x
z
(
1
−
cos
θ
)
z
sin
θ
+
x
y
(
1
−
cos
θ
)
cos
θ
+
y
2
(
1
−
cos
θ
)
−
x
sin
θ
+
y
z
(
1
−
cos
θ
)
−
y
sin
θ
+
x
z
(
1
−
cos
θ
)
x
sin
θ
+
y
z
(
1
−
cos
θ
)
cos
θ
+
z
2
(
1
−
cos
θ
)
]
情况2:
已知四元数为,
q
=
q
0
+
q
1
i
+
q
2
j
+
q
3
k
=
[
s
,
v
]
\mathbf{q}=q_0+q_1 i+q_2 j+q_3 k=[s, \mathbf{v}]
q=q0+q1i+q2j+q3k=[s,v]
利用Rodrigues公式可以由四元数求得旋转矩阵R,
q
=
q
0
+
q
1
i
+
q
2
j
+
q
3
k
=
[
s
,
v
]
\mathbf{q}=q_0+q_1 i+q_2 j+q_3 k=[s, \mathbf{v}]
q=q0+q1i+q2j+q3k=[s,v]
R
R
R
=
[
1
−
2
q
2
2
−
2
q
3
2
2
q
1
q
2
−
2
q
0
q
3
2
q
1
q
3
+
2
q
0
q
2
2
q
1
q
2
+
2
q
0
q
3
1
−
2
q
1
2
−
2
q
3
2
2
q
2
q
3
−
2
q
0
q
1
2
q
1
q
3
−
2
q
0
q
2
2
q
2
q
3
+
2
q
0
q
1
1
−
2
q
1
2
−
2
q
2
2
=\left[
q
0
=
1
+
r
11
+
r
22
+
r
33
2
.
q
1
=
r
32
−
r
23
4
q
0
.
q
2
=
r
13
−
r
31
4
q
0
q
3
=
r
21
−
r
12
4
q
0
.
其中, 要满足
q
0
≠
0
,
1
+
r
11
+
r
22
+
r
33
>
0
q_0 \neq 0,1+r_{11}+r_{22}+r_{33}>0
q0=0,1+r11+r22+r33>0, 即
1
+
tr
(
R
)
>
1+\operatorname{tr}(R)>
1+tr(R)> 0。若
q
0
q_0
q0 趋近于 0, 则求解结果略有不同。
如依次绕
z
,
y
,
x
z, y, x
z,y,x 分别旋转一个固定角度, 使用 yaw, pitch, roll 分别表示物体绕,
x
,
y
,
z
x, y, z
x,y,z 的旋转角度, 记为
ψ
,
θ
,
ϕ
。
\psi, \theta, \phi_{\text {。 }}
ψ,θ,ϕ。
[
ϕ
θ
ψ
]
=
[
arctan
2
(
q
0
q
1
+
q
2
q
3
)
1
−
2
(
q
1
2
+
q
2
2
)
arcsin
(
2
(
q
0
q
2
−
q
3
q
1
)
)
arctan
2
(
q
0
q
3
+
q
1
q
2
)
1
−
2
(
q
2
2
+
q
3
2
)
]
\left[
注意,
arctan
\arctan
arctan 和
arcsin
\arcsin
arcsin 的结果
[
−
Π
2
,
Π
2
]
\left[-\frac{\Pi}{2}, \frac{\Pi}{2}\right]
[−2Π,2Π], 这并不能覆盖所有朝向(对 于
θ
\theta
θ 角
[
−
Π
2
,
Π
2
]
\left[-\frac{\Pi}{2}, \frac{\Pi}{2}\right]
[−2Π,2Π] 的取值范围已经满足), 因此需要用 atan2 来代替
arctan
∘
\arctan _{\circ}
arctan∘
[
ϕ
θ
ψ
]
=
[
atan
2
(
2
(
q
0
q
1
+
q
2
q
3
)
,
1
−
2
(
q
1
2
+
q
2
2
)
)
asin
(
2
(
q
0
q
2
−
q
3
q
1
)
)
atan
2
(
2
(
q
0
q
3
+
q
1
q
2
)
,
1
−
2
(
q
2
2
+
q
3
2
)
)
]
\left[
其中,
atan
2
(
y
,
x
)
\operatorname{atan} 2(y, x)
atan2(y,x) 为
C
+
+
\mathrm{C}++
C++ 中的函数, 求的是
y
/
x
\mathrm{y} / \mathrm{x}
y/x 的反正切, 其返 回值为
[
−
Π
,
+
Π
]
[-\Pi,+\Pi]
[−Π,+Π] 之间的一个数。
q
I
B
=
[
cos
(
ψ
/
2
)
0
0
sin
(
ψ
/
2
)
]
[
cos
(
θ
/
2
)
0
sin
(
θ
/
2
)
0
]
[
cos
(
ϕ
/
2
)
sin
(
ϕ
/
2
)
0
0
]
=
[
cos
(
ϕ
/
2
)
cos
(
θ
/
2
)
cos
(
ψ
/
2
)
+
sin
(
ϕ
/
2
)
sin
(
θ
/
2
)
sin
(
ψ
/
2
)
sin
(
ϕ
/
2
)
cos
(
θ
/
2
)
cos
(
ψ
/
2
)
−
cos
(
ϕ
/
2
)
sin
(
θ
/
2
)
sin
(
ψ
/
2
)
cos
(
ϕ
/
2
)
sin
(
θ
/
2
)
cos
(
ψ
/
2
)
+
sin
(
ϕ
/
2
)
cos
(
θ
/
2
)
sin
(
ψ
/
2
)
cos
(
ϕ
/
2
)
cos
(
θ
/
2
)
sin
(
ψ
/
2
)
−
sin
(
ϕ
/
2
)
sin
(
θ
/
2
)
cos
(
ψ
/
2
)
]
Eigen库中三种形式可表示为:
// 初始化旋转矩阵
Eigen::Matrix3d rotation_matrix;
rotation_matrix<<x_00,x_01,x_02,x_10,x_11,x_12,x_20,x_21,x_22;
// 初始化欧拉角
Eigen::Vector3d eulerAngle(yaw,pitch,roll);
// 初始化四元数
Eigen::Quaterniond quaternion(w,x,y,z);
Eigen::AngleAxisd rollAngle(AngleAxisd(eulerAngle(2),Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(eulerAngle(1),Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(eulerAngle(0),Vector3d::UnitZ()));
Eigen::Matrix3d rotation_matrix;
rotation_matrix=yawAngle*pitchAngle*rollAngle;
// Z-Y-X,即RPY
Eigen::Vector3d eulerAngle=rotation_matrix.eulerAngles(2,1,0);
Eigen::Matrix3d rotation_matrix;
rotation_matrix=quaternion.matrix();
// 两种方法均可
Eigen::Matrix3d rotation_matrix;
rotation_matrix=quaternion.toRotationMatrix();
Eigen::Quaterniond quaternion(rotation_matrix);
// 两种方法均可
Eigen::Quaterniond quaternion;quaternion=rotation_matrix;
Eigen::Vector3d eulerAngle=quaternion.matrix().eulerAngles(2,1,0);
Eigen::AngleAxisd rollAngle(AngleAxisd(eulerAngle(2),Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(eulerAngle(1),Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(eulerAngle(0),Vector3d::UnitZ()));
Eigen::Quaterniond quaternion;
quaternion=yawAngle*pitchAngle*rollAngle;
eul2rotm()
rotm2eul()
quat2rotm()
rotm2quat()
eul2quat()
eul2quat()
可使用scipy包中的scipy.spatial.transform.Rotation实现。
from_euler()
as_matrix()
from_matrix()
as_euler()
from_quat()
as_matrix()
from_matrix()
as_quat()
from_quat()
as_euler()
from_euler()
as_quat()
如果觉得我的文章对你起到了些许的帮助,做下手指操点击下面的大拇指👍感谢~
我是专注自动驾驶、LiDAR感知、三维点云处理、激光SLAM领域的阿川,欢迎各位志同道合的朋友在下面积极留言。欲将心事付瑶琴,希望能在交流中收获知识、经验和挚友🌞