第三讲 三维空间刚体运动
3.0 目标
1.理解三维空间的刚体运动描述方式:旋转矩阵、变换矩阵、四元数和欧拉角。
2.掌握 Eigen 库的矩阵、几何模块使用方法。
3.1 旋转矩阵
3.1.1 点和向量,坐标系
三维空间中,刚体的运动可以用两个概念来表示:旋转和平移。平移比较简单一些,一般用一个表示位移的向量来表示。而旋转则有多种表示方法,例如旋转矩阵、旋转向量等等。
外积还可以表示向量的旋转,任何旋转都可以描述为:绕某个旋转轴顺时针/ 逆时针旋转多少角度.
3.1.2 坐标系间的欧氏变换
与向量间的旋转类似,我们同样可以描述两个坐标系间的旋转关系,其与平移统称为坐标系间的变换关系。常见做法是设定固定不动的一个惯性坐标系(世界坐标系),相机与机器人则是一个移动坐标系。
对于移动坐标系中的某个向量 p p p ,其坐标为 p C p_C pC,在世界坐标系下其坐标为 p W p_W pW,要转换这两个坐标,需要通过一个矩阵 T T T 描述。
对于刚体运动,其中的向量在不同坐标系下的模长与方向不会改变。故我们可以由旋转与平移两部分来构建这个欧氏变换。
首先考虑旋转,设某单位正交基
[
e
1
,
e
2
,
e
3
]
[e_1,e_2,e_3]
[e1,e2,e3] 旋转为
[
e
1
′
,
e
2
′
,
e
3
′
]
[e_1',e_2',e_3']
[e1′,e2′,e3′] ,对于同一个向量
a
a
a ,其在两个坐标系下的坐标为
[
a
1
a
2
a
3
]
\begin{bmatrix}a_1 \\a_2 \\a_3\end{bmatrix}
a1a2a3
和
[
a
1
′
a
2
′
a
3
′
]
\begin{bmatrix}a_1' \\a_2' \\a_3'\end{bmatrix}
a1′a2′a3′
,则有:
[
e
1
,
e
2
,
e
3
]
[
a
1
a
2
a
3
]
=
[
e
1
′
,
e
2
′
,
e
3
′
]
[
a
1
′
a
2
′
a
3
′
]
[\boldsymbol{e}_1, \boldsymbol{e}_2, \boldsymbol{e}_3] \begin{bmatrix} a_1 \\ a_2 \\ a_3 \end{bmatrix}= [\boldsymbol{e}_1', \boldsymbol{e}_2', \boldsymbol{e}_3'] \begin{bmatrix} a_1' \\ a_2' \\ a_3' \end{bmatrix}
[e1,e2,e3]
a1a2a3
=[e1′,e2′,e3′]
a1′a2′a3′
故:
[
a
1
a
2
a
3
]
=
[
e
1
T
e
1
′
e
1
T
e
2
′
e
1
T
e
3
′
e
2
T
e
1
′
e
2
T
e
2
′
e
2
T
e
3
′
e
3
T
e
1
′
e
3
T
e
2
′
e
3
T
e
3
′
]
[
a
1
′
a
2
′
a
3
′
]
≜
R
a
′
\begin{bmatrix} a_1 \\ a_2 \\ a_3 \end{bmatrix}= \begin{bmatrix} \boldsymbol{e}_1^T \boldsymbol{e}_1' & \boldsymbol{e}_1^T \boldsymbol{e}_2' & \boldsymbol{e}_1^T \boldsymbol{e}_3' \\ \boldsymbol{e}_2^T \boldsymbol{e}_1' & \boldsymbol{e}_2^T \boldsymbol{e}_2' & \boldsymbol{e}_2^T \boldsymbol{e}_3' \\ \boldsymbol{e}_3^T \boldsymbol{e}_1' & \boldsymbol{e}_3^T \boldsymbol{e}_2' & \boldsymbol{e}_3^T \boldsymbol{e}_3' \end{bmatrix} \begin{bmatrix} a_1' \\ a_2' \\ a_3' \end{bmatrix} \triangleq \boldsymbol{R} \boldsymbol{a}'
a1a2a3
=
e1Te1′e2Te1′e3Te1′e1Te2′e2Te2′e3Te2′e1Te3′e2Te3′e3Te3′
a1′a2′a3′
≜Ra′
这里我们得到了一个矩阵
R
\boldsymbol R
R ,这个矩阵由两组基的内积组成,构成了旋转前后的同一个向量的坐标变换关系。这个矩阵描述了旋转本身,也被称为旋转矩阵。
性质:行列式为1的正交矩阵。反之,行列式为1的正交矩阵也是一个旋转矩阵。
故其逆描述了一个相反的旋转。
旋转矩阵集合定义如下:
S
O
(
n
)
=
{
R
∈
R
n
×
n
∣
R
R
T
=
I
,
det
(
R
)
=
1
}
SO(n) = \left\{ \boldsymbol{R} \in \mathbb{R}^{n \times n} \mid \boldsymbol{R}\boldsymbol{R}^T = \boldsymbol{I}, \det(\boldsymbol{R}) = 1 \right\}
SO(n)={R∈Rn×n∣RRT=I,det(R)=1}
S
O
(
n
)
SO(n)
SO(n)为特殊正交群,具体解释在下一讲。这个集合由n维空间的旋转矩阵组成。
通过旋转矩阵,我们可以直接讨论两个坐标系之间的旋转变换。即:旋转矩阵可以描述相机的旋转。
至于平移,只需在旋转后直接与平移向量 t 相加即可。
a
=
R
a
+
t
\boldsymbol a=\boldsymbol R\boldsymbol a+\boldsymbol t
a=Ra+t
3.1.3 变换矩阵与齐次坐标
上面的公式虽然完整地表达了欧氏空间的旋转与平移,但其中的变换并不是一个线性关系。若我们进行了两次变换
R
1
,
t
1
R_1,t_1
R1,t1和
R
2
,
t
2
R_2,t_2
R2,t2,且
b
=
R
1
a
+
t
1
,
c
=
R
2
b
+
t
2
b=R_1a+t_1,\ c=R_2b+t_2
b=R1a+t1, c=R2b+t2
但从
a
a
a到
c
c
c的变换为:
c
=
R
2
(
R
1
a
+
t
1
)
+
t
2
c=R_2(R_1a+t_1)+t_2
c=R2(R1a+t1)+t2
在变换多次后形式会变得过于复杂。故我们引入齐次坐标和变换矩阵重写式:
[
a
′
1
]
=
[
R
t
0
T
1
]
[
a
1
]
≜
T
[
a
1
]
\begin{bmatrix} \boldsymbol{a}' \\ 1 \end{bmatrix}= \begin{bmatrix} \boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix} \begin{bmatrix} \boldsymbol{a} \\ 1 \end{bmatrix} \triangleq \boldsymbol{T} \begin{bmatrix} \boldsymbol{a} \\ 1 \end{bmatrix}
[a′1]=[R0Tt1][a1]≜T[a1]
我们在一个三维向量的末尾添加1,改写为了四维向量,称为齐次坐标。对于这个四维向量,我们可以把旋转和平移写在一个矩阵中,使其变为线性关系。该式中
T
T
T称为变换矩阵。我们暂用$ \tilde{a}
表示
表示
表示a$的齐次坐标。
在齐次坐标中,某个点
x
x
x的每个分量同乘一个非零常数
k
k
k后仍表示同一个点,我们可以通过把所有坐标除以最后一项得到一个点唯一的坐标表示。
x
~
=
[
x
,
y
,
z
,
w
]
T
=
[
x
/
w
,
y
/
w
,
z
/
w
,
1
]
T
\tilde{\boldsymbol{x}} = [x, y, z, w]^T = [x/w, y/w, z/w, 1]^T
x~=[x,y,z,w]T=[x/w,y/w,z/w,1]T
此时忽略掉最后一项,这个点的坐标与欧氏空间一样。这时变换为线性的。
b
~
=
T
1
a
~
,
c
~
=
T
2
b
~
⟹
c
~
=
T
2
T
1
a
~
\tilde{b} = T_1 \tilde{a}, \quad \tilde{c} = T_2 \tilde{b} \implies \tilde{c} = T_2 T_1 \tilde{a}
b~=T1a~,c~=T2b~⟹c~=T2T1a~
对于变换矩阵
T
T
T,其左上角为旋转矩阵,右上角为平移向量,左下角为0向量,右下角为1,这种矩阵称为特殊欧式群。
S
E
(
3
)
=
{
T
=
[
R
t
0
T
1
]
∈
R
4
×
4
∣
R
∈
S
O
(
3
)
,
t
∈
R
3
}
SE(3) = \left\{ \boldsymbol{T} = \begin{bmatrix} \boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix} \in \mathbb{R}^{4 \times 4} \mid \boldsymbol{R} \in SO(3), \boldsymbol{t} \in \mathbb{R}^3 \right\}
SE(3)={T=[R0Tt1]∈R4×4∣R∈SO(3),t∈R3}
与
S
O
(
3
)
SO(3)
SO(3)一样,求解该矩阵的逆表示反向转换。
3.2 旋转向量和欧拉角
3.2.1 旋转向量
3维变换矩阵用16个量来表达了6自由度的变换,或许有些冗余了。是否有更紧凑的表达方式?
旋转矩阵和变换矩阵本身有着约束:其必须是正交矩阵,行列式为1。故难以优化和求解。
我们知道,任何旋转都可以用一个旋转轴和一个旋转角来刻画,于是我们可以设定一个向量,其方向与旋转轴一致,长度等于旋转角,这个向量被称为旋转向量(轴角)。这种表示法只需要一个三维向量即可表示旋转。
同样,对于变换矩阵,我们使用一个旋转向量和一个平移向量即可表达一次变换,维数刚好为六维。
这里的旋转向量即下一讲中的李代数。
旋转向量和旋转矩阵之间如何转换?
假如有一个旋转轴为
n
n
n,角度为
θ
\theta
θ的旋转,其对应的旋转向量为
θ
n
\theta n
θn。由罗德里格斯公式可得结果:
R
=
c
o
s
θ
I
+
(
1
−
c
o
s
θ
)
n
n
T
+
s
i
n
θ
n
∧
,
R
∈
R
3
×
3
\boldsymbol R=cos\theta\boldsymbol I+(1-cos\theta)\boldsymbol n\boldsymbol n^T+sin\theta\boldsymbol n^\land, \ \boldsymbol R\in \mathbb R^{3 \times 3}
R=cosθI+(1−cosθ)nnT+sinθn∧, R∈R3×3
其中
∧
\land
∧为向量到反对称的转换符号。反之,我们也可以计算一个旋转矩阵到旋转向量的转换,对于转角
θ
\theta
θ,有:
tr
(
R
)
=
cos
θ
tr
(
I
)
+
(
1
−
cos
θ
)
tr
(
n
n
T
)
+
sin
θ
tr
(
n
∧
)
=
3
cos
θ
+
(
1
−
cos
θ
)
=
1
+
2
cos
θ
.
\begin{align*} \operatorname{tr}(R) &= \cos\theta \operatorname{tr}(I) + (1 - \cos\theta) \operatorname{tr}(nn^T) + \sin\theta \operatorname{tr}(n^\wedge) \\ &= 3\cos\theta + (1 - \cos\theta) \\ &= 1 + 2\cos\theta. \end{align*}
tr(R)=cosθtr(I)+(1−cosθ)tr(nnT)+sinθtr(n∧)=3cosθ+(1−cosθ)=1+2cosθ.
因此:
θ
=
arccos
(
tr
(
R
)
−
1
2
)
.
\theta = \arccos\left( \frac{\operatorname{tr}(\boldsymbol{R}) - 1}{2} \right).
θ=arccos(2tr(R)−1).
由于旋转后的旋转轴向量
n
n
n不发生改变,则:
R
n
=
n
\boldsymbol Rn=n
Rn=n
则转轴
n
n
n为矩阵
R
\boldsymbol R
R特征值1对应的特征向量。求解方程后再归一化,就得到了旋转轴。
3.2.2 欧拉角
常用yaw pitch roll描述一个旋转,等价于绕ZYX轴的旋转。ZYX转角相当于把任意旋转分解为:
1.绕物体的Z轴旋转,得到偏航角yaw
2.绕旋转之后的Y轴旋转,得到俯仰角pitch
3.绕旋转之后的X轴旋转,得到滚转角roll
这样,我们就可以用 [ r , p , y ] T [r,p,y]^T [r,p,y]T这个三维向量描述任意旋转。
3.3 四元数
3.3.1四元数的定义
旋转矩阵用九个量描述三自由度的旋转,具有冗余性:欧拉角和旋转向量是紧凑的,但具有奇异性,且我们无法找到不带奇异性的三维向量描述方式。三维旋转是一个三维流形,想无奇异性地表达它,三个量是不够的。
我们可以用复数集 C \mathbb C C表示复平面上的向量,而复数的乘法可以表示复平面上的旋转。在三维空间中有类似复数的代数——四元数。其既紧凑又没有奇异性,缺点为不够直观、运算稍复杂。
一个四元数
q
q
q包含一个实部和三个虚部:
q
=
q
0
+
q
1
i
+
q
2
j
+
q
3
k
\boldsymbol q=q_0+q_1i+q_2j+q_3k
q=q0+q1i+q2j+q3k
其中
i
,
j
,
k
i,j,k
i,j,k为虚部,虚部满足:
{
i
2
=
j
2
=
k
2
=
−
1
i
j
=
k
,
j
i
=
−
k
j
k
=
i
,
k
j
=
−
i
k
i
=
j
,
i
k
=
−
j
\begin{cases} i^2 = j^2 = k^2 = -1 \\ ij = k,\ ji = -k \\ jk = i,\ kj = -i \\ ki = j,\ ik = -j \end{cases}
⎩
⎨
⎧i2=j2=k2=−1ij=k, ji=−kjk=i, kj=−iki=j, ik=−j
也可以一个标量和一个向量来表示四元数:
q
=
[
s
,
v
]
,
s
=
q
0
∈
R
,
v
=
[
q
1
,
q
2
,
q
3
]
T
∈
R
3
\boldsymbol{q} = [s, \boldsymbol{v}],\quad s = q_0 \in \mathbb{R}, \boldsymbol{v} = [q_1, q_2, q_3]^T \in \mathbb{R}^3
q=[s,v],s=q0∈R,v=[q1,q2,q3]T∈R3
s
s
s为四元数的实部,
v
\boldsymbol v
v为虚部。若一个四元数的虚部为0,称为实四元数,反之若实部为0,称为虚四元数。
设单位四元数 q q q表示一个绕单位向量 n = [ n x , n y , n z ] T n=[n_x,n_y,n_z]^T n=[nx,ny,nz]T,角度为 θ \theta θ的旋转
旋转向量到单位四元数:
q
=
[
cos
(
θ
2
)
,
n
sin
(
θ
2
)
]
T
=
[
cos
(
θ
2
)
,
n
x
sin
(
θ
2
)
,
n
y
sin
(
θ
2
)
,
n
z
sin
(
θ
2
)
]
T
\boldsymbol{q} = \left[ \cos\left( \frac{\theta}{2} \right), \boldsymbol{n} \sin\left( \frac{\theta}{2} \right) \right]^T = \left[ \cos\left( \frac{\theta}{2} \right), n_x \sin\left( \frac{\theta}{2} \right), n_y \sin\left( \frac{\theta}{2} \right), n_z \sin\left( \frac{\theta}{2} \right) \right]^T
q=[cos(2θ),nsin(2θ)]T=[cos(2θ),nxsin(2θ),nysin(2θ),nzsin(2θ)]T
单位四元数到旋转向量:
{
θ
=
2
arccos
q
0
[
n
x
,
n
y
,
n
z
]
T
=
[
q
1
,
q
2
,
q
3
]
T
/
sin
θ
2
\begin{cases} \theta = 2 \arccos q_0 \\ {[n_x, n_y, n_z]}^T = {[q_1, q_2, q_3]}^T / \sin \dfrac{\theta}{2} \end{cases}
⎩
⎨
⎧θ=2arccosq0[nx,ny,nz]T=[q1,q2,q3]T/sin2θ
在四元数中,任意的旋转都可以由两个互为相反数的四元数表示。同理,取
θ
\theta
θ为0则为一个没有任何旋转的实四元数:
q
=
[
±
1
,
0
,
0
,
0
]
T
q_=[\pm1,0,0,0]^T
q=[±1,0,0,0]T
3.3.2四元数的运算
四元数之间运算时与复数相同。设两个四元数:
q
a
=
s
a
+
x
a
i
+
y
a
j
+
z
a
k
q
b
=
s
b
+
x
b
i
+
y
b
j
+
z
b
k
q_a=s_a+x_ai+y_aj+z_ak\\ q_b=s_b+x_bi+y_bj+z_bk\\
qa=sa+xai+yaj+zakqb=sb+xbi+ybj+zbk
则运算规则如下:
$ 加减:\boldsymbol q_a\pm \boldsymbol q_b=[s_a\pm s_b, v_a\pm v_b]$
乘法: q a q b = s a s b − x a x b − y a y b − z a z b + ( s a x b + x a s b + y a z b − z a y b ) i + ( s a y b − x a z b + y a s b + z a x b ) j + ( s a z b + x a y b − y b x a + z a s b ) k \begin{aligned} 乘法: \boldsymbol{q}_a \boldsymbol{q}_b = &\ s_a s_b - x_a x_b - y_a y_b - z_a z_b \\ &+ (s_a x_b + x_a s_b + y_a z_b - z_a y_b) \boldsymbol{i} \\ &+ (s_a y_b - x_a z_b + y_a s_b + z_a x_b) \boldsymbol{j} \\ &+ (s_a z_b + x_a y_b - y_b x_a + z_a s_b) \boldsymbol{k} \end{aligned} 乘法:qaqb= sasb−xaxb−yayb−zazb+(saxb+xasb+yazb−zayb)i+(sayb−xazb+yasb+zaxb)j+(sazb+xayb−ybxa+zasb)k
四元数乘法不可交换。 四元数乘法不可交换。 四元数乘法不可交换。
也可化简为 q a q b = [ s a s b − v a T v b , s a v b + s b v a + v a × v b ] 也可化简为 \ \boldsymbol{q}_a \boldsymbol{q}_b = \left[ s_a s_b - \boldsymbol{v}_a^T \boldsymbol{v}_b,\ s_a \boldsymbol{v}_b + s_b \boldsymbol{v}_a + \boldsymbol{v}_a \times \boldsymbol{v}_b \right] 也可化简为 qaqb=[sasb−vaTvb, savb+sbva+va×vb]
共轭: q a ∗ = s a − x a i − y a j − z a k = [ s a , − v a ] 共轭: \boldsymbol{q}_a^* = s_a - x_a \boldsymbol{i} - y_a \boldsymbol{j} - z_a \boldsymbol{k} = \left[ s_a, -\boldsymbol{v}_a \right] 共轭:qa∗=sa−xai−yaj−zak=[sa,−va]
四元数共轭与自己本身相乘,会得到一个实四元数,其实部为模长的平方: q ∗ q = q q ∗ = [ s a 2 + v T v , 0 ] 四元数共轭与自己本身相乘,会得到一个实四元数,其实部为模长的平方:\\ \boldsymbol{q}^* \boldsymbol{q} = \boldsymbol{q} \boldsymbol{q}^* = \left[ s_a^2 + \boldsymbol{v}^T \boldsymbol{v}, \boldsymbol{0} \right] 四元数共轭与自己本身相乘,会得到一个实四元数,其实部为模长的平方:q∗q=qq∗=[sa2+vTv,0]
模长: ∥ q a ∥ = s a 2 + x a 2 + y a 2 + z a 2 模长:\|\boldsymbol{q}_a\| = \sqrt{s_a^2 + x_a^2 + y_a^2 + z_a^2} 模长:∥qa∥=sa2+xa2+ya2+za2
四元数的乘积的模长等于模长的乘积,单位四元数相乘后仍是单位四元数 ∥ q a q b ∥ = ∥ q a ∥ ∥ q b ∥ 四元数的乘积的模长等于模长的乘积,单位四元数相乘后仍是单位四元数\\ \|\boldsymbol{q}_a \boldsymbol{q}_b\| = \|\boldsymbol{q}_a\|\|\boldsymbol{q}_b\| 四元数的乘积的模长等于模长的乘积,单位四元数相乘后仍是单位四元数∥qaqb∥=∥qa∥∥qb∥
逆: q − 1 = q ∗ / ∥ q ∥ 2 逆:\boldsymbol{q}^{-1} = \boldsymbol{q}^* / \|\boldsymbol{q}\|^2 逆:q−1=q∗/∥q∥2
四元数和自己的逆的乘积为实四元数的 1 : q q − 1 = q − 1 q = 1 四元数和自己的逆的乘积为实四元数的1:\\ \boldsymbol q \boldsymbol q^{-1}=\boldsymbol q^{-1}\boldsymbol q=1 四元数和自己的逆的乘积为实四元数的1:qq−1=q−1q=1
若 q 为单位四元数,则逆和共轭为同一个量。且乘积的逆等于逆的乘积。 ( q a q b ) − 1 = q b − 1 q a − 1 若\boldsymbol q为单位四元数,则逆和共轭为同一个量。且乘积的逆等于逆的乘积。\\ (\boldsymbol{q}_a \boldsymbol{q}_b)^{-1} = \boldsymbol{q}_b^{-1} \boldsymbol{q}_a^{-1} 若q为单位四元数,则逆和共轭为同一个量。且乘积的逆等于逆的乘积。(qaqb)−1=qb−1qa−1
数乘: k q = [ k s , k v ] 数乘:k\boldsymbol q = [ks,k\boldsymbol v] 数乘:kq=[ks,kv]
点乘: q a ⋅ q b = s a s b + x a x b + y a y b + z a z b 点乘:\boldsymbol{q}_a \cdot \boldsymbol{q}_b = s_a s_b + x_a x_b + y_a y_b + z_a z_b 点乘:qa⋅qb=sasb+xaxb+yayb+zazb
3.3.3 用四元数表示旋转
我们可以用四元数表示对一个点的旋转。设点 p = [ x , y , z ] ∈ R 3 \boldsymbol p = [x,y,z] \in \mathbb R^3 p=[x,y,z]∈R3和由轴角 n , θ \boldsymbol n,\theta n,θ指定的旋转,点 p \boldsymbol p p经过旋转后变为 p ′ \boldsymbol p' p′用矩阵描述为 p ′ = R p \boldsymbol p'=\boldsymbol R \boldsymbol p p′=Rp。若用四元数表示,则:
将点用一个虚四元数表示: p = [ 0 , x , y , z ] = [ 0 , v ] \boldsymbol p=[0,x,y,z]=[0,\boldsymbol v] p=[0,x,y,z]=[0,v]
即将四元数的虚部与空间中三个轴对应,随后以四元数
q
\boldsymbol q
q表示这个旋转:
q
=
[
c
o
s
θ
2
,
n
s
i
n
θ
2
]
\boldsymbol q=[cos\frac{\theta}{2},\boldsymbol n sin \frac{\theta}2{}]
q=[cos2θ,nsin2θ]
则旋转后的点
p
′
\boldsymbol p'
p′可表示为如下乘积:
p
′
=
q
p
q
−
1
\boldsymbol p'=\boldsymbol q \boldsymbol p \boldsymbol q^{-1}
p′=qpq−1
计算结果实部为0,为纯虚四元数,其他三个分量表示旋转后的3D点坐标
过程如下:
设
q
=
[
s
,
v
]
,
p
=
[
0
,
u
]
\boldsymbol q = [s, \boldsymbol v], \boldsymbol p = [0, \boldsymbol u]
q=[s,v],p=[0,u],则
q
p
=
[
s
,
v
]
[
0
,
u
]
=
[
−
v
T
u
,
s
u
+
v
×
u
]
\boldsymbol{qp}=[s,\boldsymbol v][0, \boldsymbol u]=[-\boldsymbol v^T\boldsymbol u, s\boldsymbol u+\boldsymbol v\times\boldsymbol u]
qp=[s,v][0,u]=[−vTu,su+v×u]
又
q
−
1
=
[
s
,
−
v
]
\boldsymbol q^{-1}=[s,-\boldsymbol v]
q−1=[s,−v]
则
p
′
=
[
0
,
u
′
]
\boldsymbol p'=[0,\boldsymbol u']
p′=[0,u′]
且
u
′
=
u
c
o
s
θ
+
(
n
×
u
)
s
i
n
θ
+
n
(
n
T
u
)
(
1
−
c
o
s
θ
)
\boldsymbol u'=\boldsymbol ucos\theta+(\boldsymbol n \times \boldsymbol u)sin\theta + \boldsymbol n(\boldsymbol n^T \boldsymbol u)(1-cos\theta)
u′=ucosθ+(n×u)sinθ+n(nTu)(1−cosθ)
过程可视为: q \boldsymbol q q描述了怎么旋转, p \boldsymbol p p表示被旋转的对象, q − 1 \boldsymbol q^{-1} q−1表示撤销多余的影响,保证结果回到三维世界。
3.3.4 四元数到旋转矩阵的转换
任意单位四元数都描述了一个旋转,这个旋转也可以转换为旋转矩阵或旋转向量。我们在以上通过把四元数 q \boldsymbol q q转换为轴角 θ \theta θ和 n \boldsymbol n n,再根据罗德里格斯公式转换为矩阵。计算中涉及到 a r c c o s arccos arccos,代价较大,可以通过一定的技巧绕过:
设四元数
q
=
q
0
+
q
1
i
+
q
2
j
+
q
3
k
\boldsymbol q = q_0+q_1i+q_2j+q_3k
q=q0+q1i+q2j+q3k,对应的旋转矩阵
R
\boldsymbol 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
]
\boldsymbol{R} = \begin{bmatrix} 1 - 2q_2^2 - 2q_3^2 & 2q_1q_2 + 2q_0q_3 & 2q_1q_3 - 2q_0q_2 \\ 2q_1q_2 - 2q_0q_3 & 1 - 2q_1^2 - 2q_3^2 & 2q_2q_3 + 2q_0q_1 \\ 2q_1q_3 + 2q_0q_2 & 2q_2q_3 - 2q_0q_1 & 1 - 2q_1^2 - 2q_2^2 \end{bmatrix}
R=
1−2q22−2q322q1q2−2q0q32q1q3+2q0q22q1q2+2q0q31−2q12−2q322q2q3−2q0q12q1q3−2q0q22q2q3+2q0q11−2q12−2q22
由旋转矩阵到四元数的转换如下。设矩阵
R
=
{
m
i
j
}
,
i
,
j
∈
[
1
,
2
,
3
]
\boldsymbol R=\{m_{ij}\},i,j\in [1,2,3]
R={mij},i,j∈[1,2,3],其对应的四元数如下:
q
0
=
tr
(
R
)
+
1
2
,
q
1
=
m
23
−
m
32
4
q
0
,
q
2
=
m
31
−
m
13
4
q
0
,
q
3
=
m
12
−
m
21
4
q
0
q_0 = \frac{\sqrt{\text{tr}(R) + 1}}{2}, \quad q_1 = \frac{m_{23} - m_{32}}{4q_0}, \quad q_2 = \frac{m_{31} - m_{13}}{4q_0}, \quad q_3 = \frac{m_{12} - m_{21}}{4q_0}
q0=2tr(R)+1,q1=4q0m23−m32,q2=4q0m31−m13,q3=4q0m12−m21
由于
q
\boldsymbol q
q和
−
q
-\boldsymbol q
−q表示同一个旋转,故
R
\boldsymbol R
R对应的四元数不唯一。当
q
0
q_0
q0接近于0时,其余三个分量会很大,导致解不稳定。此时再考虑其他方法进行转换。
3.4 相似、仿射、射影变换
欧氏变换保持了向量的长度和夹角,相当于我们把一个刚体原封不动地进行了移动或旋转,不改变它自身的样子。而其他几种变换则会改变它的外形。它们都拥有类似的矩阵表示。
3.4.1 相似变换
相似变换比欧氏变换多了一个自由度,其允许物体进行均匀缩放,矩阵表示为:
T
S
=
[
s
R
t
0
T
1
]
\boldsymbol{T}_S = \begin{bmatrix} s\boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix}
TS=[sR0Tt1]
旋转部分多了一个缩放因子
s
s
s。相似变换不保持图形的面积不变。
3.4.2 仿射变换
仿射变换矩阵如下:
T
A
=
[
A
t
0
T
1
]
\boldsymbol{T}_A = \begin{bmatrix} \boldsymbol{A} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix}
TA=[A0Tt1]
仿射变换只要求
A
\boldsymbol A
A是一个可逆矩阵,不必是正交矩阵。
仿射变换也叫正交投影,经过仿射变换后,立方体不再是方的,但各个面仍是平行四边形。
3.4.3 射影变换
射影变换是最一般的变换,其矩阵表示为:
T
P
=
[
A
t
a
T
v
]
\boldsymbol{T}_P = \begin{bmatrix} \boldsymbol{A} & \boldsymbol{t} \\ \boldsymbol{a}^T & v \end{bmatrix}
TP=[AaTtv]
其左上为可逆矩阵
A
\boldsymbol A
A,右上为平移
t
\boldsymbol t
t,左下为缩放
a
T
\boldsymbol a^T
aT。当
v
≠
0
v\neq0
v=0时,可以对整个矩阵除以
v
v
v得到一个右下角为1的矩阵,否则得到右下角为0的矩阵。
2D射影变换有8个自由度,3D有15个自由度。
变换名称 | 矩阵形式 | 自由度 | 不变性质 |
---|---|---|---|
欧氏变换 | T = [ R t 0 T 1 ] \boldsymbol{T} = \begin{bmatrix} \boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix} T=[R0Tt1] | 6 | 长度、夹角、体积 |
相似变换 | T S = [ s R t 0 T 1 ] \boldsymbol{T}_S = \begin{bmatrix} s\boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix} TS=[sR0Tt1] | 7 | 体积比 |
仿射变换 | T A = [ A t 0 T 1 ] \boldsymbol{T}_A = \begin{bmatrix} \boldsymbol{A} & \boldsymbol{t} \\ \boldsymbol{0}^T & 1 \end{bmatrix} TA=[A0Tt1] | 12 | 平行比、体积比 |
射影变换 | T P = [ A t a T v ] \boldsymbol{T}_P = \begin{bmatrix} \boldsymbol{A} & \boldsymbol{t} \\ \boldsymbol{a}^T & v \end{bmatrix} TP=[AaTtv] | 15 | 接触平面的相交和相切 |
3.5 Eigen几何模块
#include <iostream>
#include <cmath>
using namespace std;
#include <Eigen/Core>
// Eigen 几何模块
#include <Eigen/Geometry>
/****************************
* 本程序演示了 Eigen 几何模块的使用方法
****************************/
int main ( int argc, char** argv )
{
// Eigen/Geometry 模块提供了各种旋转和平移的表示
// 3D 旋转矩阵直接使用 Matrix3d 或 Matrix3f
Eigen::Matrix3d rotation_matrix = Eigen::Matrix3d::Identity();
// 旋转向量使用 AngleAxis, 它底层不直接是Matrix,但运算可以当作矩阵(因为重载了运算符)
Eigen::AngleAxisd rotation_vector ( M_PI/4, Eigen::Vector3d ( 0,0,1 ) ); //沿 Z 轴旋转 45 度
cout .precision(3);
cout<<"rotation matrix =\n"<<rotation_vector.matrix() <<endl; //用matrix()转换成矩阵
// 也可以直接赋值
rotation_matrix = rotation_vector.toRotationMatrix();
// 用 AngleAxis 可以进行坐标变换
Eigen::Vector3d v ( 1,0,0 );
Eigen::Vector3d v_rotated = rotation_vector * v;
cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;
// 或者用旋转矩阵
v_rotated = rotation_matrix * v;
cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;
// 欧拉角: 可以将旋转矩阵直接转换成欧拉角
Eigen::Vector3d euler_angles = rotation_matrix.eulerAngles ( 2,1,0 ); // ZYX顺序,即roll pitch yaw顺序
cout<<"yaw pitch roll = "<<euler_angles.transpose()<<endl;
// 欧氏变换矩阵使用 Eigen::Isometry
Eigen::Isometry3d T=Eigen::Isometry3d::Identity(); // 虽然称为3d,实质上是4*4的矩阵
T.rotate ( rotation_vector ); // 按照rotation_vector进行旋转
T.pretranslate ( Eigen::Vector3d ( 1,3,4 ) ); // 把平移向量设成(1,3,4)
cout << "Transform matrix = \n" << T.matrix() <<endl;
// 用变换矩阵进行坐标变换
Eigen::Vector3d v_transformed = T*v; // 相当于R*v+t
cout<<"v tranformed = "<<v_transformed.transpose()<<endl;
// 对于仿射和射影变换,使用 Eigen::Affine3d 和 Eigen::Projective3d 即可,略
// 四元数
// 可以直接把AngleAxis赋值给四元数,反之亦然
Eigen::Quaterniond q = Eigen::Quaterniond ( rotation_vector );
cout<<"quaternion = \n"<<q.coeffs() <<endl; // 请注意coeffs的顺序是(x,y,z,w),w为实部,前三者为虚部
// 也可以把旋转矩阵赋给它
q = Eigen::Quaterniond ( rotation_matrix );
cout<<"quaternion = \n"<<q.coeffs() <<endl;
// 使用四元数旋转一个向量,使用重载的乘法即可
v_rotated = q*v; // 注意数学上是qvq^{-1}
cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;
return 0;
}