视觉SLAM十四讲2nd—学习笔记(一)

3.1旋转矩阵

点、向量、坐标系

向量aaaa=eae=Σ13aieia=e a_e = \Sigma_1^3 a_i e_ia=eae=Σ13aieie=[e1,e2,e3]e=[e_1, e_2, e_3]e=[e1,e2,e3]为三维空间的一组基(是一个矩阵,每个元素eie_iei是一个列向量),aea_eaeaaa在这组基下的坐标(是一个列向量)。
内积:a⋅b=aeTbe=Σaibi=∣a∣∣b∣cos<a,b>a\cdot b = a_e^T b_e = \Sigma a_i b_i = |a| |b| cos<a,b>ab=aeTbe=Σaibi=a∣∣bcos<a,b>,向量的坐标与基有关,所以右小角有一个⋅e\cdot_ee,但向量的长度、夹角都与基无关,所以不加⋅e\cdot_eeai,bia_i,b_iai,bi分别是ae,bea_e,b_eae,be的元素。
外积:a×b=det([eaeTbeT])=[a2b3−a3b2a3b1−a1b3a1b2−a2b1]=[0−a3a2a30−a1−a2a10]bea\times b = det(\begin{bmatrix} e \\ a_e^T \\ b_e^T \end{bmatrix}) = \begin{bmatrix} a_2b_3 - a_3b_2 \\ a_3b_1 - a_1b_3 \\ a_1b_2 - a_2b_1 \end{bmatrix} = \begin{bmatrix} 0 & -a_3 & a_2 \\ a_3 & 0 & -a_1 \\ -a_2 & a_1 & 0 \end{bmatrix} b_ea×b=det(eaeTbeT)=a2b3a3b2a3b1a1b3a1b2a2b1=0a3a2a30a1a2a10be
[0−a3a2a30−a1−a2a10]\begin{bmatrix} 0 & -a_3 & a_2 \\ a_3 & 0 & -a_1 \\ -a_2 & a_1 & 0 \end{bmatrix}0a3a2a30a1a2a10是一个由aea_eae改写成的反对称矩阵。
注:这么写有点麻烦,后面无特殊说明,a,ba,ba,b就指用同一组基表示的向量。
注:反对称矩阵满足AT=−AA^T = -AAT=A

坐标系间的欧式变换

世界坐标系或惯性坐标系是一个静坐标系,相机坐标系是一个动坐标系。
刚体运动:如果相机运动是一个刚体运动,则两个坐标系间的运动由一个旋转加一个平移组成。或者说两个坐标系间相差一个欧式变换(Euclidean Transform)。

向量aaa在两个坐标系下的坐标为ae,ae′a_e, a_{e'}ae,ae,两个坐标系是经过一次旋转的关系,则有:
ae=Rae′a_e = R a_{e'}ae=Rae,其中R=eTe′R= e^T e'R=eTe称为旋转矩阵或方向余弦矩阵(direction cosine)。
旋转矩阵是行列式为1的正交矩阵;行列式为1的正交矩阵是旋转矩阵。
注:正交矩阵满足AT=A−1A^T=A^{-1}AT=A1,则有ae′=R−1aea_{e'} = R^{-1} a_eae=R1ae,矩阵求逆描述了反向旋转
注:行列式为-1的正交矩阵是瑕旋转矩阵(一次旋转加一次反射)。

nnn维旋转矩阵的集合:SO(n)={R∈Rn×n∣RRT=I,det(R)=I}SO(n) = \{R \in \mathbb R^{n\times n} | RR^T = I, det(R)=I \}SO(n)={RRn×nRRT=I,det(R)=I}SO(n)SO(n)SO(n)是特殊正交群的意思。

欧式变换:两个坐标系是一次旋转加一次平移的关系,ae′=Rae+ta_{e'} = R a_e + tae=Rae+tttt为平移向量
注:将ae′=Rae+ta_{e'} = R a_e + tae=Rae+t简写为a′=Ra+ta' = R a + ta=Ra+t

变换矩阵与齐次坐标

如果向量aaaccc经过两次欧式变换,则有:c=R2(R1a+t1)+t2c = R_2(R_1 a + t_1) + t_2c=R2(R1a+t1)+t2
为了简便表示,引入齐次坐标,将a′=Ra+ta' = R a + ta=Ra+t表示为:
[a′1]=[Rt01][a1]=T[a1]\begin{bmatrix} a' \\ 1 \end{bmatrix} = \begin{bmatrix} R & t \\ 0 & 1 \end{bmatrix} \begin{bmatrix} a \\1 \end{bmatrix} = T \begin{bmatrix} a \\1 \end{bmatrix}[a1]=[R0t1][a1]=T[a1]
用变换矩阵TTT表示欧式变换,aaa用齐次坐标[a1]\begin{bmatrix} a \\1 \end{bmatrix}[a1]代替(为简便表示,aaa就是齐次坐标),则两次欧式变换可写作:c=T2T1ac = T_2T_1 ac=T2T1a

特殊欧式群:SE(3)={T=[Rt01]∈R4×4∣R∈SO(3),t∈R3}SE(3) = \{T = \begin{bmatrix} R & t \\ 0 & 1 \end{bmatrix} \in \mathbb{R}^{4\times 4} | R \in SO(3), t\in \mathbb{R}^3 \}SE(3)={T=[R0t1]R4×4RSO(3),tR3}
欧式变换的逆:T−1=[RT−RTt01]T^{-1} = \begin{bmatrix} R^T & -R^Tt \\ 0 & 1 \end{bmatrix}T1=[RT0RTt1]

3.3 旋转向量与欧拉角

旋转向量

旋转矩阵有9个分量,但一次旋转只有3个自由度,是否有更紧凑的表达?
答:罗德里格斯公式(Rodrigues),用一个向量nnn和一个标量θ\thetaθ表示

任意旋转都可以用一个旋转轴和一个旋转角表示,转轴是单位向量nnn,转角为θ\thetaθ,则有:
R=cosθI+(1−cosθ)nnT+sinθnssmR = cos\theta I + (1-cos \theta) n n^T + sin \theta n^{ssm}R=cosθI+(1cosθ)nnT+sinθnssm
其中,⋅ssm\cdot^{ssm}ssm表示向量的反对称矩阵
缺点:具有奇异性,θ=0\theta=0θ=0时,R=IR=IR=Innn可以是任意向量,即转轴不唯一。

RRR计算n,θn,\thetan,θ
θ=arccos(tr(R)−12)\theta = arccos(\frac{tr(R) - 1}{2})θ=arccos(2tr(R)1)
因为Rn=nRn=nRn=n,所以nnnRRR的特征值为1对应的特征向量。

欧拉角

欧拉角:将一个旋转分解为三次绕不同轴的旋转,最常见的是采用偏航-俯仰-滚转描述旋转。
偏航-俯仰-滚转:绕Z轴旋转α\alphaα,绕旋转后的Y轴旋转β\betaβ,绕旋转后的X轴旋转γ\gammaγ
缺点:用三个标量表示旋转会出现奇异性问题(万向锁问题)。

万向锁:如果绕Y轴旋转90度,那么系统丢失一个自由度(绕X轴的旋转)。绕Z轴旋转α\alphaα再绕旋转后的Y轴旋转909090再绕旋转后的X轴旋转β\betaβ 等于 绕Z轴旋转α±β\alpha \pm \betaα±β再绕旋转后的Y轴旋转909090
欧拉角演示网站 https://danceswithcode.net/engineeringnotes/rotations_in_3d/demo3D/rotations_in_3d_tool.html

3.4 四元数

四元数即紧凑也没有奇异性
平面旋转可由单位复数描述eiθ=cosθ+isinθe^{i \theta} = cos\theta + i sin\thetaeiθ=cosθ+isinθ,三维旋转可由单位四元数描述。

四元数q=[s,v]T,s=q0∈R,v=[q1,q2,q3]T∈R3q=[s,v]^T, s=q_0 \in \mathbb{R}, v=[q_1,q_2,q_3]^T \in \mathbb{R}^3q=[s,v]T,s=q0R,v=[q1,q2,q3]TR3,四元数有三个虚部一个实部。
四元数的加减、乘、逆、数乘和复数类似。

用四元数描述旋转:p′=qpq−1p'=qpq^{-1}p=qpq1,等效为p′=Rpp'=Rpp=Rp
其中,三维空间点p=[0,x,y,z]Tp=[0,x,y,z]^Tp=[0,x,y,z]T(用虚四元数表示),单位四元数qqq
注:用四元数表示旋转,则ppp为虚四元数;用旋转矩阵表示旋转,则ppp为三维向量。需要读者带入当前语境中自行理解。

旋转即可用单位四元数q=[s,v]Tq=[s,v]^Tq=[s,v]T表示,也可用旋转矩阵表示,则前者转换为后者的公式为:
R=vvT+s2I+2svssm+(vssm)2R=vv^T + s^2 I + 2s v^{ssm} + (v^{ssm})^2R=vvT+s2I+2svssm+(vssm)2
反过来的转换公式:
θ=2arccos(s),n=[q1,q2,q3]/sin(θ/2)\theta = 2arccos(s), n=[q_1,q_2,q_3]/sin(\theta/2)θ=2arccos(s),n=[q1,q2,q3]/sin(θ/2)

3.5 相似、仿射、射影变换

相似变换比欧式变换多了一个自由度:缩放,变换矩阵为:
TS=[sRt01]T_S = \begin{bmatrix} sR & t \\ 0 & 1 \end{bmatrix}TS=[sR0t1]
Sim(3)Sim(3)Sim(3)表示三维相似变换的集合(相似变换群)

仿射变换(正交投影)仅要求AAA是一个可逆矩阵,不是必须为一个正交矩阵,变换矩阵为:
TA=[At01]T_A = \begin{bmatrix} A & t \\ 0 & 1 \end{bmatrix}TA=[A0t1]

射影变换是最一般的变换,变换矩阵为:
TA=[AtaTv]T_A = \begin{bmatrix} A & t \\ a^T & v \end{bmatrix}TA=[AaTtv]
其中,AAA是一个可逆矩阵,左下角为缩放,右上角为平移

真实世界到相机照片的变换,如果焦距有限是射影变换,焦距无限是仿射变换。

欧式变换:保持长度、夹角、体积,6自由度;
相似变换:保持体积比,7自由度;
仿射变换:保持平行性、体积比,12自由度;
射影变换:保持接触平面的相交和相切,15自由度。
注:欧式变换的旋转矩阵有正交性,将其自由度缩减为3,再加上平移向量,共6个自由度。
注:射影变换右下角的v=0v=0v=0111,共15个自由度

Python代码

对矩形的变换

import matplotlib.pyplot as plt
import numpy as np

# 绘制矩阵
#rect_coords=[rect_coord1, rect_coord2, ...]
#rect_coord的一列为矩形的一个顶点的齐次坐标
def display_rect(rect_coords): 
    for rect_coord in rect_coords:
        markers = ['o', 's', '^', 'D']
        for i in range(4):
            plt.scatter(rect_coord[:, i][0], rect_coord[:, i][1], marker=markers[i], s=100)

            next_i = (i + 1) % 4
            plt.plot([rect_coord[0, i], rect_coord[0, next_i]],
                     [rect_coord[1, i], rect_coord[1, next_i]],
                     'k-')
    plt.show()

# 欧式变换
angle = 20 / 180 * np.pi
Euclid = np.array([[np.cos(angle), -np.sin(angle), 1],
                   [np.sin(angle), np.cos(angle), -1],
                   [0, 0, 1]])
# print(Euclid)

# 相似变换
scale = 0.5
Sim = Euclid.copy()
Sim[0:2, 0:2] = Euclid[0:2, 0:2] * scale

# 仿射变换
Affine = Euclid.copy()
Affine[0:2, 0:2] = np.array([[0.5, 0.3], [0, 2]])
# print(np.linalg.det(Affine[0:2,0:2])) #判断矩阵是否可逆

# 射影变换
Project = Affine.copy()
Project[2, :] = np.array([2, 0, 1])
# Project[2, :] = np.array([0, 2, 1])

# 矩形
rect_coord = np.array([[0, 0, 1, 1],
                       [0, 1, 1, 0],
                       [1, 1, 1, 1]]) #坐标按顺序排序 才可以正确画出矩形

## 显示1
# display_rect([rect_coord, Euclid @ rect_coord, Sim @ rect_coord])
## 显示2
# display_rect([rect_coord, Affine @ rect_coord])
# 显示3
proj_rect_coord = Project @ rect_coord
proj_rect_coord = proj_rect_coord/proj_rect_coord[2,:]
print(proj_rect_coord)
display_rect([rect_coord, Affine @ rect_coord, proj_rect_coord])

对图像的变换

from scipy import interpolate
from skimage import data
import matplotlib.pyplot as plt
import numpy as np

# 显示图像
def display(img):
    plt.imshow(img, cmap='gray')
    plt.axis('off')
    plt.subplots_adjust(0, 0, 1, 1)
    plt.tight_layout()
    plt.show()

# 对原图像坐标执行变换 #遍历的效率较低应该用矩阵乘法
def transform(X, Y, A):  # A为变换矩阵
    new_X, new_Y = X.copy(), Y.copy()
    for i in range(img.shape[1]):
        for j in range(img.shape[0]):
            new_coord = A @ np.array([X[i, j], Y[i, j], 1])
            new_X[i, j] = new_coord[0]
            new_Y[i, j] = new_coord[1]
    return new_X, new_Y

# 图像
img = data.camera()
display(img)

# 对图像执行变换
# 原图像坐标
x, y = (np.arange(img.shape[1]) - img.shape[1]/2 + 0.5,
        np.arange(img.shape[0]) - img.shape[0]/2 + 0.5)
Y, X = np.meshgrid(y, x)
xy = np.stack([X.ravel(), Y.ravel()]).T
# print(xy)

# 对图像执行变换
new_X, new_Y = transform(X, Y, Euclid)
# display(new_X)
new_img = interpolate.griddata(xy, img.ravel(),
                               (new_X.ravel(), new_Y.ravel()), method='linear')
new_img = new_img.reshape(img.shape)
display(new_img)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值