perspective
138
perspective/perspective.md
Normal file
@ -0,0 +1,138 @@
|
||||
# 透视投影
|
||||
|
||||
# 总体思路:
|
||||
 1.先透视变换 $P_{透视}$
|
||||
 2.再投影 $P_{投影}$
|
||||
 3.最终的变换矩阵 $T = P_{透视}P_{投影}$
|
||||
 4.定点序列 $V_{new}=V_{origin}T $
|
||||
# 1. 透视
|
||||
|
||||
## 1.1 一点透视
|
||||
|
||||
### 步骤:
|
||||
|
||||
 (1) 进行平移变换,将三维形体平移到适当位 置l、m、n;
|
||||
|
||||
 (2)进行透视变换;
|
||||
|
||||
 (3)进行投影变换,向xoy平面作正投影变换,将结果变换到xoy平面上。
|
||||
|
||||
 变换矩阵:
|
||||
<center>
|
||||
|
||||
$P_{透视}=\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&1&0\\L&M&N&1\end{bmatrix}$
|
||||
</center>
|
||||
|
||||
## 1.2 两点透视
|
||||
|
||||
### 步骤:
|
||||
|
||||
 (1)先将三维形体平移到适当位置,使视点有一定 高度,且使形体的主要表面不会积聚成线;
|
||||
|
||||
 (2)将形体绕y轴旋转一个φ⻆(φ<90 ̊),方向满足 右手定则;
|
||||
|
||||
 (3)进行透视变换;
|
||||
|
||||
 (4)最后向xoy面作正投影,即得二点透视图。
|
||||
|
||||
 变换矩阵:
|
||||
<center>
|
||||
|
||||
$P_{透视}=\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&1&0\\L&M&N&1\end{bmatrix}\begin{bmatrix} cos(φ)&0&sin(φ)&0\\0&1&0&0\\-sin(φ)&0&cos(φ)&0\\0&0&0&1\end{bmatrix}$
|
||||
</center>
|
||||
|
||||
## 1.3 三点透视
|
||||
|
||||
### 步骤:
|
||||
|
||||
 (1)首先将三维形体平移到适当位置;;
|
||||
|
||||
 (2)将形体进行透视变换;
|
||||
|
||||
 (3)然后使形体先绕y轴旋转φ⻆;
|
||||
|
||||
 (4)再绕x轴旋转θ⻆;
|
||||
|
||||
 (5)将变形且旋转后的形体向xoy面作正投影。
|
||||
|
||||
 变换矩阵:
|
||||
<center>
|
||||
|
||||
$P_{透视}=\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&1&0\\L&M&N&1\end{bmatrix}\begin{bmatrix} cosφ&0&sinφ&0\\0&1&0&0\\-sinφ&0&cosφ&0\\0&0&0&1\end{bmatrix}\begin{bmatrix} 1&0&0&0\\0&cosθ&sinθ&0\\0&-sinθ&cosθ&0\\0&0&0&1\end{bmatrix}$
|
||||
</center>
|
||||
|
||||
# 2 投影
|
||||
|
||||
<center>
|
||||
<img src="pic//Untitled.png" width="400">
|
||||
</center>
|
||||
|
||||
  首先考虑这样一种最简单的情况,假设投影中心为坐标为 $(0, 0, -d)$ ,空间中任意一点$P(x,y,z)$,投影到$xOy$平面一点$P^’(x^’,y^’,0)$,由相似三角形易证:
|
||||
<center>
|
||||
|
||||
$x^’= \frac{d}{d+z}*x$
|
||||
|
||||
$y^’= \frac{d}{d+z}*y$
|
||||
</center>
|
||||
|
||||
  易得,$P^’$的齐次坐标位为
|
||||
|
||||
<center>
|
||||
|
||||
$[\frac{d}{d+z}*x,\frac{d}{d+z}*y,0,1]$
|
||||
</center>
|
||||
|
||||
  即
|
||||
|
||||
<center>
|
||||
|
||||
$[x,y,0,\frac{1+z}d]$
|
||||
</center>
|
||||
  因此,投投影矩阵为
|
||||
|
||||
<center>
|
||||
|
||||
$P_{投影}=\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&0& \frac{1}{d} \\ 0&0&0&1 \\ \end{bmatrix}$
|
||||
</center>
|
||||
  推广:空间任意一点作为投影中心,投影到xOy平面
|
||||
|
||||
<center>
|
||||
|
||||
$P_{投影}=\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&1&0 \\ -x_0&-y_0&0&1 \\ \end{bmatrix}\begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&0& \frac{1}{d} \\ 0&0&0&1 \\ \end{bmatrix} \begin{bmatrix} 1&0&0&0\\0&1&0&0\\0&0&1&0 \\ x_0&y_0&0&1\\ \end{bmatrix}= \begin{bmatrix} 1&0&0&0\\0&1&0&0\\\frac{x}{d}& \frac{y}{d}&0& \frac{1}{d} \\ 0&0&0&1\\ \end{bmatrix}$
|
||||
</center>
|
||||
|
||||
# 3 实例
|
||||
 假设初始顶点序列表示一个顶点在原点,边长为2的正方体,视点在(4,4,-2),投影平面在$xOy$。
|
||||
 用蓝色图形表示原图形;红色图形表示透视移动后的图形;黑色图形表示投影结果;绿色平面是投影平面;粉色虚线表示进行透视所进行的变换对应关系;黄色虚线表示投影进行的变换关系。
|
||||
## 3.1 一点透视
|
||||
 假设移动距离L=6,M=5,N=1
|
||||
<center>
|
||||
<img src="pic/Figure_2.png" width="400">
|
||||
|
||||
<p>一点透视三维示意图</p>
|
||||
<img src="pic/Figure_1.png" width="400">
|
||||
|
||||
<p>一点透视投影结果</p>
|
||||
</center>
|
||||
|
||||
## 3.2 二点透视
|
||||
 假设移动距离L=6,M=5,N=1,φ=40$^。$
|
||||
<center>
|
||||
<img src="pic/Figure_4.png" width="400">
|
||||
|
||||
<p>一二点透视三维示意图</p>
|
||||
<img src="pic/Figure_3.png" width="400">
|
||||
|
||||
<p>二点透视投影结果</p>
|
||||
</center>
|
||||
|
||||
## 3.3 三点透视
|
||||
 假设移动距离L=1,M=-3,N=4,φ=45$^。$,θ=30$^。$
