线性(向量)空间基本知识
1)线性空间 :
n 维有序数组组成的向量的全体集合构成的空间称为 n 维向量空间,也即 n 维线性空间。
2)线性相关与线性无关:
在n维线性空间中的n个n维向量中,若存在1个向量,可以由其它n-l个n维向量线性表示,则称这n个n维向量是线性相关的。此时,n个n维向量组成的矩阵的秩小于n。
若不存在可以被其他n-1个向量线性表示的向量,则称这n个向量是线性无关的。n个n维向量组成的矩阵的秩等于n,即矩阵满秩。
3)向量正交:
两个同维向量的点积等于零,称这两个向量正交。当n个n维向量两两点积为零时,称这n个向量两两正交。
4)向量的模:
n维向量的各个分量的平方和再开方,在三维中表示向量的空间长度。
5)线性空间的基:
在n维线性空间中,若存在n个n维向量,它们线性无关且可以线性表示该线性空间中的任意n维向量,则称这n个n维向量为该线性空间的一组基,其中的向量称为基向量。例如,三维空间中最常用的一组基为 ( 1 , 0 , 0 ) T (1,0,0)^T (1,0,0)T、 ( 0 , 1 , 0 ) T (0,1,0)^T (0,1,0)T、 ( 0 , 0 , 1 ) T (0,0,1)^T (0,0,1)T。
6)正交积与标准(规范)正交积:
当一组基中的各个基向量两两正交时,这组基称为正交积。同时,若各个基向量的模均为1,则称这组基为标准正交积。
7)向量的坐标空间表示方法:
对于n维线性空间中的任意一个位置,都可以由一组基以及这组基下的坐标表示。例如,在三维空间中的点位置,用最一般最常用的标准正交积 ( 1 , 0 , 0 ) T (1,0,0)^T (1,0,0)T、 ( 0 , 1 , 0 ) T (0,1,0)^T (0,1,0)T、 ( 0 , 0 , 1 ) T (0,0,1)^T (0,0,1)T 表示的公式为下式。
为了描述线性空间的坐标单位转换比以及坐标轴原点的位置,需要在三维的基础上增加一个维度,即上式需要扩充为下式。其中第四个列向量的前三位是坐标轴原点的位置,第四位是坐标单位转换比,其值通常为1。
标准正交基中向量的末尾需要补充零元素来构成向量表达式。该式与对应的矩阵表示形式等价。
不失一般性,对于三维空间中任意位置作为坐标原点且任意满足右手法则的标准正交基构成的坐标系统框架有如下一般表达式。坐标原点为 ( R x , R y , R z ) T (R_x,R_y,R_z)^T (Rx,Ry,Rz)T,坐标单位转换比为 m,坐标轴单位向量组为 ( X x , X y , X z ) T (X_x,X_y,X_z)^T (Xx,Xy,Xz)T, ( Y x , Y y , Y z ) T (Y_x,Y_y,Y_z)^T (Yx,Yy,Yz)T, ( Z x , Z y , Z z ) T (Z_x,Z_y,Z_z)^T (Zx,Zy,Zz)T。
向量
REF:https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/
向量点乘
点乘(Dot Product),记作 v ⃗ ⋅ k ⃗ \vec{v}·\vec{k} v ⋅k
两个向量的点乘等于他们数乘结果乘上他们夹角的余弦值:
v
⃗
⋅
k
⃗
=
∥
v
∥
⃗
⋅
∥
k
∥
⃗
⋅
c
o
s
θ
\vec{v}·\vec{k} = \vec{\left \| v \right \|} · \vec{\left \|k \right \|}·cos\theta
v
⋅k
=∥v∥
⋅∥k∥
⋅cosθ
90 度的余弦角是 0,因此点乘能够测试出两个向量是否正交(Orthogonal),且当
v
⃗
\vec{v}
v
和
k
⃗
\vec{k}
k
都是单位向量时,公式就简化为:
v
⃗
⋅
k
⃗
=
1
⋅
1
⋅
c
o
s
θ
=
c
o
s
θ
\vec{v}·\vec{k} = 1·1·cos\theta = cos\theta
v
⋅k
=1⋅1⋅cosθ=cosθ
而 0 度的余弦角是 1,因此此时点乘能够用来测试两个向量是否平行。
当然,点乘还能计算两个向量之间的夹角。
点乘是通过将对应分量逐个相乘,然后再把所得积相加来计算的。两个单位向量的(你可以验证它们的长度都为1)点乘会像是这样:
(
0.6
−
0.8
0
)
⋅
(
0
1
0
)
=
(
0.6
∗
0
)
+
(
−
0.8
∗
1
)
+
(
0
∗
0
)
=
−
0.8
\begin{pmatrix} \color{red}{0.6} \\ -\color{green}{0.8} \\ \color{blue}0 \end{pmatrix} \cdot \begin{pmatrix} \color{red}0 \\ \color{green}1 \\ \color{blue}0 \end{pmatrix} = (\color{red}{0.6} * \color{red}0) + (-\color{green}{0.8} * \color{green}1) + (\color{blue}0 * \color{blue}0) = -0.8
⎝⎛0.6−0.80⎠⎞⋅⎝⎛010⎠⎞=(0.6∗0)+(−0.8∗1)+(0∗0)=−0.8
要计算两个单位向量间的夹角,我们可以使用反余弦函数
c
o
s
−
1
cos^{-1}
cos−1 ,可得结果是 143.1 度。现在我们很快就计算出了这两个向量的夹角。点乘会在计算光照的时候非常有用。
叉乘
叉乘只在3D空间中有定义,它需要两个不平行向量作为输入,生成一个正交于两个输入向量的第三个向量。
下面的图片展示了3D空间中叉乘的样子:
两个正交向量A和B叉积公式:
( A x A y A z ) × ( B x B y B z ) = ( A y ⋅ B z − A z ⋅ B y A z ⋅ B x − A x ⋅ B z A x ⋅ B y − A y ⋅ B x ) \begin{pmatrix} \color{red}{A_{x}} \\ \color{green}{A_{y}} \\ \color{blue}{A_{z}} \end{pmatrix} \times \begin{pmatrix} \color{red}{B_{x}} \\ \color{green}{B_{y}} \\ \color{blue}{B_{z}} \end{pmatrix} = \begin{pmatrix} \color{green}{A_{y}} \cdot \color{blue}{B_{z}} - \color{blue}{A_{z}} \cdot \color{green}{B_{y}} \\ \color{blue}{A_{z}} \cdot \color{red}{B_{x}} - \color{red}{A_{x}} \cdot \color{blue}{B_{z}} \\ \color{red}{A_{x}} \cdot \color{green}{B_{y}} - \color{green}{A_{y}} \cdot \color{red}{B_{x}} \end{pmatrix} ⎝⎛AxAyAz⎠⎞×⎝⎛BxByBz⎠⎞=⎝⎛Ay⋅Bz−Az⋅ByAz⋅Bx−Ax⋅BzAx⋅By−Ay⋅Bx⎠⎞
矩阵变换
REF:https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/
缩放
对一个向量进行**缩放(Scaling)**就是对向量的长度进行缩放,而保持它的方向不变。
均匀缩放(Uniform Scale):对空间中的每个轴都使用相同的缩放因子(Scaling Factor)
不均匀缩放(Non-uniform):对空间中的轴有使用了不同的缩放因子
如果我们把缩放变量表示为
(
S
1
,
S
2
,
S
3
)
(\color{red}{S_1}, \color{green}{S_2}, \color{blue}{S_3})
(S1,S2,S3) 我们可以为任意向量
(
x
,
y
,
z
)
(x,y,z)
(x,y,z) 定义一个缩放矩阵:
[
S
1
0
0
0
0
S
2
0
0
0
0
S
3
0
0
0
0
1
]
⋅
(
x
y
z
1
)
=
(
S
1
⋅
x
S
2
⋅
y
S
3
⋅
z
1
)
\begin{bmatrix} \color{red}{S_1} & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{S_2} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}{S_3} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{S_1} \cdot x \\ \color{green}{S_2} \cdot y \\ \color{blue}{S_3} \cdot z \\ 1 \end{pmatrix}
⎣⎢⎢⎡S10000S20000S300001⎦⎥⎥⎤⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎜⎜⎛S1⋅xS2⋅yS3⋅z1⎠⎟⎟⎞
注意,第四个缩放向量仍然是 1,因为在3D空间中缩放 w 分量是无意义的。w 分量另有其他用途,在后面我们会看到。
位移
位移(Translation) 是在原始向量的基础上加上另一个向量从而获得一个在不同位置的新向量的过程,从而在位移向量基础上移动了原始向量。
和缩放矩阵一样,在 4×4 矩阵上有几个特别的位置用来执行特定的操作,对于位移来说它们是第四列最上面的 3 个值。如果我们把位移向量表示为
(
T
x
,
T
y
,
T
z
)
(\color{red}{T_x},\color{green}{T_y},\color{blue}{T_z})
(Tx,Ty,Tz),我们就能把位移矩阵定义为:
[
1
0
0
T
x
0
1
0
T
y
0
0
1
T
z
0
0
0
1
]
⋅
(
x
y
z
1
)
=
(
x
+
T
x
y
+
T
y
z
+
T
z
1
)
\begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}{T_x} \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}{T_y} \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}{T_z} \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + \color{red}{T_x} \\ y + \color{green}{T_y} \\ z + \color{blue}{T_z} \\ 1 \end{pmatrix}
⎣⎢⎢⎡100001000010TxTyTz1⎦⎥⎥⎤⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎜⎜⎛x+Txy+Tyz+Tz1⎠⎟⎟⎞
齐次坐标(Homogeneous Coordinates)
向量的
w分量也叫齐次坐标。想要从齐次向量得到3D向量,我们可以把x、y和z坐标分别除以w坐标。我们通常不会注意这个问题,因为w分量通常是1.0。使用齐次坐标有几点好处:它允许我们在3D向量上进行位移
如果一个向量的齐次坐标是
0,这个坐标就是方向向量(Direction Vector),因为w坐标是0,这个向量就不能位移
旋转
2D 或 3D 空间中的旋转用角(Angle)来表示。角可以是角度制或弧度制的,周角是 360 角度或 2PI 弧度。我个人更喜欢用角度,因为它们看起来更直观。
不过大多数旋转函数需要用弧度制的角,它们能够进行相互转换:
- 弧度转角度:
角度 = 弧度 * (180.0f / PI)- 角度转弧度:
弧度 = 角度 * (PI / 180.0f)
下图中展示的 2D 向量
v
ˉ
\color{red}{\bar{v}}
vˉ 是由
k
ˉ
\color{green}{\bar{k}}
kˉ 向右旋转 72 度所得的:
在3D空间中旋转需要定义一个角和一个旋转轴(Rotation Axis)。当2D向量在3D空间中旋转时,我们把旋转轴设为 z 轴。
给定一个角度,可以把一个向量变换为一个经过旋转的新向量。这通常是使用一系列正弦(sin)和余弦函数(cos)各种巧妙的组合得到的
旋转矩阵在3D空间中每个单位轴都有不同定义,旋转角度用 θ 表示:
沿 x 轴旋转:
[
1
0
0
0
0
cos
θ
−
sin
θ
0
0
sin
θ
cos
θ
0
0
0
0
1
]
⋅
(
x
y
z
1
)
=
(
x
cos
θ
⋅
y
−
sin
θ
⋅
z
sin
θ
⋅
y
+
cos
θ
⋅
z
1
)
\begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{\cos \theta} & - \color{green}{\sin \theta} & \color{green}0 \\ \color{blue}0 & \color{blue}{\sin \theta} & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x \\ \color{green}{\cos \theta} \cdot y - \color{green}{\sin \theta} \cdot z \\ \color{blue}{\sin \theta} \cdot y + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
⎣⎢⎢⎡10000cosθsinθ00−sinθcosθ00001⎦⎥⎥⎤⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎜⎜⎛xcosθ⋅y−sinθ⋅zsinθ⋅y+cosθ⋅z1⎠⎟⎟⎞
沿 y 轴旋转:
[
cos
θ
0
sin
θ
0
0
1
0
0
−
sin
θ
0
cos
θ
0
0
0
0
1
]
⋅
(
x
y
z
1
)
=
(
cos
θ
⋅
x
+
sin
θ
⋅
z
y
−
sin
θ
⋅
x
+
cos
θ
⋅
z
1
)
\begin{bmatrix} \color{red}{\cos \theta} & \color{red}0 & \color{red}{\sin \theta} & \color{red}0 \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}0 \\ - \color{blue}{\sin \theta} & \color{blue}0 & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x + \color{red}{\sin \theta} \cdot z \\ y \\ - \color{blue}{\sin \theta} \cdot x + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
⎣⎢⎢⎡cosθ0−sinθ00100sinθ0cosθ00001⎦⎥⎥⎤⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎜⎜⎛cosθ⋅x+sinθ⋅zy−sinθ⋅x+cosθ⋅z1⎠⎟⎟⎞
沿 z 轴旋转:
[
cos
θ
−
sin
θ
0
0
sin
θ
cos
θ
0
0
0
0
1
0
0
0
0
1
]
⋅
(
x
y
z
1
)
=
(
cos
θ
⋅
x
−
sin
θ
⋅
y
sin
θ
⋅
x
+
cos
θ
⋅
y
z
1
)
\begin{bmatrix} \color{red}{\cos \theta} & - \color{red}{\sin \theta} & \color{red}0 & \color{red}0 \\ \color{green}{\sin \theta} & \color{green}{\cos \theta} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x - \color{red}{\sin \theta} \cdot y \\ \color{green}{\sin \theta} \cdot x + \color{green}{\cos \theta} \cdot y \\ z \\ 1 \end{pmatrix}
⎣⎢⎢⎡cosθsinθ00−sinθcosθ0000100001⎦⎥⎥⎤⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎜⎜⎛cosθ⋅x−sinθ⋅ysinθ⋅x+cosθ⋅yz1⎠⎟⎟⎞
关于正余弦组合问题可看下面的仿射变换小节
利用旋转矩阵我们可以把任意位置向量沿一个单位旋转轴进行旋转。也可以将多个矩阵复合,比如先沿着x轴旋转再沿着y轴旋转。但是这会很快导致一个问题——万向节死锁(Gimbal Lock,可以看看这个视频(优酷)来了解)。
避免万向节死锁的真正解决方案是使用四元数(Quaternion),它不仅更安全,而且计算会更有效率。
对四元数的理解会用到非常多的数学知识。如果想了解四元数与3D旋转之间的关系,可以来阅读教程。如果你对万向节死锁的概念仍不是那么清楚,可以来阅读教程的Bonus章节。
现在3Blue1Brown也已经开始了一个四元数的视频系列,他采用球极平面投影(Stereographic Projection)的方式将四元数投影到3D空间,同样有助于理解四元数的概念(仍在更新中):https://www.youtube.com/watch?v=d4EgbgTm0Bg
矩阵的组合
根据矩阵之间的乘法,我们可以把多个变换组合到一个矩阵中。
假设我们有一个顶点
(
x
,
y
,
z
)
(x, y, z)
(x,y,z),我们希望将其缩放 2 倍,然后位移 $(1, 2, 3) $个单位。结果的变换矩阵看起来像这样:
T
r
a
n
s
.
S
c
a
l
e
=
[
1
0
0
1
0
1
0
2
0
0
1
3
0
0
0
1
]
.
[
2
0
0
0
0
2
0
0
0
0
2
0
0
0
0
1
]
=
[
2
0
0
1
0
2
0
2
0
0
2
3
0
0
0
1
]
Trans . Scale = \begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}1 \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}2 \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}3 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} . \begin{bmatrix} \color{red}2 & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}2 & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}2 & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} = \begin{bmatrix} \color{red}2 & \color{red}0 & \color{red}0 & \color{red}1 \\ \color{green}0 & \color{green}2 & \color{green}0 & \color{green}2 \\ \color{blue}0 & \color{blue}0 & \color{blue}2 & \color{blue}3 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix}
Trans.Scale=⎣⎢⎢⎡1000010000101231⎦⎥⎥⎤.⎣⎢⎢⎡2000020000200001⎦⎥⎥⎤=⎣⎢⎢⎡2000020000201231⎦⎥⎥⎤
注意,当矩阵相乘时我们先写位移再写缩放变换的。矩阵乘法是不遵守交换律的,这意味着它们的顺序很重要。
当矩阵相乘时,在最右边的矩阵是第一个与向量相乘的,所以你应该从右向左读这个乘法。
建议在组合矩阵时,先进行缩放操作,然后是旋转,最后才是位移,否则它们会(消极地)互相影响。
比如,如果你先位移再缩放,位移的向量也会同样被缩放(比如向某方向移动 2 米,2 米也许会被缩放成 1 米)!
用最终的变换矩阵左乘我们的向量会得到以下结果:
[
2
0
0
1
0
2
0
2
0
0
2
3
0
0
0
1
]
.
[
x
y
z
1
]
=
[
2
x
+
1
2
y
+
2
2
z
+
3
1
]
\begin{bmatrix} \color{red}2 & \color{red}0 & \color{red}0 & \color{red}1 \\ \color{green}0 & \color{green}2 & \color{green}0 & \color{green}2 \\ \color{blue}0 & \color{blue}0 & \color{blue}2 & \color{blue}3 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} . \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} = \begin{bmatrix} \color{red}2x + \color{red}1 \\ \color{green}2y + \color{green}2 \\ \color{blue}2z + \color{blue}3 \\ 1 \end{bmatrix}
⎣⎢⎢⎡2000020000201231⎦⎥⎥⎤.⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡2x+12y+22z+31⎦⎥⎥⎤
向量先缩放 2 倍,然后位移了
(
1
,
2
,
3
)
(1, 2, 3)
(1,2,3) 个单位。
仿射变换
REF:https://blog.csdn.net/u011681952/article/details/98942207
概念
仿射变换(Affine Transformation)其实是另外两种简单变换的叠加:一个是线性变换,一个是平移变换
仿射变换变化包括缩放(Scale)、平移(transform)、旋转(rotate)、反射(reflection)、错切(shear mapping,感觉像是一个图形的倒影),原来的直线仿射变换后还是直线,原来的平行线经过仿射变换之后还是平行线,这就是仿射.
仿射变换中集合中的一些性质保持不变:
- 凸性
- 共线性:若几个点变换前在一条线上,则仿射变换后仍然在一条线上
- 平行性:若两条线变换前平行,则变换后仍然平行
- 共线比例不变性:变换前一条线上两条线段的比例,在变换后比例不变
注:所有的三角形都能通过仿射变化为其他三角形,所有平行四边形也能仿射变换为另一个平行四边形。
数学表达
一个集合 X 的仿射变换为:
f
(
x
)
=
A
x
+
b
,
x
∈
X
f(x) = Ax + b, x∈X
f(x)=Ax+b,x∈X
仿射变换是二维平面中一种重要的变换,在图像图形领域有广泛的应用,在二维图像变换中,一般表达为:
仿射变换理解
要熟练应用仿射变换,则需先理解仿射变换,说白了就是要弄清楚上面的 R,T 矩阵各个参数代表什么含义,用图像来表达
平移变换
不难想象,就是将 x,y 平移指定值,则 R 矩阵为单位矩阵,T 矩阵为指定值,如上图中,第一行第二列图
反射变换
见图最后一行,如相对 x 轴反射,则 x 不变,y 变为相反号
旋转变换
为简单起见,只从一个点的旋转来看
1) 左下角为坐标原点
- 坐标原点为左下角
- 点
P(x,y)为坐标系中一个点,与 x 轴的夹角为α,假设其到原点的距离为 1(方便计算) - 点
P'(x',y')为 p 点逆时针旋转θ角度的点 - 点
P''(x'',y'')为 p 点顺时针旋转θ角度的点
根据简单三角关系,可知
逆时针时:
则,逆时针旋转矩阵 R 为:
顺时针时:
则,顺时针旋转矩阵 R'' 为:
从上可以看出,这个负号位置问题,个人认为与旋转方向相关
2) 左上角为坐标原点
- 坐标原点为左上角
- 点
P(x,y)为坐标系中一个点,与 x 轴的夹角为α,假设其到原点的距离为 1(方便计算) - 点
P'(x',y')为 p 点逆时针旋转θ角度的点 - 点
P''(x'',y'')为 p 点顺时针旋转θ角度的点
根据简单三角关系,可知
逆时针时:
则,逆时针旋转矩阵 R 为:
顺时针时:
则,顺时针旋转矩阵 R'' 为:
从上可以看出,这个负号位置问题,不但与旋转方向有关,还与原点有关
3) 总结
- 旋转矩阵 R 中,
sinθ的负号位置与旋转方向和原点相关 - 当记逆时针为正,左上角为原点时(opencv默认),旋转矩阵为: