perspective

This commit is contained in:
CalebChen 2022-10-10 17:09:31 +08:00
parent b3c9998aed
commit bd4247e28f
9 changed files with 215 additions and 71 deletions

138
perspective/perspective.md Normal file
View 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 两点透视
### 步骤:
&emsp;(1)先将三维形体平移到适当位置,使视点有一定 高度,且使形体的主要表面不会积聚成线;
&emsp;(2)将形体绕y轴旋转一个φ⻆(φ<90 ̊)方向满足 右手定则
&emsp;(3)进行透视变换;
&emsp;(4)最后向xoy面作正投影即得二点透视图。
&emsp;变换矩阵:
<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 三点透视
### 步骤:
&emsp;(1)首先将三维形体平移到适当位置;
&emsp;(2)将形体进行透视变换;
&emsp;(3)然后使形体先绕y轴旋转φ⻆
&emsp;(4)再绕x轴旋转θ⻆
&emsp;(5)将变形且旋转后的形体向xoy面作正投影。
&emsp;变换矩阵:
<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>
&emsp; 首先考虑这样一种最简单的情况,假设投影中心为坐标为 $(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>
&emsp; 易得,$P^$的齐次坐标位为
<center>
$[\frac{d}{d+z}*x,\frac{d}{d+z}*y,0,1]$
</center>
&emsp;
<center>
$[x,y,0,\frac{1+z}d]$
</center>
&emsp; 因此,投投影矩阵为
<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>
&emsp; 推广空间任意一点作为投影中心投影到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 实例
&emsp;假设初始顶点序列表示一个顶点在原点边长为2的正方体视点在44-2投影平面在$xOy$。
&emsp;用蓝色图形表示原图形;红色图形表示透视移动后的图形;黑色图形表示投影结果;绿色平面是投影平面;粉色虚线表示进行透视所进行的变换对应关系;黄色虚线表示投影进行的变换关系。
## 3.1 一点透视
&emsp;假设移动距离L=6M=5N=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 二点透视
&emsp;假设移动距离L=6M=5N=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 三点透视
&emsp;假设移动距离L=1M=-3N=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>

View File

@ -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):
'''一点透视移动LMN'''
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):
'''二点透视'''
#先移动LMN
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):
'''三点透视'''
#先移动LMN
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):
'''三点'''
#先移动LMN
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()
#视点00-11
view_point = np.array([4,4,-2,1],dtype=np.float32)
#以000为原点的正方体
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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB