三维空间物体视锥投影数学推导

一、三维空间基转换

1.绕原点旋转

二维坐标旋转可以用矩阵表示:

设有向量\textbf{\emph{v}} = (x,y)^T=\begin{bmatrix} x\\y\end{bmatrix},那么当向量\textbf{\emph{v}}绕原点逆时针旋转\theta度,那么旋转矩阵为T= \begin{bmatrix} cos\theta &-sin\theta\\ sin\theta &cos\theta \end{bmatrix}

推导略。

注:向量\textbf{\emph{v}}是列向量,因此旋转后的向量为:\tilde{\textbf{\emph{v}}} = T\textbf{\emph{v}}

旋转矩阵可以推广至更高维度的空间,以三维空间为例:

设有向量\textbf{\emph{v}} = (x,y,z)^T=\begin{bmatrix} x\\y\\z\end{bmatrix},那么当向量\textbf{\emph{v}}z轴逆时针旋转\theta度时,相当于在向量\textbf{\emph{v}}在一个平行于xOy平面的的二维空间中,绕原点旋转,旋转后z坐标保持不变,那么旋转矩阵可以改为:

T_z= \begin{bmatrix} cos\theta_z &-sin\theta_z &0\\ sin\theta_z & cos\theta_z & 0\\ 0 &0 &1 \end{bmatrix}

向量\textbf{\emph{v}}x轴和y轴逆时针旋转\theta度的旋转矩阵为:

T_x= \begin{bmatrix} 1 &0 &0 \\ 0 &cos\theta_x &-sin\theta_x\\ 0 &sin\theta_x & cos\theta_x \end{bmatrix}

T_y= \begin{bmatrix} cos\theta_y &0 &-sin\theta_y\\ 0 &1 &0 \\ sin\theta_y & 0 &cos\theta_y \end{bmatrix}

因此向量\textbf{\emph{v}}在三维空间中,绕原点旋转任意角度,可由以上三个旋转矩阵连乘得到,即:

T = T_zT_yT_z

2.绕特定点旋转

二维空间中绕特定\textbf{\emph{c}}=(x_c,y_c)^T= \begin{bmatrix} x_c\\ y_c \end{bmatrix}旋转可以用以下矩阵乘法表示:

\tilde{\textbf{\emph{v}}} = \begin{bmatrix} 1&0&x_c\\ 0&1&y_c\\ 0&0&1 \end{bmatrix} \begin{bmatrix} cos\theta &-sin\theta &0\\ sin\theta &cos\theta &0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} 1&0&-x_c\\ 0&1&-y_c\\ 0&0&1 \end{bmatrix} \textbf{\emph{v}} = \begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix} \begin{bmatrix} T' & O\\ O &1 \end{bmatrix} \begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix} \textbf{\emph{v}}

其中向量\textbf{\emph{v}}用齐次坐标表示,即\textbf{\emph{v}} = (x,y,1)^T=\begin{bmatrix} x\\y\\1\end{bmatrix}T'= \begin{bmatrix} cos\theta &-sin\theta\\ sin\theta &cos\theta \end{bmatrix}

三个矩阵从右至左的含义分别是:

\begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix}:平移向量使得空间以\textbf{\emph{c}}为原点

\begin{bmatrix} T' & O\\ O &1 \end{bmatrix}:绕原点\textbf{\emph{c}}旋转

\begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix}:还原空间的原点

推导略。

推广至三维空间,绕特定点\textbf{\emph{c}}=(x_c,y_c,z_c)^T= \begin{bmatrix} x_c\\ y_c\\z_c \end{bmatrix}旋转可以表示为:

\tilde{\textbf{\emph{v}}} = \begin{bmatrix} 1&0 &0 &x_c\\ 0&1 &0 &y_c\\ 0&0 &1 &z_c\\ 0 &0 &0 &1 \end{bmatrix} T_{xyz} \begin{bmatrix} 1&0 &0 &-x_c\\ 0&1 &0 &-y_c\\ 0&0 &1 &-z_c\\ 0 &0 &0 &1 \end{bmatrix} \textbf{\emph{v}} = \begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix} T_{xyz} \begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix} \textbf{\emph{v}}

其中

