计算机图形学4-透视投影
效果
按下“c”展示不同的三维图形的一点、二点、三点透视图,需注意展示的是三个txt文件中的图形。 按下”q”退出
三维图形文件
边-三棱锥.txt
0,1
0,2
0,3
1,2
1,3
2,3
边-长方体.txt
0,1
0,3
0,4
1,2
1,5
2,3
2,6
3,7
4,5
4,7
5,6
6,7
边-正方体.txt
0,1
0,3
0,4
1,2
1,5
2,3
2,6
3,7
4,5
4,7
5,6
6,7
点-三棱锥.txt
2,3,5
4,2,0
3,6,0
1,4,0
点-长方体.txt
0,0,0
1,0,0
1,1,0
0,1,0
0,0,3
1,0,3
1,1,3
0,1,3
点-正方体.txt
0,0,0
1,0,0
1,1,0
0,1,0
0,0,1
1,0,1
1,1,1
0,1,1
代码
import cv2
import numpy as np
import time
from math import*
img = np.zeros((800, 1020, 3), np.uint8)#背景
cv2.namedWindow('src')
filestr=["三棱锥","正方体","长方体"]
growthFactor=[20,100,40]
#三维透视变换:一点、两点、三点
def PerspectiveP(verticies,l,m,n,p,q,r,o=0,a=0):
global choice,growthFactor
#平移变换矩阵
TsM=np.array([[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[l,m,n,1] ], dtype = np.float)
#旋转变换矩阵
RyM=np.array([[cos(o),0,-sin(o),0],
[0,1,0,0],
[sin(o),0,cos(o),0],
[0,0,0,1] ], dtype = np.float)
RxM=np.array([[1,0,0,0],
[0,cos(a),-sin(a),0],
[0,sin(a),cos(a),0],
[0,0,0,1] ], dtype = np.float)
#透视变换矩阵
PeM=np.array([[1,0,0,p],
[0,1,0,q],
[0,0,1,r],
[0,0,0,1] ], dtype = np.float)
#向xoy面投影的投影矩阵
OtM=np.array([[1,0,0,0],
[0,1,0,0],
[0,0,0,0],
[0,0,0,1] ], dtype = np.float)
#将获取的点做成矩阵形式
vs=np.c_[verticies,np.ones(len(verticies))]
#与变换矩阵相乘,则成为最终的二维平面坐标
t=TsM
mode=0
if o!=0:
t=np.dot(t,RyM)
mode+=1
if a!=0:
t=np.dot(t,RxM)
mode+=1
t=np.dot(t,PeM)
Tp1=np.dot(t,OtM)
print(Tp1)
t=np.dot(vs,Tp1)
#将最后一列化为1
lastCol=t[:,-1]
t=t/np.c_[lastCol,lastCol,lastCol,lastCol]
print(t)
#化成在x∈(0,+),y∈(0,+)之间的坐标
#取x,y坐标值
t=np.c_[t[:,0],t[:,1]]
#适当扩大
t=(t-t.min())*growthFactor[choice]+50
t=t+np.c_[np.ones(len(t))*200*mode,np.zeros(len(t))]
t=t.astype(int)
#化成好画线的元组
t=[tuple(x) for x in t]
print(t)
return t
#根据边的关系,在两个点之间进行连线,最终得到具有三维感的二维图形
def drawG(edges,pts):
for edge in edges:
cv2.waitKey(1)
cv2.imshow('src',img)
cv2.line(img,pts[edge[0]],pts[edge[1]],(255,255,255))
def nextone(x):
global filestr
if x>=len(filestr)-1:
return 0
return x+1
def DrawAll():
global choice,filestr
#获取要变换的三维物体所有顶点以及边(点与点之间的关系)
verticies=np.loadtxt('点-'+filestr[choice]+'.txt',dtype=np.float32,delimiter=",")
edges =np.loadtxt('边-'+filestr[choice]+'.txt',dtype=np.int,delimiter=",").tolist()
#参数
l,m,n,pf,qf,rf,o,a=-0.8,-1.6,-2,-3,-4,-2.5,pi/2,pi
#一点
pts=PerspectiveP(verticies,l,m,n,0,0,1/rf)
strx ="One Point:"
cv2.putText(img,strx , (100, 30), cv2.FONT_HERSHEY_PLAIN,2, (255, 255, 0))
drawG(edges,pts)
#二点
pts=PerspectiveP(verticies,l,m,n,0,1/qf,1/rf,o)
strx ="Two Point:"
cv2.putText(img,strx , (300, 30), cv2.FONT_HERSHEY_PLAIN,2, (255, 0, 255))
drawG(edges,pts)
#三点
pts=PerspectiveP(verticies,l,m,n,1/pf,1/qf,1/rf,o,a)
strx ="Three Point:"
cv2.putText(img,strx , (500, 30), cv2.FONT_HERSHEY_PLAIN,2, (0, 255, 255))
drawG(edges,pts)
all=[np.array([[0, 0], [1500, 0], [1500, 1500], [0, 1500]])]
choice=0
while(1):
cv2.imshow('src',img)
code=cv2.waitKey(100)
if code == ord('q'):#按下q退出
break
elif code == ord('c'):
cv2.fillPoly(img,all,(0,0,0))
choice=nextone(choice)
DrawAll()
cv2.destroyAllWindows()