社区计算机视觉课程文档
3D 数据线性代数基础
并获得增强的文档体验
开始使用
3D 数据线性代数基础
坐标系
大多数三维数据由点等对象组成,这些对象在空间中具有确定的位置,通常由它们的三个笛卡尔坐标表示.
然而,不同的系统对该坐标系有不同的约定。最重要的区别是手性,即 X、Y 和 Z 轴的相对方向。记住这个区别最简单的方法是向内弯曲中指,使拇指、食指和中指大致相互垂直。在您的左手中,拇指 (X)、食指 (Y) 和中指 (Z) 构成一个左手坐标系。同样,您的右手手指构成一个右手坐标系。
在数学和物理学中,通常使用右手系。然而,在计算机图形学中,不同的库和环境有不同的约定。值得注意的是,Blender、Pytorch3d 和 OpenGL(大部分)使用右手坐标系,而 DirectX 使用左手坐标系。这里我们将遵循 Blender 和 NerfStudio 的右手约定。
变换
能够旋转、缩放和平移空间中的这些坐标非常有用。例如,如果一个物体正在移动,或者我们想将这些坐标从相对于某个固定轴集的世界坐标更改为相对于我们相机的坐标。
这些变换可以用矩阵表示。这里我们用 @
表示矩阵乘法。为了能够以一致的方式表示平移、旋转和缩放,我们采用三维坐标,并添加一个额外坐标。这些被称为齐次坐标——更一般地,可以取任何值,并且四维线上的所有点对应于三维空间中的同一点。但是,这里将始终为 1。
像 Pytorch3d 这样的库提供了一系列用于生成和操作变换的函数。
另一个需要注意的约定是——OpenGL 将位置视为列向量 x
(形状为 4x1),并通过将向量乘以矩阵(M @ x
)来应用变换 M
,而 DirectX 和 Pytorch3d 将位置视为形状为 (1x4) 的行向量,并通过将向量乘以矩阵(x @ M
)来应用变换。为了在两种约定之间进行转换,我们需要对矩阵 M.T
进行转置。我们将在几个代码片段中展示立方体在不同变换矩阵下的变换方式。对于这些代码片段,我们将使用 OpenGL 约定。
平移
平移,即将空间中所有点以相同距离和方向移动,可以表示为
其中是平移所有点的方向向量。
为了亲自尝试平移,让我们首先编写一个可视化立方体的小辅助函数
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")
输出应如下所示

缩放
缩放是统一增加或减小物体尺寸的过程。缩放变换由一个矩阵表示,该矩阵将每个坐标乘以一个比例因子。缩放矩阵由下式给出
让我们尝试以下示例,将立方体沿 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")
输出应如下所示

旋转
绕轴旋转是另一种常用的变换。有许多不同的表示旋转的方法,包括欧拉角和四元数,这在某些应用中非常有用。同样,Pytorch3d 等库包含执行旋转的广泛功能。然而,作为一个简单的示例,我们将只展示如何构造绕三个轴的旋转。
- 绕 X 轴旋转
下面是一个绕 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")
输出应如下所示

- 绕 Y 轴旋转
我们相信您可以使用上面的示例代码片段并弄清楚如何实现绕 Y 轴的旋转。😎😎
- 绕 Z 轴旋转
再来,您能使用上一个代码片段并实现绕 Z 轴的旋转吗❓
请注意,标准约定是,当旋转轴指向观察者时,正旋转角度对应逆时针旋转。另请注意,在大多数库中,余弦函数要求角度以弧度表示。要从度转换为弧度,请乘以.
组合变换
多个变换可以通过将其矩阵相乘来组合。请注意,矩阵的乘法顺序很重要——矩阵从右到左应用。要创建一个按 P、Q、R 顺序应用变换的矩阵,复合变换由以下给出.
如果我们要将上面进行的平移、旋转和缩放一次性完成,它看起来如下
# 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")
输出应如下所示。
