二维平面上常见的三种几何变换
- 平移
- 缩放
- 旋转
平移
在二维平面上每个点可以用
(
x
,
y
)
(x,y)
(x,y)表示,假设有一点
P
(
x
,
y
)
P(x,y)
P(x,y),它平移到
P
′
(
x
′
,
y
′
)
P'(x',y')
P′(x′,y′),则相应的数学表达式子为:
P
′
=
P
+
Δ
P
[
x
′
y
′
]
=
[
x
y
]
+
[
Δ
x
Δ
y
]
=
[
x
+
Δ
x
y
+
Δ
y
]
P'=P+\Delta P\\ \left [ \begin{matrix} x' \\y' \end{matrix}\right]=\left [ \begin{matrix} x \\y \end{matrix}\right]+\left [ \begin{matrix} \Delta x \\ \Delta y \end{matrix}\right] =\left [ \begin{matrix} x+\Delta x \\ y + \Delta y \end{matrix}\right]
P′=P+ΔP[x′y′]=[xy]+[ΔxΔy]=[x+Δxy+Δy]
例如,点
(
1
,
1
)
(1,1)
(1,1) 平移到
(
2
,
3
)
(2,3)
(2,3) 需要相应的
Δ
P
=
[
1
2
]
\Delta P =\left [ \begin{matrix} 1\\ 2\end{matrix}\right ]
ΔP=[12]
缩放
假设有一点
P
(
x
,
y
)
P(x,y)
P(x,y),它缩放到
P
′
(
x
′
,
y
′
)
P'(x',y')
P′(x′,y′),则相应的数学表达式子为:
P
′
=
S
P
[
x
′
y
′
]
=
[
S
x
0
0
S
y
]
[
x
y
]
=
[
x
S
x
y
S
y
]
P'=SP\\ \left [ \begin{matrix} x' \\y' \end{matrix}\right]=\left [ \begin{matrix} S_x & 0 \\0 & S_y \end{matrix}\right]\left [ \begin{matrix} x \\ y \end{matrix}\right] =\left [ \begin{matrix} xS_x \\ yS_y \end{matrix}\right]
P′=SP[x′y′]=[Sx00Sy][xy]=[xSxySy]
其中,
S
S
S代表缩放的矩阵。
旋转
二维平面是上的旋转矩阵如下,
R
=
[
c
o
s
(
α
)
s
i
n
(
α
)
−
s
i
n
(
α
)
c
o
s
(
α
)
]
R = \left [ \begin{matrix} cos(\alpha) & sin(\alpha) \\-sin(\alpha) & cos(\alpha) \end{matrix}\right]
R=[cos(α)−sin(α)sin(α)cos(α)]
想要知道详细这个矩阵的详细推导可以看这篇博客;
那么,假设有一点
P
(
x
,
y
)
P(x,y)
P(x,y),它绕着原点旋转到
P
′
(
x
′
,
y
′
)
P'(x',y')
P′(x′,y′),则相应的数学表达式子为:
P
′
=
R
P
[
x
′
y
′
]
=
[
c
o
s
(
α
)
s
i
n
(
α
)
−
s
i
n
(
α
)
c
o
s
(
α
)
]
[
x
y
]
=
[
x
c
o
s
(
α
)
+
y
s
i
n
(
α
)
−
x
s
i
n
(
α
)
+
y
c
o
s
(
α
)
]
P'=RP\\ \left [ \begin{matrix} x' \\y' \end{matrix}\right]=\left [ \begin{matrix} cos(\alpha) & sin(\alpha) \\-sin(\alpha) & cos(\alpha) \end{matrix}\right]\left [ \begin{matrix} x \\ y \end{matrix}\right] =\left [ \begin{matrix} xcos(\alpha)+ysin(\alpha) \\-xsin(\alpha) +ycos(\alpha) \end{matrix}\right]
P′=RP[x′y′]=[cos(α)−sin(α)sin(α)cos(α)][xy]=[xcos(α)+ysin(α)−xsin(α)+ycos(α)]
齐次坐标系的引入
在二维平面上,缩放和旋转通过乘法实现,平移是通过加法实现,这样计算是很麻烦地!为了规范二维平面上的几何变换,数学家们引入了齐次坐标的概念。
齐次坐标的是什么呢?直观上来讲就是在原来的维度上面再添加一个维度,且多出的维度一直是1,例如:
P
=
[
x
y
1
]
P = \left[ \begin{matrix} x\\ y\\1 \end{matrix} \right]
P=⎣⎡xy1⎦⎤
则上述平移过程中的
Δ
P
\Delta P
ΔP在齐次坐标系的表达方式为:
Δ
P
=
[
1
0
Δ
x
0
1
Δ
y
0
0
1
]
\Delta P = \left[ \begin{matrix} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1\end{matrix} \right]
ΔP=⎣⎡100010ΔxΔy1⎦⎤
利用齐次坐标系,平移过程的数学表达式为:
P
′
=
Δ
P
×
P
[
x
′
y
′
1
]
=
[
1
0
Δ
x
0
1
Δ
y
0
0
1
]
[
x
y
1
]
=
[
x
+
Δ
x
y
+
Δ
y
1
]
P'=\Delta P \times P\\ \left [ \begin{matrix} x' \\y' \\ 1 \end{matrix}\right]=\left[ \begin{matrix} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1\end{matrix} \right] \left [ \begin{matrix} x \\ y \\ 1\end{matrix}\right] =\left [ \begin{matrix} x+\Delta x \\ y + \Delta y \\ 1 \end{matrix}\right]
P′=ΔP×P⎣⎡x′y′1⎦⎤=⎣⎡100010ΔxΔy1⎦⎤⎣⎡xy1⎦⎤=⎣⎡x+Δxy+Δy1⎦⎤
上述缩放过程中,
S
S
S在齐次坐标系中的表达方式为:
S
=
[
S
x
0
0
0
S
y
0
0
0
1
]
S = \left[ \begin{matrix} S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & 1\end{matrix} \right]
S=⎣⎡Sx000Sy0001⎦⎤
则缩放过程的数学表达式为:
P ′ = S × P [ x ′ y ′ 1 ] = [ S x 0 0 0 S y 0 0 0 1 ] [ x y 1 ] = [ x S x y S y 1 ] P'=S \times P\\ \left [ \begin{matrix} x' \\y' \\ 1 \end{matrix}\right]=\left[ \begin{matrix} S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & 1\end{matrix} \right] \left [ \begin{matrix} x \\ y \\ 1\end{matrix}\right] =\left [ \begin{matrix} xS_x \\ y S_y \\ 1 \end{matrix}\right] P′=S×P⎣⎡x′y′1⎦⎤=⎣⎡Sx000Sy0001⎦⎤⎣⎡xy1⎦⎤=⎣⎡xSxySy1⎦⎤
同理,上述旋转过程中的旋转矩阵
R
R
R在其次坐标系统的表达方式为:
S
=
[
c
o
s
(
α
)
s
i
n
(
α
)
0
−
s
i
n
(
α
)
c
o
s
(
α
)
0
0
0
1
]
S = \left[ \begin{matrix} cos(\alpha) & sin(\alpha) & 0 \\ -sin(\alpha) & cos(\alpha) & 0 \\ 0 & 0 & 1\end{matrix} \right]
S=⎣⎡cos(α)−sin(α)0sin(α)cos(α)0001⎦⎤
则旋转过程的数学表达式为:
P
′
=
R
×
P
[
x
′
y
′
1
]
=
[
c
o
s
(
α
)
s
i
n
(
α
)
0
−
s
i
n
(
α
)
c
o
s
(
α
)
0
0
0
1
]
[
x
y
1
]
=
[
x
c
o
s
(
α
)
+
y
s
i
n
(
α
)
−
x
s
i
n
(
α
)
+
y
c
o
s
(
α
)
1
]
P'=R \times P\\ \left [ \begin{matrix} x' \\y' \\ 1 \end{matrix}\right]=\left[ \begin{matrix} cos(\alpha) & sin(\alpha) & 0 \\ -sin(\alpha) & cos(\alpha) & 0 \\ 0 & 0 & 1\end{matrix} \right] \left [ \begin{matrix} x \\ y \\ 1\end{matrix}\right] =\left [ \begin{matrix} xcos(\alpha) + ysin(\alpha) \\ -xsin(\alpha)+ycos(\alpha) \\ 1 \end{matrix}\right]
P′=R×P⎣⎡x′y′1⎦⎤=⎣⎡cos(α)−sin(α)0sin(α)cos(α)0001⎦⎤⎣⎡xy1⎦⎤=⎣⎡xcos(α)+ysin(α)−xsin(α)+ycos(α)1⎦⎤
至此,二维平面上所有几何变换都可以通过乘法实现。比如,在二维平面上要实现绕着某个点 P ( x , y ) P(x,y) P(x,y)旋转,需要以下三个步骤完成:
- 将图形平移到原点
- 对图形进行旋转
- 将图形平移回原来的位置
没有利用齐次坐标系的话,变换过程的数学公式为:
P
′
=
R
(
P
+
Δ
P
)
+
(
−
Δ
P
)
=
[
c
o
s
(
α
)
s
i
n
(
α
)
−
s
i
n
(
α
)
c
o
s
(
α
)
]
(
[
x
y
]
+
[
Δ
x
Δ
y
]
)
−
[
Δ
x
Δ
y
]
P' = R(P+\Delta P)+(-\Delta P) \\ = \left [ \begin{matrix} cos(\alpha) & sin(\alpha) \\-sin(\alpha) & cos(\alpha) \end{matrix}\right] \left( \left [ \begin{matrix} x \\ y \end{matrix}\right] + \left [ \begin{matrix} \Delta x \\ \Delta y \end{matrix}\right] \right) -\left [ \begin{matrix} \Delta x \\ \Delta y \end{matrix}\right]
P′=R(P+ΔP)+(−ΔP)=[cos(α)−sin(α)sin(α)cos(α)]([xy]+[ΔxΔy])−[ΔxΔy]
利用齐次坐标系的话,变换过程的数学公式为:
P
′
=
(
−
Δ
P
)
×
R
×
Δ
P
×
P
=
−
[
1
0
Δ
x
0
1
Δ
y
0
0
1
]
[
c
o
s
(
α
)
s
i
n
(
α
)
0
−
s
i
n
(
α
)
c
o
s
(
α
)
0
0
0
1
]
[
1
0
Δ
x
0
1
Δ
y
0
0
1
]
[
x
y
1
]
P' = (-\Delta P)\times R\times \Delta P\times P \\ =- \left[ \begin{matrix} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1\end{matrix} \right] \left[ \begin{matrix} cos(\alpha) & sin(\alpha) & 0 \\ -sin(\alpha) & cos(\alpha) & 0 \\ 0 & 0 & 1\end{matrix} \right]\left[ \begin{matrix} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1\end{matrix} \right] \left[ \begin{matrix} x\\ y\\1 \end{matrix} \right]
P′=(−ΔP)×R×ΔP×P=−⎣⎡100010ΔxΔy1⎦⎤⎣⎡cos(α)−sin(α)0sin(α)cos(α)0001⎦⎤⎣⎡100010ΔxΔy1⎦⎤⎣⎡xy1⎦⎤
下面用根据本篇文章的知识,利用Python实现一个正方形绕着中心点旋转45度的例子。
import numpy as np
import matplotlib.pyplot as plt
def poly_gen(x0=(10,10),length = 20):
poly = []
x = x0[0]
y = x0[1]
for _ in range(length):
y += 1
poly.append(np.array([x,y,1]))
x = x0[0]
y = x0[1]
for _ in range(length):
x += 1
poly.append(np.array([x,y,1]))
x = x0[0]+length
y = x0[1]
for _ in range(length):
y += 1
poly.append(np.array([x,y,1]))
x = x0[0]
y = x0[1]+length
for _ in range(length):
x +=1
poly.append(np.array([x,y,1]))
center = np.array([x0[0]+length/2,x0[1]+length/2])
return poly, center
def translation(poly,dx,dy):
T = np.array([[1,0,dx],
[0,1,dy],
[0,0,1]])
poly_trans = []
for x in poly:
poly_trans.append(np.dot(T,x))
return poly_trans
def rotation(poly,theta):
R = np.array([[np.cos(theta), np.sin(theta),0],
[-np.sin(theta),np.cos(theta),0],
[0,0,1]])
poly_rotation = []
for x in poly:
poly_rotation.append(np.dot(R,x))
return poly_rotation
if __name__=='__main__':
fig1=plt.figure()
poly, center = poly_gen()
for x in poly:
plt.scatter(x[0],x[1])
plt.xlim(0,50)
plt.ylim(0,50)
fig2=plt.figure()
poly_trans = translation(poly,-center[0],-center[1])
poly_rotation = rotation(poly_trans, np.pi / 4.)
poly_trans = translation(poly_rotation,center[0],center[1])
for x in poly_trans:
plt.scatter(x[0],x[1])
plt.xlim(0,50)
plt.ylim(0,50)
plt.show()
其运行的结果如下: