《视觉SLAM十四讲》自用笔记 第三讲:三维空间刚体运动

news2025/6/9 9:37:06

第三讲 三维空间刚体运动

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} a1a2a3 ,则有:
[ 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] a1a2a3
故:
[ 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 = e1Te1e2Te1e3Te1e1Te2e2Te2e3Te2e1Te3e2Te3e3Te3 a1a2a3 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)={RRn×nRRT=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} [a1]=[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×4RSO(3),tR3}
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+(1cosθ)nnT+sinθn, RR3×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)+(1cosθ)tr(nnT)+sinθtr(n)=3cosθ+(1cosθ)=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=q0R,v=[q1,q2,q3]TR3
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= sasbxaxbyaybzazb+(saxb+xasb+yazbzayb)i+(saybxazb+yasb+zaxb)j+(sazb+xaybybxa+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=[sasbvaTvb, 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=saxaiyajzak=[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] 四元数共轭与自己本身相乘,会得到一个实四元数,其实部为模长的平方:qq=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 逆:q1=q/∥q2

四元数和自己的逆的乘积为实四元数的 1 : q q − 1 = q − 1 q = 1 四元数和自己的逆的乘积为实四元数的1:\\ \boldsymbol q \boldsymbol q^{-1}=\boldsymbol q^{-1}\boldsymbol q=1 四元数和自己的逆的乘积为实四元数的1qq1=q1q=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=qb1qa1

数乘: 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 点乘:qaqb=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=qpq1
计算结果实部为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] q1=[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)(1cosθ)

过程可视为: q \boldsymbol q q描述了怎么旋转, p \boldsymbol p p表示被旋转的对象, q − 1 \boldsymbol q^{-1} q1表示撤销多余的影响,保证结果回到三维世界。

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= 12q222q322q1q22q0q32q1q3+2q0q22q1q2+2q0q312q122q322q2q32q0q12q1q32q0q22q2q3+2q0q112q122q22
由旋转矩阵到四元数的转换如下。设矩阵 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=4q0m23m32,q2=4q0m31m13,q3=4q0m12m21
由于 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2405194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Zephyr 系列 15】构建企业级 BLE 模块通用框架:驱动 + 事件 + 状态机 + 低功耗全栈设计

🧠关键词:Zephyr、BLE 模块、架构设计、驱动封装、事件机制、状态机、低功耗、可维护框架 📌面向读者:希望将 BLE 项目从“Demo 工程”升级为“企业可复用框架”的研发人员与技术负责人 📊预计字数:5500+ 字 🧭 前言:从 Demo 到产品化,架构该如何升级? 多数 BLE…

Docker构建Vite项目内存溢出:从Heap Limit报错到完美解决的剖析

问题现象:诡异的"消失的index.html" 最近在CI/CD流水线中遇到诡异现象:使用Docker构建Vite项目时,dist目录中缺少关键的index.html文件,但本地构建完全正常。报错截图显示关键信息: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out…

Android端口转发

如上图所示&#xff0c;有一个Android设备&#xff0c;Android设备里面有主板&#xff0c;主板上有网络接口和Wi-Fi&#xff0c;网络接口通过网线连接了一个网络摄像头&#xff0c;这就跟电脑一样&#xff0c;电脑即可以通过网线接入一个网络&#xff0c;也可以同时用Wi-Fi接入…

PHP环境极速搭建

一、为什么选择phpStudy VS Code&#xff1f; 作为一名初次接触PHP的开发者&#xff0c;我深知环境配置往往是学习路上的第一道门槛。传统PHP环境搭建需要手动配置Apache/Nginx、PHP解释器、MySQL等多重组件&#xff0c;光是处理版本兼容性和依赖问题就可能耗费半天时间——这…

建造者模式深度解析与实战应用

作者简介 我是摘星&#xff0c;一名全栈开发者&#xff0c;专注 Java后端开发、AI工程化 与 云计算架构 领域&#xff0c;擅长Python技术栈。热衷于探索前沿技术&#xff0c;包括大模型应用、云原生解决方案及自动化工具开发。日常深耕技术实践&#xff0c;乐于分享实战经验与…

代码中文抽取工具并替换工具(以ts为例)

文章目录 基本思路目录结构配置文件AST解析替换代码中文生成Excel启动脚本 基本思路 通过对应语言的AST解析出中文相关信息&#xff08;文件、所在行列等&#xff09;存到临时文件通过相关信息&#xff0c;逐个文件位置替换掉中文基于临时文件&#xff0c;通过py脚本生成Excel…

pgsql batch insert optimization (reWriteBatchedInserts )

reWriteBatchedInserts 是 PostgreSQL JDBC 驱动 提供的一个优化选项&#xff0c;它可以 重写批量插入语句&#xff0c;从而提高插入性能。 作用 当 reWriteBatchedInsertstrue 时&#xff0c;PostgreSQL JDBC 驱动会将 多个单独的 INSERT 语句 转换为 一个多行 INSERT 语句&a…

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(上)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…

华为云Flexus+DeepSeek征文 | 基于DeepSeek-V3构建企业知识库问答机器人实战

作者简介 我是摘星&#xff0c;一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型&#xff0c;将实际使用经验分享给大家&#xff0c;希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 作者简介 1. 引言 2. 技术选型与架构设计 2.1 技…

【Docker 01】Docker 简介

&#x1f308; 一、虚拟化、容器化 ⭐ 1. 什么是虚拟化、容器化 物理机&#xff1a;真实存在的服务器 / 计算机&#xff0c;对于虚拟机来说&#xff0c;物理机为虚拟机提供了硬件环境。虚拟化&#xff1a;通过虚拟化技术将一台计算机虚拟为 1 ~ n 台逻辑计算机。在一台计算机…

AUTOSAR实战教程--DoIP_02_诊断链路建立流程

第一步&#xff1a;DoIP实体车辆声明/诊断仪车辆识别请求 打开激活线以后&#xff0c;DoIP实体发的三帧车辆声明报文。其中包含了DoIP实体的诊断逻辑地址&#xff08;可以类比DoCAN的物理请求/响应地址&#xff09;&#xff0c;对应车辆的VIN码&#xff08;若已配置&#xff0…

音频剪辑软件少之又少好用

我们平时见到的图片以及视频编辑工具非常多&#xff0c;但是音频剪辑软件却是少之又少&#xff0c;更不用说有没有好用的&#xff0c;今天&#xff0c;给大家带来一款非常专业的音频剪辑软件&#xff0c;而且是会员喔。 软件简介 一款手机号登录即可以享受会员的超专业音频剪…

客户端和服务器已成功建立 TCP 连接【输出解析】

文章目录 图片**1. 连接状态解析****第一条记录&#xff08;服务器监听&#xff09;****第二条记录&#xff08;客户端 → 服务器&#xff09;****第三条记录&#xff08;服务器 → 客户端&#xff09;** **2. 关键概念澄清****(1) 0.0.0.0 的含义****(2) 端口号的分配规则** *…

day26-计算机网络-4

1. tcp的11种状态 ss -ant -a 表示看所有状态 -n 表示不将ip解析为主机名 -t 表示tcp 1.1. closed状态&#xff08;客户端、服务端&#xff09; 客户端发起建立连接前的状态服务端启动服务前的状态 1.2. listen状态&#xff08;服务端&#xff09; 服务端软件运行的时候状…

国防科技大学计算机基础慕课课堂学习笔记

1.信息论 香农作为信息论的这个创始人&#xff0c;给出来了这个信息熵的计算方法&#xff0c;为我们现在的这个生活的很多领域奠定了基础&#xff0c;我第一次听说这个信息熵是在这个数学建模里面的理论学习中有关于这个&#xff1a;决策树的模型&#xff0c;在那个问题里面&a…

【第七篇】 SpringBoot项目的热部署

简介 本文介绍了热部署&#xff08;Hot Deployment&#xff09;的概念、使用场景及在IDEA中的配置方法。热部署可在不重启应用的情况下动态更新代码&#xff0c;提升开发效率&#xff0c;适用于调试、微服务架构和自动化测试等场景。文章详细说明了热部署的实现步骤&#xff08…

解决pycharm同一个文件夹下from *** import***仍显示No module named

1、&#xff0c;from ***import *&#xff0c;同文件夹中已有.py文件但是仍然报错No module named 原因是因为pycharm没有把文件夹设置为根目录&#xff0c;只需要在文件夹的上一级设置为根目录即可&#xff0c;测试过如果仅仅将当前的文件夹设置仍然报错&#xff0c;如果把最上…

使用 Redisson 实现分布式锁—解决方案详解

Redisson 是 Redis 官方推荐的 Java 客户端&#xff0c;提供了一系列分布式服务实现&#xff0c;其中分布式锁是其核心功能之一。本文将深入解析 Redisson 分布式锁的实现原理、高级特性和最佳实践。 一、Redisson 分布式锁的优势 与传统实现的对比 特性手动实现Redisson 实现…

结合三维基因建模与智能体技术打造工业软件无码平台

通过深度整合 Protocol Buffers (Protobuf)、gRPC 及 Microsoft AI 技术&#xff0c;构建面向智能制造的高性能、智能化 PLM 平台。 一、Protocol Buffers 深度集成 1. 基因模型标准化定义 三维基因容器 Protobuf 规范&#xff1a; protobuf syntax "proto3"; pa…

Python Day46

Task&#xff1a; 1.不同CNN层的特征图&#xff1a;不同通道的特征图 2.什么是注意力&#xff1a;注意力家族&#xff0c;类似于动物园&#xff0c;都是不同的模块&#xff0c;好不好试了才知道。 3.通道注意力&#xff1a;模型的定义和插入的位置 4.通道注意力后的特征图和热力…