|
||||
<center>
|
||||
<img src="pic/Figure_6.png" width="400">
|
||||
|
||||
<p>三点透视三维示意图</p>
|
||||
<img src="pic/Figure_5.png" width="400">
|
||||
|
||||
<p>三点透视投影结果</p>
|
||||
</center>
|
||||
@ -19,19 +19,38 @@ def projection_trans(view_point,points):
|
||||
new_points=np.matmul(points,mtx)
|
||||
return new_points
|
||||
|
||||
def one_point_projection(L,M,N,view_point,point):
|
||||
'''一点'''
|
||||
def one_point_perspective(L,M,N,view_point,point):
|
||||
'''一点透视:移动L,M,N'''
|
||||
mtx_mv=np.array([[1,0,0,0],
|
||||
[0,1,0,0],
|
||||
[0,0,1,0],
|
||||
[L,M,N,1]],dtype=np.float32)
|
||||
new_point=np.matmul(point,mtx_mv)
|
||||
|
||||
return new_point
|
||||
|
||||
def two_point_perspective(L,M,N,a,view_point,point):
|
||||
'''二点透视'''
|
||||
#先移动L,M,N
|
||||
mtx_mv=np.array([[1,0,0,0],
|
||||
[0,1,0,0],
|
||||
[0,0,1,0],
|
||||
[L,M,N,1]],dtype=np.float32)
|
||||
point=np.matmul(point,mtx_mv)
|
||||
# print(point)
|
||||
new_point=projection_trans(view_point,point)
|
||||
return new_point,point
|
||||
|
||||
def two_point_projection(L,M,N,a,view_point,point):
|
||||
'''二点'''
|
||||
#绕y轴旋转 a 度(a<90deg)
|
||||
a=a/180*np.pi
|
||||
mtx_roty=np.array([[np.cos(a),0,np.sin(a),0],
|
||||
[0,1,0,0],
|
||||
[-1*np.sin(a),0,np.cos(a),0],
|
||||
[0,0,0,1]],dtype=np.float32)
|
||||
new_point=np.matmul(point,mtx_roty)
|
||||
|
||||
return new_point
|
||||
|
||||
|
||||
def three_point_perspective(L,M,N,a,b,view_point,point):
|
||||
'''三点透视'''
|
||||
#先移动L,M,N
|
||||
mtx_mv=np.array([[1,0,0,0],
|
||||
[0,1,0,0],
|
||||
@ -47,71 +66,18 @@ def two_point_projection(L,M,N,a,view_point,point):
|
||||
[0,0,0,1]],dtype=np.float32)
|
||||
point=np.matmul(point,mtx_roty)
|
||||
|
||||
# print(point)
|
||||
new_point=projection_trans(view_point,point)
|
||||
return new_point,point
|
||||
|
||||
|
||||
def three_point_projection(L,M,N,a,b,view_point,point):
|
||||
'''三点'''
|
||||
#先移动L,M,N
|
||||
mtx_mv=np.array([[1,0,0,0],
|
||||
[0,1,0,0],
|
||||
[0,0,1,0],
|
||||
[L,M,N,1]],dtype=np.float32)
|
||||
point=np.matmul(point,mtx_mv)
|
||||
print("aaa")
|
||||
print(point)
|
||||
#绕y轴旋转 a 度(a<90deg)
|
||||
a=a/180*np.pi
|
||||
mtx_roty=np.array([[np.cos(a),0,np.sin(a),0],
|
||||
[0,1,0,0],
|
||||
[-1*np.sin(a),0,np.cos(a),0],
|
||||
[0,0,0,1]],dtype=np.float32)
|
||||
point=np.matmul(point,mtx_roty)
|
||||
print("bbb")
|
||||
print(point)
|
||||
#绕x轴旋转 b 度(b<90deg)
|
||||
b=b/180*np.pi
|
||||
mtx_rotx=np.array([[1,0,0,0],
|
||||
[0,np.cos(b),np.sin(b),0],
|
||||
[0,-1*np.sin(b),np.cos(b),0],
|
||||
[0,0,0,1]],dtype=np.float32)
|
||||
point=np.matmul(point,mtx_rotx)
|
||||
print("ccc")
|
||||
print(point)
|
||||
# print(point)
|
||||
new_point=projection_trans(view_point,point)
|
||||
return new_point,point
|
||||
new_point=np.matmul(point,mtx_rotx)
|
||||
|
||||
return new_point
|
||||
|
||||
|
||||
view_point = np.array([0,0,-1,1],dtype=np.float32)
|
||||
points= np.array([[0,0,0,1],
|
||||
[1,0,0,1],
|
||||
[1,1,0,1],
|
||||
[0,1,0,1],
|
||||
[0,0,0,1],
|
||||
[0,0,1,1],
|
||||
[1,0,1,1],
|
||||
[1,1,1,1],
|
||||
[0,1,1,1],
|
||||
[0,0,1,1],
|
||||
[0,0,0,1],
|
||||
[1,0,0,1],
|
||||
[1,0,1,1],
|
||||
[1,1,1,1],
|
||||
[1,1,0,1],
|
||||
[0,1,0,1],
|
||||
[0,1,1,1]],dtype=np.float32)
|
||||
|
||||
|
||||
#new_points=one_point_projection(0,0,0,view_point,points)
|
||||
new_points,ori_points=three_point_projection(2,3,1,50,30,view_point,points)
|
||||
|
||||
new_points=homo2cart(new_points)
|
||||
|
||||
|
||||
def draw(view_point,ori_points,new_points):
|
||||
def draw(view_point,ori_points,mv_points,new_points):
|
||||
plt.scatter(new_points[:,0],new_points[:,1],c="black")
|
||||
plt.plot(new_points[:,0],new_points[:,1],c="black")
|
||||
ax=Axes3D(plt.figure())
|
||||
@ -123,23 +89,63 @@ def draw(view_point,ori_points,new_points):
|
||||
|
||||
ax.plot_surface(X,Y,Z=X*0,color='g',alpha=0.3)
|
||||
|
||||
ax.scatter(ori_points[:,0],ori_points[:,1],ori_points[:,2])
|
||||
#原来的点阵
|
||||
ax.scatter(ori_points[:,0],ori_points[:,1],ori_points[:,2],c="brown")
|
||||
ax.plot(ori_points[:,0],ori_points[:,1],ori_points[:,2],c="brown")
|
||||
#透视移动后
|
||||
ax.scatter(mv_points[:,0],mv_points[:,1],mv_points[:,2])
|
||||
ax.scatter(view_point[0],view_point[1],view_point[2],c='r')
|
||||
ax.plot(ori_points[:,0],ori_points[:,1],ori_points[:,2])
|
||||
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1,1, 0.5, 1]))
|
||||
|
||||
ax.plot(mv_points[:,0],mv_points[:,1],mv_points[:,2])
|
||||
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1,1, 1, 1]))
|
||||
#投影后
|
||||
ax.scatter(new_points[:,0],new_points[:,1],c="black")
|
||||
ax.plot(new_points[:,0],new_points[:,1],c="black")
|
||||
|
||||
#原来与移动后点两两连接
|
||||
for i in range(len(mv_points)):
|
||||
ax.plot([ori_points[i,0],mv_points[i,0]],[ori_points[i,1],mv_points[i,1]],[ori_points[i,2],mv_points[i,2]],c="pink",linestyle='--')
|
||||
#两组点两两连接
|
||||
for i in range(len(mv_points)):
|
||||
ax.plot([mv_points[i,0],view_point[0]],[mv_points[i,1],view_point[1]],[mv_points[i,2],view_point[2]],c='y',linestyle='dashdot')
|
||||
|
||||
ax.set_zlabel('Z', fontdict={'size': 15, 'color': 'red'})
|
||||
ax.set_ylabel('Y', fontdict={'size': 15, 'color': 'red'})
|
||||
ax.set_xlabel('X', fontdict={'size': 15, 'color': 'red'})
|
||||
|
||||
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
#视点(0,0,-1,1)
|
||||
view_point = np.array([4,4,-2,1],dtype=np.float32)
|
||||
#以(0,0,0)为原点的正方体
|
||||
points= np.array([[0,0,0,1],
|
||||
[2,0,0,1],
|
||||
[2,2,0,1],
|
||||
[0,2,0,1],
|
||||
[0,0,0,1],
|
||||
[0,0,2,1],
|
||||
[2,0,2,1],
|
||||
[2,2,2,1],
|
||||
[0,2,2,1],
|
||||
[0,0,2,1],
|
||||
[0,0,0,1],
|
||||
[2,0,0,1],
|
||||
[2,0,2,1],
|
||||
[2,2,2,1],
|
||||
[2,2,0,1],
|
||||
[0,2,0,1],
|
||||
[0,2,2,1]],dtype=np.float32)
|
||||
|
||||
#获得透视移动后的点和投影后的点
|
||||
#per_points=one_point_perspective(6,5,1,view_point,points)
|
||||
#per_points=two_point_perspective(6,5,1,40,view_point,points)
|
||||
#透视移动后的点
|
||||
per_points=three_point_perspective(1,-3,3,45,30,view_point,points)
|
||||
#投影后的点
|
||||
pro_points=projection_trans(view_point,per_points)
|
||||
#转为笛卡尔坐标系
|
||||
per_points=homo2cart(per_points)
|
||||
pro_points=homo2cart(pro_points)
|
||||
|
||||
draw(view_point,ori_points,new_points)
|
||||
#画图
|
||||
draw(view_point,points,per_points,pro_points)
|
||||
BIN
perspective/pic/Figure_1.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
perspective/pic/Figure_2.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
perspective/pic/Figure_3.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
perspective/pic/Figure_4.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
perspective/pic/Figure_5.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
perspective/pic/Figure_6.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
perspective/pic/Untitled.png
Normal file
|
After Width: | Height: | Size: 92 KiB |