2021-02-11

计算机图形学4-透视投影

效果

按下“c”展示不同的三维图形的一点、二点、三点透视图,需注意展示的是三个txt文件中的图形。 按下”q”退出
2021-02-11

三维图形文件

边-三棱锥.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()

上一篇:Linux系统编程34 进程控制 - init 进程和僵死进程


下一篇:vtk编辑点