社群計算機視覺課程文件

3D 資料線性代數基礎

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

3D 資料線性代數基礎

座標系

大多數三維資料由點等物件組成,這些物件在空間中具有確定的位置,通常由它們的三個笛卡爾座標表示[X,Y,Z][X, Y, Z].

Axis handedness

然而,不同的系統對該座標系有不同的約定。最重要的區別是手性,即 X、Y 和 Z 軸的相對方向。記住這個區別最簡單的方法是向內彎曲中指,使拇指、食指和中指大致相互垂直。在您的左手中,拇指 (X)、食指 (Y) 和中指 (Z) 構成一個左手座標系。同樣,您的右手手指構成一個右手座標系。

在數學和物理學中,通常使用右手系。然而,在計算機圖形學中,不同的庫和環境有不同的約定。值得注意的是,Blender、Pytorch3d 和 OpenGL(大部分)使用右手座標系,而 DirectX 使用左手座標系。這裡我們將遵循 Blender 和 NerfStudio 的右手約定。

變換

能夠旋轉、縮放和平移空間中的這些座標非常有用。例如,如果一個物體正在移動,或者我們想將這些座標從相對於某個固定軸集的世界座標更改為相對於我們相機的座標。

這些變換可以用矩陣表示。這裡我們用 @ 表示矩陣乘法。為了能夠以一致的方式表示平移、旋轉和縮放,我們採用三維座標[x,y,z][x,y,z],並新增一個額外座標w=1w=1。這些被稱為齊次座標——更一般地,ww可以取任何值,並且四維線上的所有點[wx,wy,wz,w][wx, wy, wz, w]對應於三維空間中的同一點[x,y,z][x,y,z]。但是,這裡ww將始終為 1。

Pytorch3d 這樣的庫提供了一系列用於生成和操作變換的函式。

另一個需要注意的約定是——OpenGL 將位置視為列向量 x(形狀為 4x1),並透過將向量乘以矩陣(M @ x)來應用變換 M,而 DirectX 和 Pytorch3d 將位置視為形狀為 (1x4) 的行向量,並透過將向量乘以矩陣(x @ M)來應用變換。為了在兩種約定之間進行轉換,我們需要對矩陣 M.T 進行轉置。我們將在幾個程式碼片段中展示立方體在不同變換矩陣下的變換方式。對於這些程式碼片段,我們將使用 OpenGL 約定。

平移

平移,即將空間中所有點以相同距離和方向移動,可以表示為T=(100tx010ty001tz0001)T = \begin{pmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \end{pmatrix}

其中t=[tx,ty,tz]t = [t_x,t_y,t_z]是平移所有點的方向向量。

為了親自嘗試平移,讓我們首先編寫一個視覺化立方體的小輔助函式

import numpy as np
import matplotlib.pyplot as plt


def plot_cube(ax, cube, label, color="black"):
    ax.scatter3D(cube[0, :], cube[1, :], cube[2, :], label=label, color=color)
    lines = [
        [0, 1],
        [1, 2],
        [2, 3],
        [3, 0],
        [4, 5],
        [5, 6],
        [6, 7],
        [7, 4],
        [0, 4],
        [1, 5],
        [2, 6],
        [3, 7],
    ]
    for line in lines:
        ax.plot3D(cube[0, line], cube[1, line], cube[2, line], color=color)
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_zlabel("Z")
    ax.legend()
    ax.set_xlim([-2, 2])
    ax.set_ylim([-2, 2])
    ax.set_zlim([-2, 2])

現在,我們可以建立一個立方體並將其預乘平移矩陣

# define 8 corners of our cube with coordinates (x,y,z,w) and w is always 1 in our case
cube = np.array(
    [
        [-1, -1, -1, 1],
        [1, -1, -1, 1],
        [1, 1, -1, 1],
        [-1, 1, -1, 1],
        [-1, -1, 1, 1],
        [1, -1, 1, 1],
        [1, 1, 1, 1],
        [-1, 1, 1, 1],
    ]
)

# translate to follow OpenGL notation
cube = cube.T

# set up figure
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

# plot original cube
plot_cube(ax, cube, label="Original", color="blue")

# translation matrix (shift 1 in positive x and 1 in positive y-axis)
translation_matrix = np.array([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]])