\begin{align*} T_{xyz}&= \begin{bmatrix} 1 &0 &0 &0\\ 0 &cos\theta_x &-sin\theta_x &0\\ 0 &sin\theta_x & cos\theta_x &0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} cos\theta_y &0 &-sin\theta_y &0\\ 0 &1 &0 &0\\ sin\theta_y & 0 &cos\theta_y &0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} cos\theta_z &-sin\theta_z &0 &0\\ sin\theta_z &cos\theta_z & 0 &0\\ 0 &0 &1 &0\\ 0 &0 &0 &1 \end{bmatrix}\\ & = \begin{bmatrix} cos\theta_ycos\theta_z &-cos\theta_y sin\theta_z &-sin\theta_y & 0\\ cos\theta_x sin\theta_z - sin\theta_x sin\theta_y cos\theta_z & cos\theta_x cos\theta_z + sin\theta_x sin\theta_y sin\theta_z & -sin\theta_x cos\theta_y & 0\\ sin\theta_x sin\theta_z + cos\theta_x sin\theta_y cos\theta_z & sin\theta_x cos\theta_z - cos\theta_x sin\theta_y sin\theta_z & cos\theta_x cos\theta_y & 0\\ 0 &0 &0 &1 \end{bmatrix} \end{align*}

3. 

 

二、视锥体成像

1.视点空间中的视椎体成像

如下图所示,在一个视点空间\mathbb{R}^3_s中有一根棍子(线段)AB,其中A=(x_A, y_A, z_A)B=(x_B, y_B, z_B),点S=(x_S,y_S,z_S)为视点,平面xoy|_{z=z_0}为成像平面,A'B'为棍子AB在视平面上的成像。

注:视点空间\mathbb{R}^3_s是一个左手系的三维线性空间

三维空间物体视锥投影数学推导_第1张图片

由于点A'和点B'分别是点S和点A和点B的线性组合,因此视线SASB的空间可以表示为

\begin{matrix} &\textbf{A}=(\textbf{x}_A,\textbf{y}_A,\textbf{z}_A)=S+k_A(A-S)\\&\textbf{B}=(\textbf{x}_B,\textbf{y}_B,\textbf{z}_B)=S+k_B(B-S)\end{matrix}  即

\begin{align*} &\textbf{x}_A = x_S+k_A(x_A-x_S)\\ &\textbf{y}_A= y_S+k_A(y_A-y_S)\\ &\textbf{z}_A = z_S+k_A(z_A-x_S)\\ \end{align*} \qquad \begin{align*} &\textbf{x}_B = x_S+k_B(x_B-x_S)\\ &\textbf{y}_B= y_S+k_B(y_B-y_S)\\ &\textbf{z}_B = z_S+k_B(z_B-z_S)\\ \end{align*} \qquad\qquad(1)

k_A=\frac{|S-A'|}{|S-A|}=\frac{|z_S-z_0|}{|z_S-z_A|}, k_B=\frac{|S-B'|}{|S-B|}=\frac{|z_S-z_0|}{|z_S-z_B|}时(z_0为视平面xoy|_{z=z_0}在三维空间中的z坐标),便能得到AB在成像平面xoy|_{z=z_0}上的成像。

