【Open3D】基础操作之三维变换
【Open3D】基础操作之三维变换
文章目录
- 【Open3D】基础操作之三维变换
- 前言
- 三维旋转
- o3d.geometry.TriangleMesh.create_coordinate_frame(创建表示坐标系的三角形网格的函数)
- Rotation Matrix(旋转矩阵)
- o3d.geometry.rotate(对几何对象进行旋转变换的函数)
- Rotation Vector(旋转向量)
- o3d.geometry.get_rotation_matrix_from_axis_angle(从旋转向量生成旋转矩阵的函数)
- Euler Angles(欧拉角)
- o3d.geometry.get_rotation_matrix_from_AAA(从欧拉角生成旋转矩阵的函数)
- Quaternions(四元数)
- o3d.geometry.get_rotation_matrix_from_quaternion(从四元素生成旋转矩阵的函数)
- 三维平移和缩放
- Translation(平移)
- o3d.geometry.translate(对几何对象进行平移操作的函数)
- Scale(缩放)
- o3d.geometry.translate(对几何对象进行缩放操作的函数)
- o3d.geometry.get_center(计算并返回几何体的中心点的函数)
- 总结
前言
Open3D 是一个开源库,旨在支持快速开发处理 3D 数据的软件。它提供了精心挑选的 C++ 和 Python 数据结构和算法,并且后端经过高度优化并设置为并行化。
官方文档:http://www.open3d.org/docs/
GitHub仓库:https://github.com/isl-org/Open3D
三维旋转
在三维空间中表示和计算旋转是计算机图形学、机器人学、航空航天等领域中的核心问题。主要有四种常用的方法:旋转矩阵 (Rotation Matrix)、旋转向量 (Rotation Vector)、欧拉角 (Euler Angles) 和 四元数 (Quaternions)。
o3d.geometry.TriangleMesh.create_coordinate_frame(创建表示坐标系的三角形网格的函数)
函数原型
o3d.geometry.TriangleMesh.create_coordinate_frame(size=1.0, origin=[0.0, 0.0, 0.0])
返回一个TriangleMesh对象,表示3D坐标系。
红色箭头表示 X 轴;绿色箭头表示 Y 轴;蓝色箭头表示 Z 轴。
参数 | 参数说明 |
---|---|
size (float, 可选,默认值1.0) | 坐标系的大小(比例因子),控制坐标轴的长度和整体大小。 |
origin (list[float], 可选,默认值[0.0, 0.0, 0.0]) | 坐标系原点的位置,格式为 [x, y, z]。 |
示例
import open3d as o3d# 创建默认大小的坐标系(原点在[0,0,0],大小为1.0)
coord_frame = o3d.geometry.TriangleMesh.create_coordinate_frame()
# 创建自定义坐标系(原点在[1,2,3],大小为2.0)
custom_coord_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=2.0, origin=[1.0, 2.0, 3.0]
)
# 可视化
o3d.visualization.draw_geometries([coord_frame, custom_coord_frame])
Rotation Matrix(旋转矩阵)
旋转矩阵是一个3x3的矩阵,用来描述一个刚体绕着某个固定点(通常是原点)进行旋转的情况。用3x3 旋转矩阵 R\mathbf{R}R来旋转一个三维空间中的点或向量 v=[x,y,z]T\mathbf{v} = [x, y, z]^Tv=[x,y,z]T :
v′=Rv=[r11r12r13r21r22r23r31r32r33]v\mathbf{v'} = \mathbf{R}\mathbf{v} = \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{bmatrix}\mathbf{v}v′=Rv=r11r21r31r12r22r32r13r23r33v
后续的旋转向量、欧拉角和 四元数最终都需要先转化成旋转矩阵,然后再进行旋转变换。
o3d.geometry.rotate(对几何对象进行旋转变换的函数)
适用于 TriangleMesh、PointCloud、LineSet 等几何类型。
函数原型
geometry.rotate(R, center=(0, 0, 0))
没有显式返回值,直接修改调用它的几何对象的顶点坐标。
参数 | 参数说明 |
---|---|
R (np.ndarray) | 3x3 的旋转矩阵。 |
center (tuple/list, 可选,默认为原点(0, 0, 0)) | 旋转中心的坐标,格式为 (x, y, z)。 |
Rotation Vector(旋转向量)
旋转向量使用一个三维向量来同时描述旋转轴和旋转角度,旋转向量的方向表示旋转轴的方向,而其长度(或者说模)则代表旋转的角度大小。给定一个旋转向量r=(rx,ry,rz)\mathbf{r} = (r_x, r_y, r_z)r=(rx,ry,rz) ,其对应的旋转轴为单位向量n=(nx,ny,nz)\mathbf{n} = (n_x, n_y, n_z)n=(nx,ny,nz),旋转角度为θ\thetaθ,则有r=θn\mathbf{r} = \theta \mathbf{n}r=θn。
公式 r=θnr = θnr=θn 中的乘法把旋转角度 θθθ 这个数值直接乘以表示旋转轴方向的单位向量 nnn,得到的向量 rrr 同时包含了旋转轴的方向(由其方向决定)和旋转角度的大小(由其长度决定)。
要将一个三维点p=(x,y,z)\mathbf{p} = (x, y, z)p=(x,y,z)绕此旋转轴旋转指定角度,可以使用罗德里格斯公式得到旋转后的点p′\mathbf{p}'p′:
p′=cosθp+(1−cosθ)(p⋅n)n+sinθ(n×p)\mathbf{p}' = \cos \theta \mathbf{p} + (1 - \cos \theta) (\mathbf{p} \cdot \mathbf{n}) \mathbf{n} + \sin \theta (\mathbf{n} \times \mathbf{p})p′=cosθp+(1−cosθ)(p⋅n)n+sinθ(n×p)
另一种常见的方法是使用旋转矩阵,对于绕任意轴 nnn 旋转角度 θθθ 的情况,旋转矩阵 RRR 可以根据旋转向量计算得到:
R=[cosθ+nx2(1−cosθ)nxny(1−cosθ)−nzsinθnxnz(1−cosθ)+nysinθnynx(1−cosθ)+nzsinθcosθ+ny2(1−cosθ)nynz(1−cosθ)−nxsinθnznx(1−cosθ)−nysinθnzny(1−cosθ)+nxsinθcosθ+nz2(1−cosθ)]R = \begin{bmatrix} \cos \theta + n_x^2 (1 - \cos \theta) & n_x n_y (1 - \cos \theta) - n_z \sin \theta & n_x n_z (1 - \cos \theta) + n_y \sin \theta \\ n_y n_x (1 - \cos \theta) + n_z \sin \theta & \cos \theta + n_y^2 (1 - \cos \theta) & n_y n_z (1 - \cos \theta) - n_x \sin \theta \\ n_z n_x (1 - \cos \theta) - n_y \sin \theta & n_z n_y (1 - \cos \theta) + n_x \sin \theta & \cos \theta + n_z^2 (1 - \cos \theta) \end{bmatrix}R=cosθ+nx2(1−cosθ)nynx(1−cosθ)+nzsinθnznx(1−cosθ)−nysinθnxny(1−cosθ)−nzsinθcosθ+ny2(1−cosθ)nzny(1−cosθ)+nxsinθnxnz(1−cosθ)+nysinθnynz(1−cosθ)−nxsinθcosθ+nz2(1−cosθ)
o3d.geometry.get_rotation_matrix_from_axis_angle(从旋转向量生成旋转矩阵的函数)
o3d.geometry.get_rotation_matrix_from_axis_angle(axis_angle)
返回一个 3x3 的旋转矩阵 。
参数 | 参数说明 |
---|---|
axis_angle (np.ndarray) | 形状为(3,)的数组,旋转轴的方向向量,包含三个欧拉角,顺序为绕X、Y、Z轴的旋转角度。 |
示例:
import open3d as o3d
import numpy as np
import copy# 创建原始坐标系
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() # 深拷贝坐标系用于旋转
mesh_r = copy.deepcopy(mesh) # 定义旋转向量(注意:这里的向量不是分别绕XYZ轴旋转,而是沿某个轴的旋转)
# np.pi/2 是 90度, np.pi/3 是 60度, np.pi/4 是 45度
rotation_vector = np.array([np.pi / 2, np.pi / 3, np.pi / 4])# 将旋转向量转换为旋转矩阵
# 输入表示的是旋转轴方向和旋转角度的组合,不是欧拉角
R = o3d.geometry.get_rotation_matrix_from_axis_angle(rotation_vector) print("总的旋转矩阵:")
print(R)# 应用旋转,以原点为中心
mesh_r.rotate(R, center=(0, 0, 0)) # 可视化原始和旋转后的坐标系
o3d.visualization.draw_geometries([mesh, mesh_r])
Euler Angles(欧拉角)
欧拉角通过三个角度来表示一个刚体在三维空间中的旋转状态,这三个角度通常代表了绕着特定坐标轴的三次连续旋转。根据选择的旋转顺序不同,可以有多种不同的欧拉角定义方式。
常见的旋转顺序包括XYZ、XZY、YXZ、YZX、ZXY和ZYX等,这些旋转顺序分别代表了按照选定的顺序依次绕着坐标系的X轴、Y轴和Z轴进行旋转。
以下是绕三个基本坐标轴旋转的旋转矩阵。
- 绕XXX轴旋转α\alphaα角的旋转矩阵:
Rx(α)=[1000cosα−sinα0sinαcosα]R_x(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha \\ 0 & \sin\alpha & \cos\alpha \end{bmatrix}Rx(α)=1000cosαsinα0−sinαcosα - 绕YYY轴旋转β\betaβ角的旋转矩阵:
Ry(β)=[cosβ0sinβ010−sinβ0cosβ]R_y(\beta) = \begin{bmatrix} \cos\beta & 0 & \sin\beta \\ 0 & 1 & 0 \\ -\sin\beta & 0 & \cos\beta \end{bmatrix}Ry(β)=cosβ0−sinβ010sinβ0cosβ - 绕ZZZ轴旋转γ\gammaγ角的旋转矩阵:
Rz(γ)=[cosγ−sinγ0sinγcosγ0001]R_z(\gamma) = \begin{bmatrix} \cos\gamma & -\sin\gamma & 0 \\ \sin\gamma & \cos\gamma & 0 \\ 0 & 0 & 1 \end{bmatrix}Rz(γ)=cosγsinγ0−sinγcosγ0001
总的旋转矩阵可以通过将这三个单独的旋转矩阵相乘得到,对于ZYX顺序的欧拉角变换,其对应的旋转矩阵为:
R=Rz(γ)⋅Ry(β)⋅Rx(α)=[cosγcosβcosγsinβsinα−sinγcosαcosγsinβcosα+sinγsinαsinγcosβsinγsinβsinα+cosγcosαsinγsinβcosα−cosγsinα−sinβcosβsinαcosβcosα]R =R_z(\gamma) \cdot R_y(\beta) \cdot R_x(\alpha)= \begin{bmatrix} \cos\gamma\cos\beta & \cos\gamma\sin\beta\sin\alpha - \sin\gamma\cos\alpha & \cos\gamma\sin\beta\cos\alpha + \sin\gamma\sin\alpha \\ \sin\gamma\cos\beta & \sin\gamma\sin\beta\sin\alpha + \cos\gamma\cos\alpha & \sin\gamma\sin\beta\cos\alpha - \cos\gamma\sin\alpha \\ -\sin\beta & \cos\beta\sin\alpha & \cos\beta\cos\alpha \end{bmatrix}R=Rz(γ)⋅Ry(β)⋅Rx(α)=cosγcosβsinγcosβ−sinβcosγsinβsinα−sinγcosαsinγsinβsinα+cosγcosαcosβsinαcosγsinβcosα+sinγsinαsinγsinβcosα−cosγsinαcosβcosα
o3d.geometry.get_rotation_matrix_from_AAA(从欧拉角生成旋转矩阵的函数)
函数原型
o3d.geometry.get_rotation_matrix_from_AAA(rotation)
AAA具体表示的函数 | 旋转顺序 | 说明 |
---|---|---|
get_rotation_matrix_from_xyz | X→Y→Z | 先绕X轴,再绕Y轴,最后绕Z轴 |
get_rotation_matrix_from_xzy | X→Z→Y | 先绕X轴,再绕Z轴,最后绕Y轴 |
get_rotation_matrix_from_yxz | Y→X→Z | 先绕Y轴,再绕X轴,最后绕Z轴 |
get_rotation_matrix_from_yzx | Y→Z→X | 先绕Y轴,再绕Z轴,最后绕X轴 |
get_rotation_matrix_from_zxy | Z→X→Y | 先绕Z轴,再绕X轴,最后绕Y轴 |
get_rotation_matrix_from_zyx | Z→Y→X | 先绕Z轴,再绕Y轴,最后绕X轴 |
get_rotation_matrix_from_xyx | X→Y→X | 两次绕X轴(经典欧拉角 |
get_rotation_matrix_from_xzx | X→Z→X | 两次绕X轴(经典欧拉角 |
get_rotation_matrix_from_yxy | Y→X→Y | 两次绕Y轴(经典欧拉角 |
get_rotation_matrix_from_yzy | Y→Z→Y | 两次绕Y轴(经典欧拉角 |
get_rotation_matrix_from_zxz | Z→X→Z | 两次绕Z轴(经典欧拉角 |
get_rotation_matrix_from_zyz | Z→Y→Z | 两次绕Z轴(经典欧拉角 |
返回一个 3x3 的旋转矩阵 。
参数 | 参数说明 |
---|---|
rotation (np.ndarray) | 显式格式:形状为(4,)的数组,前三个元素是旋转轴向量(x, y, z),第四个元素是旋转角度(弧度); 紧凑格式:形状为(3,)的数组,旋转向量的方向表示旋转轴,旋转向量的模长表示旋转角度(弧度)。 |
示例:
import open3d as o3d
import numpy as np
import copy# 创建原始坐标系
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()# 深拷贝坐标系用于旋转
mesh_r = copy.deepcopy(mesh)# 定义欧拉角(绕X轴旋转90度,绕Y轴旋转60度,绕Z轴旋转45度)
# 弧度
euler_angles = np.array([np.pi / 2, # X轴: 90度 (π/2)np.pi / 3, # Y轴: 60度 (π/3)np.pi / 4]) # Z轴: 45度 (π/4)# 将欧拉角转换为旋转矩阵 (使用 ZYX 旋转顺序)
R = o3d.geometry.get_rotation_matrix_from_zyx(euler_angles) print("总的旋转矩阵 (XYZ顺序):")
print(R)# 应用旋转,以原点为中心
mesh_r.rotate(R, center=(0, 0, 0))# 可视化原始和旋转后的坐标系
o3d.visualization.draw_geometries([mesh, mesh_r])
Quaternions(四元数)
四元数是一个扩展了复数概念的数学实体,由一个实部和三个虚部组成,可以用来表示三维空间中的旋转。
四元数 q=[w,x,y,z]q = [w, x, y, z]q=[w,x,y,z]形式上可以写作:
q=w+xi+yj+zkq = w + xi + yj + zkq=w+xi+yj+zk
对应的旋转矩阵 RRR 表示为:
R=[1−2(y2+z2)2(xy−wz)2(xz+wy)2(xy+wz)1−2(x2+z2)2(yz−wx)2(xz−wy)2(yz+wx)1−2(x2+y2)]R = \begin{bmatrix} 1 - 2(y^2 + z^2) & 2(xy - wz) & 2(xz + wy) \\ 2(xy + wz) & 1 - 2(x^2 + z^2) & 2(yz - wx) \\ 2(xz - wy) & 2(yz + wx) & 1 - 2(x^2 + y^2) \end{bmatrix}R=1−2(y2+z2)2(xy+wz)2(xz−wy)2(xy−wz)1−2(x2+z2)2(yz+wx)2(xz+wy)2(yz−wx)1−2(x2+y2)
这里需要注意的是,四元数 qqq 应该是单位四元数(即满足 w2+x2+y2+z2=1w^2 + x^2 + y^2 + z^2 = 1w2+x2+y2+z2=1),这样才能正确表示一个旋转。如果不是单位四元数,则需要先将其归一化
o3d.geometry.get_rotation_matrix_from_quaternion(从四元素生成旋转矩阵的函数)
函数原型
o3d.geometry.get_rotation_matrix_from_quaternion(quaternion)
返回一个 3x3 的旋转矩阵 。
参数 | 参数说明 |
---|---|
quaternion (np.ndarray) | 旋转的四元数,顺序为 (w, x, y, z)。 |
示例:
import open3d as o3d
import numpy as np
import copy# 创建原始坐标系
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()# 深拷贝坐标系用于旋转
mesh_r = copy.deepcopy(mesh)# 定义一个四元数[w,x,y,z]
quat = np.array([0.7330127, 0.30940108, 0.58508386, 0.15891862])
# 从四元数获取旋转矩阵
R = o3d.geometry.get_rotation_matrix_from_quaternion(quat)print("旋转矩阵:")
print(R)# 应用旋转,以原点为中心
mesh_r.rotate(R, center=(0, 0, 0))# 可视化原始和旋转后的坐标系
o3d.visualization.draw_geometries([mesh, mesh_r])
三维平移和缩放
Translation(平移)
在三维空间中,平移变换是最基本的几何变换之一,用于将点或物体沿指定方向移动固定距离,只是它在空间中的位置发生了变化。
原始点坐标: P=(x,y,z)P = (x, y, z)P=(x,y,z),平移T=(tx,ty,tz)T = (t_x, t_y, t_z)T=(tx,ty,tz)后的新坐标:
P′=P+T=(x+txy+tyz+tz)P' = P + T = \begin{pmatrix} x + t_x \\ y + t_y \\ z + t_z \end{pmatrix} P′=P+T=x+txy+tyz+tz
其中,txt_xtx, tyt_yty, 和 tzt_ztz 分别表示在 xxx 轴、yyy 轴和 zzz 轴方向上的平移距离。
o3d.geometry.translate(对几何对象进行平移操作的函数)
适用于 TriangleMesh、PointCloud、LineSet 等几何类型。
函数原型
geometry.translate(T, relative=True)
没有显式返回值,直接修改调用它的几何对象的顶点坐标。
参数 | 参数说明 |
---|---|
T (np.ndarray,list) | 形状需为[3,],平移向量的三维数组 [tx, ty, tz]。 |
relative (bool, 可选,默认为True) | True相对平移,在当前基础上增加平移量;False绝对平移,将物体中心移动到指定位置。 |
示例:
import open3d as o3d
import copy# 创建原始坐标系
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()# 深拷贝坐标系用于旋转
mesh_t = copy.deepcopy(mesh)# 设置平移向量 (X, Y, Z 三个方向的平移距离)
T = (2, 2, 2)# 平移操作(绝对平移)
mesh_t.translate(T, relative=False)# 可视化原始和旋转后的坐标系
o3d.visualization.draw_geometries([mesh, mesh_t])
Scale(缩放)
在三维空间中,缩放变换是另一种基本的几何变换,用于改变点或物体的大小。通过缩放变换,我们可以使物体变大或变小,而其形状保持不变。
原始点坐标: P=(x,y,z)P = (x, y, z)P=(x,y,z),缩放因子 S=(sx,sy,sz)S = (s_x, s_y, s_z)S=(sx,sy,sz) 后的新坐标:
P′=P⋅S=(x⋅sxy⋅syz⋅sz)P' = P \cdot S = \begin{pmatrix} x \cdot s_x \\ y \cdot s_y \\ z \cdot s_z \end{pmatrix}P′=P⋅S=x⋅sxy⋅syz⋅sz
其中,sxs_xsx, sys_ysy, 和 szs_zsz 分别表示在 xxx 轴、yyy 轴和 zzz 轴方向上的缩放比例。如果 sx=sy=szs_x = s_y = s_zsx=sy=sz,则物体将均匀缩放;否则,物体将进行非均匀缩放,导致物体在不同轴方向上的尺寸变化不一致。
o3d.geometry.translate(对几何对象进行缩放操作的函数)
适用于 TriangleMesh、PointCloud、LineSet 等几何类型。
函数原型
geometry.scale(S, center=None)
没有显式返回值,直接修改调用它的几何对象的顶点坐标。
参数 | 参数说明 |
---|---|
S (float) | 所有轴按相同比例缩放。 |
center (np.ndarray或list) | 缩放中心点坐标。 |
示例:
import open3d as o3d
import copy# 创建原始坐标系
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame(size=1.0) # 设置初始大小# 深拷贝坐标系用于缩放
mesh_s = copy.deepcopy(mesh)# 设置缩放因子 (X, Y, Z 三个方向的缩放比例)
scale_factor = 2.0 # 均匀放大2倍# 执行缩放操作(相对于物体自身坐标系原点)
mesh_s.scale(scale_factor, center=mesh_s.get_center())# 可视化原始和缩放后的坐标系
o3d.visualization.draw_geometries([mesh, mesh_s])
o3d.geometry.get_center(计算并返回几何体的中心点的函数)
适用于 TriangleMesh、PointCloud、LineSet 等几何类型。
函数原型
geometry.get_center()
返回一个中心点坐标的 np.ndarray数组 [cx, cy, cz]。
总结
Open3D的三维变换基本操作。