# translation
translated_cube = translation_matrix @ cube
plot_cube(ax, translated_cube, label="Translated", color="red")

輸出應如下所示

output_translation

縮放

縮放是統一增加或減小物體尺寸的過程。縮放變換由一個矩陣表示,該矩陣將每個座標乘以一個比例因子。縮放矩陣由下式給出S=(sx0000sy0000sz00001)S = \begin{pmatrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}

讓我們嘗試以下示例,將立方體沿 X 軸縮放 2 倍,沿 Y 軸縮放 0.5 倍。

# set up figure
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

# plot original cube
plot_cube(ax, cube, label="Original", color="blue")

# scaling matrix (scale by 2 along x-axis and by 0.5 along y-axis)
scaling_matrix = np.array([[2, 0, 0, 0], [0, 0.5, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])


scaled_cube = scaling_matrix @ cube

plot_cube(ax, scaled_cube, label="Scaled", color="green")

輸出應如下所示

output_scaling

旋轉

繞軸旋轉是另一種常用的變換。有許多不同的表示旋轉的方法,包括尤拉角和四元數,這在某些應用中非常有用。同樣,Pytorch3d 等庫包含執行旋轉的廣泛功能。然而,作為一個簡單的示例,我們將只展示如何構造繞三個軸的旋轉。

  • 繞 X 軸旋轉Rx(α)=(10000cosαsinα00sinαcosα00001) R_x(\alpha) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \alpha & -\sin \alpha & 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}

下面是一個繞 X 軸正向旋轉 20 度的簡單示例

# set up figure
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

# plot original cube
plot_cube(ax, cube, label="Original", color="blue")

# rotation matrix: +20 deg around x-axis
angle = 20 * np.pi / 180
rotation_matrix = np.array(
    [
        [1, 0, 0, 0],
        [0, np.cos(angle), -np.sin(angle), 0],
        [0, np.sin(angle), np.cos(angle), 0],
        [0, 0, 0, 1],
    ]
)


rotated_cube = rotation_matrix @ cube

plot_cube(ax, rotated_cube, label="Rotated", color="orange")

輸出應如下所示

output_rotation
  • 繞 Y 軸旋轉Ry(β)=(cosβ0sinβ00100sinβ0cosβ00001) R_y(\beta) = \begin{pmatrix} \cos \beta & 0 & \sin \beta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \beta & 0 & \cos \beta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}

我們相信您可以使用上面的示例程式碼片段並弄清楚如何實現繞 Y 軸的旋轉。😎😎

  • 繞 Z 軸旋轉Rz(β)=(cosβsinβ00sinβcosβ0000100001) R_z(\beta) = \begin{pmatrix} \cos \beta & -\sin \beta & 0 & 0 \\ \sin \beta & \cos \beta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}

再來,您能使用上一個程式碼片段並實現繞 Z 軸的旋轉嗎❓

請注意,標準約定是,當旋轉軸指向觀察者時,正旋轉角度對應逆時針旋轉。另請注意,在大多數庫中,餘弦函式要求角度以弧度表示。要從度轉換為弧度,請乘以pi/180 pi/180.

組合變換

多個變換可以透過將其矩陣相乘來組合。請注意,矩陣的乘法順序很重要——矩陣從右到左應用。要建立一個按 P、Q、R 順序應用變換的矩陣,複合變換由以下給出X=R@Q@P X = R @ Q @ P.

如果我們要將上面進行的平移、旋轉和縮放一次性完成,它看起來如下

# set up figure
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

# plot original cube
plot_cube(ax, cube, label="Original", color="blue")

# combination of transforms
combination_transform = rotation_matrix.dot(scaling_matrix.dot(translation_matrix))
final_result = combination_transform.dot(cube)
plot_cube(ax, final_result, label="Combined", color="violet")

輸出應如下所示。

output_combined
< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.