根据以上可以得出,视点空间中一个物体的成像和两个因素有关:视线(视点和物体的连线)与视平面的相对角度(直接决定在物体在三维空间中的坐标),视平面在物体和视点间的相对位置(即k

如果将视点S平移至原点(0,0,0),即如下图所示:

三维空间物体视锥投影数学推导_第2张图片

那么等式组(1)可以简化为

\begin{matrix} &x'_A = k_Ax_A\\ &y'_A= k_Ay_A\\ &z'_A =k_Az_A\\ \end{matrix} \qquad \begin{matrix} &x'_B = k_Bx_B\\ &y'_B=k_By_B\\ &z'_B = k_Bz_B\\ \end{matrix} \qquad\qquad(2)

其中k_A=\frac{|A'|}{|A|}=\frac{|z_0|}{|z_A|}, k_B=\frac{|B'|}{|B|}=\frac{|z_0|}{|z_B|},因此可以得出:

三维空间物体视锥投影数学推导_第3张图片

在成像平面xoy|_{z=z_0}上,点A'=(x'_A, y'_A)B'=(x'_B, y'_B)即平面成像。

一般情况下,z_0\in (0, min(z_i)), \quad k_i \in (0, 1),即成像屏幕介于视点和物体之间。

2.透视效果

下图是一个二维空间中的成像示意图,视点为s,成像平面为\textbf{S},蓝色实线代表两个离视点距离不同,但是大小相同的物体,蓝色虚线为实际成像,图(a)为正射投影,图(b)为视锥体投影。

三维空间物体视锥投影数学推导_第4张图片

从对比图中可以看到,两个一样的物体(物体形状及物体与视平面的角度均一致)在视平面上的正射投影是一致的,但是视椎体投影会因为距离的原因而出现不同的成像,这种现象就是透视效果(近大远小)。

当等式组(2)中的k_i\rightarrow 0\quad(z_0\rightarrow 0)时,即成像屏幕与物体的距离趋向于无穷远时,视椎体投影的比例和正射投影一致,证明略。

3.物体空间到视点空间的转换

物体空间\mathbb{R}^3是一个服从右手系的三维空间,蓝色平面为地面,如下图所示:

三维空间物体视锥投影数学推导_第5张图片

下图(b)为视点空间,图(a)是成像平面,图(c)为物体空间。

三维空间物体视锥投影数学推导_第6张图片

物体空间中的物体映射到视点空间主要有两部操作:

STEP1 翻转z

STEP2 绕x轴逆时针旋转\pi/2

可以通过转换矩阵实现

\begin{align*} T&= \begin{bmatrix} cos\theta_ycos\theta_z &-cos\theta_y sin\theta_z &-sin\theta_y & 0\\ cos\theta_x sin\theta_z - sin\theta_x sin\theta_y cos\theta_z & cos\theta_x cos\theta_z + sin\theta_x sin\theta_y sin\theta_z & -sin\theta_x cos\theta_y & 0\\ sin\theta_x sin\theta_z + cos\theta_x sin\theta_y cos\theta_z & sin\theta_x cos\theta_z - cos\theta_x sin\theta_y sin\theta_z & cos\theta_x cos\theta_y & 0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \end{align*}

其中\theta_x = -\frac{\pi}{2},\quad\theta_y =\theta_z =0,即:

三、总结

当需要计算一个三维空间\mathbb{R}^3中的物体A_1的二维成像,只需要进行以下两步操作,如下图所示:

STEP1:通过基转换把物体\mathbb{R}^3中的物体A_1转换至视点坐标系\mathbb{R}^3_s中,得到物体A,即:

三维空间物体视锥投影数学推导_第7张图片

其中

STEP2:在视点坐标系\mathbb{R}^3_s中,计算物体A'在成像屏幕\textbf{S}|_{z=z_0}处的成像,即:A' = z_0\begin{bmatrix} \frac{1}{z_1 } &0 &\cdots &0\\ 0 & \frac{1}{z_2 } &\cdots &0\\ \vdots & \vdots &\ddots &\vdots\\ 0 &0 &\cdots& \frac{1}{z_n }\\ \end{bmatrix} \begin{bmatrix} x_1 &y_1 &z_1\\ x_2 &y_2 &z_2\\ \vdots&\vdots&\vdots\\ x_n &y_n &z_n \end{bmatrix} = \begin{align*} \begin{bmatrix} x'_1 &y'_1 &z'_0\\ x'_2 &y'_2 &z'_0\\ \vdots&\vdots&\vdots\\ x'_n &y'_n &z'_0 \end{bmatrix} \end{align*}

 

四、PYTHON实现

# -*- coding:utf-8 -*-

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def trans_base(x, y, z):
    # 计算三维空间中的旋转矩阵
    Txyz = np.array(
        [
            [np.cos(y) * np.cos(z), -np.cos(y) * np.sin(z), -np.sin(y), 0],
            [np.cos(x) * np.sin(z) - np.sin(x) * np.sin(y) * np.cos(z),
             np.cos(x) * np.cos(z) + np.sin(x) * np.sin(y) * np.sin(z),
             -np.sin(x) * np.cos(y), 0
             ],
            [np.sin(x) * np.sin(z) + np.cos(x) * np.sin(y) * np.cos(z),
             np.sin(x) * np.cos(z) - np.cos(x) * np.sin(y) * np.sin(z),
             np.cos(x) * np.cos(y), 0
             ],
            [0, 0, 0, 1]
        ]
    )
    return Txyz


def gen_cube(a=1):
    # 生成一个以原点为中心,边长为a的正方体
    d = []
    X = np.linspace(a/2, -a/2, 2)
    for x1 in X:
        for x2 in X:
            for x3 in X:
                d.append([x1, x2, x3])
    return np.array(d)


def to_hc(a):
    # 齐次坐标表示矩阵
    a = np.column_stack((a,np.zeros(a.shape[0])))
    r = np.zeros(a.shape[1])
    r[-1] = 1
    a = np.row_stack((a, r))
    return a


def trans_cube(cube, x=0, y=0, z=0):
    # 旋转立方体
    x_ = x / 180 * np.pi
    y_ = y / 180 * np.pi
    z_ = z / 180 * np.pi
    T = trans_base(x_, y_, z_)
    cube2 = to_hc(cube)
    c2 = np.dot(T, cube2.T).T
    return c2[:-1, :-1]


def map_2d(cube, z0):
    # 在二维平面上计算视锥体投影
    cube_ = cube.copy()
    z0_ = max(z0, np.abs(cube_[:, 2].min()))   # 确保立方体不会被成像屏幕穿过
    cube_[:, 2] = cube_[:, 2] + z0_               # 平移立方体
    cube2 = np.dot(np.diag(z0_/cube_[:,2]), cube_)
    l = []
    for i in range(len(cube_)):
        for j in range(len(cube_)):
            d = cube_[i] - cube_[j]
            if d.dot(d)/1-1 < 1E-10:
                tc = np.array([cube2[i], cube2[j]])
                l.append(tc)
    return cube2, l


def plot_2d(cube, thetax, thetay, thetaz, d, color):
    # 旋转并投影
    cube_ = trans_cube(cube, thetax, thetay, thetaz)    # 为了更加生动,对立方体做了旋转
    cube_t = np.dot(trans_cube(cube_, -90, 0, 0), np.diag([1, 1, -1]))   # 从物体空间映射至视点空间
    cube_2d, edges = map_2d(cube_t, d)
    plt.scatter(x=cube_2d[:,0], y=cube_2d[:,1], color=color)
    for e in edges:
        plt.plot(e[:,0], e[:,1], c='grey', alpha=0.3)


def plot_3d(cube, thetax, thetay, thetaz, color):
    # 立方体矩阵
    cube_ = trans_cube(cube, thetax, thetay, thetaz)    # 为了更加生动,对立方体做了旋转
    x, y, z = cube_[:,0], cube_[:,1], cube_[:,2]
    fig=plt.figure()
    ax2 = Axes3D(fig)
    ax2.scatter3D(x, y, z, color=color, s=30)
    for i in range(len(cube_)):
        for j in range(len(cube_)):
            # 绘制棱
            d = cube_[i] - cube_[j]
            if d.dot(d)/1-1 < 1E-10:
                tc = np.array([cube_[i], cube_[j]])
                tx, ty, tz = tc[:,0], tc[:,1], tc[:,2]
                ax2.plot3D(tx, ty, tz, alpha=0.3, c='grey', lw=2)
    fig.show()


# 定义正方体顶角的颜色
color = ['red', 'orange', 'limegreen', 'cyan', 'blue', 'royalblue', 'purple', 'deeppink']

# 生成立方体
cube = gen_cube(a=1)

# 绘图
plot_3d(cube, 45, 45, 45, color)
plot_2d(cube, 45, 45, 45, 1.5, color)    # 近距离投影
plot_2d(cube, 45, 45, 45, 100, color)    # 远距离投影

下图是生成的立方体在三维空间中的呈现:

 三维空间物体视锥投影数学推导_第8张图片

plot_2d函数会生成该立方体在视点空间中的视锥体投影,如下图所示(视距参数z_0=1.5):

三维空间物体视锥投影数学推导_第9张图片

如果把视距调远至100,则透视效果将会降低,视锥投影会逼近正射投影,如下图所示:

 

三维空间物体视锥投影数学推导_第10张图片

你可能感兴趣的:(线性代数,几何学,3d,python)