点云可视化之旋转GIF动画
当我们拿到一个点云数据,想看看到底是啥样的东西,或者经过我们一系列操作(如点云重建)得到最后的点云模型,我们要向别人展示点云模型效果,我们可以考虑采用GIF旋转动画的形式。
安装第三方库
open3d
numpy
imageio
-
Open3D是一个开源的跨平台库,专注于高效的3D数据处理和实时3D可视化。它提供了广泛的功能,包括点云处理、几何体(如网格、体积、线框等)的操作、配准算法、表面重建、基于物理的渲染(PBR)、以及与深度学习框架(如PyTorch和TensorFlow)的集成。Open3D不仅支持CPU运算,还支持GPU加速,特别适合于三维计算机视觉、机器人学、以及三维重建等相关领域的研究和开发。
-
NumPy(Numerical Python)是Python中用于科学计算的核心库之一,它提供了一个强大的N维数组对象ndarray以及一套数学函数库,使得Python能够高效地处理大量的多维数据。NumPy是许多科学计算、数据分析、机器学习等库的基础,例如SciPy、Pandas、Matplotlib以及Open3D等都会依赖NumPy来进行底层的数据操作。
-
imageio是一个Python库,用于读写多种图像文件格式(如JPEG、PNG、TIFF、GIF等)。它允许开发者以统一的接口读取、写入和显示静态图像和动态图像序列。imageio常用于图像处理、计算机视觉、数据预处理和动画制作等方面,因为它提供了一种简洁、直观的方式来操作各种图像数据,并且可以与NumPy无缝集成,方便进行进一步的数据分析和处理。在Open3D中,imageio可用于读取和显示深度图或者其他图像数据,以配合3D数据的可视化和分析。
open3d用来处理点云以及可视化点云数据,imageio用来处理图像,生成GIF动画。
过程分析
关于Open3D库中的点云模型旋转,并没有直接提供具体的GIF动画,需要自行创建一个展示点云旋转的GIF。
在Open3D中,旋转点云可以通过设置旋转矩阵或者欧拉角(轴角式)来实现。
pcd.transform( M)
在 Open3D 库中,transform() 方法应用于点云 (PointCloud) 或三角网格 (TriangleMesh) 对象,参赛M为一个4x4齐次变换矩阵。这个矩阵可以组合了多种基本变换,包括:
- 旋转(绕某个轴或任意方向旋转一定角度)
- 平移(沿任意方向移动一定距离)
- 缩放(沿各个轴按比例放大或缩小)
- 镜像(通过反对称矩阵实现)
理想效果:围绕一个固定轴旋转的gif动画,旋转轴可以任意选择
问题拆分:
- 旋转轴如何确定
- 求4x4齐次变换矩阵M
- GIF图像合成
旋转轴如何确定
三维空间的一个旋转轴可以由一个方向向量
和一个起点
确定
求4x4齐次变换矩阵 M M M
绕任意轴旋转的这个过程可以分解为两步:
- 先绕过原点与旋转轴平行的线旋转
- 再平移到目标旋转轴
变换矩阵 M 在三维几何变换中可以分为两部分:旋转和平移(Rotation and Translation)
- 旋转部分通常体现在矩阵的左上角3x3的子矩阵中,这个子矩阵是对称并且行列式为1的正交矩阵,它负责描述点或向量在三维空间中的旋转操作。
- 平移部分体现在矩阵的第四列(除了最后一行),它们分别对应沿x、y、z轴的平移量
在一个三维空间中,齐次坐标系下的变换矩阵M
通常由旋转矩阵R
和平移向量T
组合而成,其形式如下:
M = [ R T 0 1 ] M = \begin{bmatrix} R & T \\ \mathbf{0} & 1 \end{bmatrix} M=[R0T1]
其中,
- R R R 是一个3x3的旋转矩阵,表示三维空间中的旋转变换。
- T T T 是一个长度为3的一维向量,扩展为列向量后构成一个3x1的矩阵,表示三维空间中的平移变换。
- 0 \mathbf{0} 0 是一个1x3的全零向量。
展开来看,变换矩阵M
的具体形式为:
M = [ r 11 r 12 r 13 t x r 21 r 22 r 23 t y r 31 r 32 r 33 t z 0 0 0 1 ] M = \begin{bmatrix} r_{11} & r_{12} & r_{13} & t_x \\ r_{21} & r_{22} & r_{23} & t_y \\ r_{31} & r_{32} & r_{33} & t_z \\ 0 & 0 & 0 & 1 \end{bmatrix} M= r11r21r310r12r22r320r13r23r330txtytz1
其中,
r
i
j
r_{ij}
rij表示旋转矩阵R
中的元素,
t
x
t_x
tx,
t
y
t_y
ty,
t
z
t_z
tz分别表示平移向量T
在三维空间中的各个分量。
旋转矩阵 R R R
绕
u
^
\hat{\textbf{u}}
u^ 旋转
θ
\theta
θ 的旋转矩阵R的公式为:
R
(
θ
,
u
^
)
=
[
cos
(
θ
)
+
u
x
2
(
1
−
cos
(
θ
)
)
u
x
u
y
(
1
−
cos
(
θ
)
)
−
u
z
sin
(
θ
)
u
x
u
z
(
1
−
cos
(
θ
)
)
+
u
y
sin
(
θ
)
u
y
u
x
(
1
−
cos
(
θ
)
)
+
u
z
sin
(
θ
)
cos
(
θ
)
+
u
y
2
(
1
−
cos
(
θ
)
)
u
y
u
z
(
1
−
cos
(
θ
)
)
−
u
x
sin
(
θ
)
u
z
u
x
(
1
−
cos
(
θ
)
)
−
u
y
sin
(
θ
)
u
z
u
y
(
1
−
cos
(
θ
)
)
+
u
x
sin
(
θ
)
cos
(
θ
)
+
u
z
2
(
1
−
cos
(
θ
)
)
]
R(\theta, \hat{\textbf{u}}) = \begin{bmatrix} \cos(\theta) + u_x^2(1-\cos(\theta)) & u_xu_y(1-\cos(\theta)) - u_z\sin(\theta) & u_xu_z(1-\cos(\theta)) + u_y\sin(\theta) \\ u_yu_x(1-\cos(\theta)) + u_z\sin(\theta) & \cos(\theta) + u_y^2(1-\cos(\theta)) & u_yu_z(1-\cos(\theta)) - u_x\sin(\theta) \\ u_zu_x(1-\cos(\theta)) - u_y\sin(\theta) & u_zu_y(1-\cos(\theta)) + u_x\sin(\theta) & \cos(\theta) + u_z^2(1-\cos(\theta)) \end{bmatrix}
R(θ,u^)=
cos(θ)+ux2(1−cos(θ))uyux(1−cos(θ))+uzsin(θ)uzux(1−cos(θ))−uysin(θ)uxuy(1−cos(θ))−uzsin(θ)cos(θ)+uy2(1−cos(θ))uzuy(1−cos(θ))+uxsin(θ)uxuz(1−cos(θ))+uysin(θ)uyuz(1−cos(θ))−uxsin(θ)cos(θ)+uz2(1−cos(θ))
其中,
- θ \theta θ 是围绕轴向量 u ^ \hat{\textbf{u}} u^ 的旋转角度,
- u x u_x ux, u y u_y uy, u z u_z uz 是轴向量 u ^ \hat{\textbf{u}} u^ 在 x x x、 y y y、 z z z轴上的分量,
- u ^ \hat{\textbf{u}} u^ 是单位向量,满足 ∥ u ^ ∥ = 1 \lVert \hat{\textbf{u}} \rVert = 1 ∥u^∥=1。
平移矩阵 T T T
T T T取旋转轴起点[x,y,z]到原点的平移矩阵
T = [ x y z ] T= \begin{bmatrix} x\\ y\\ z \end{bmatrix} T= xyz
合并得到变换矩阵 M M M
GIF图像合成
使用open3d
库渲染旋转的每一贞图像,使用vis.capture_screen_float_buffer
保存图像信息列表。
imageio.mimsave()
是 imageio
库中用于将一系列图像帧保存为 GIF 动画文件的一个函数。下面是 imageio.mimsave()
函数的基本用法和参数说明:
imageio.mimsave(gifname, frames, fps=60, duration=None, subrectangles=False, loop=0, metadata=None)
-
gifname
(str): 指定要保存的 GIF 动画文件的名称(包括路径和扩展名,例如"animation.gif"
)。 -
frames
(list or generator): 包含多个图像的数据,可以是 PIL.Image 对象的列表,或者是返回 PIL.Image 对象的生成器。每一幅图像都将作为动画中的一帧。 -
fps
(float, 默认为 60): 每秒帧数,即动画播放的速度。例如设置为 60,意味着动画将以每秒 60 帧的速度播放。 -
duration
(float, 默认为 None): 如果提供了这个参数,它将覆盖fps
参数的作用,指定每一帧持续的时间(以秒为单位)。如果不提供,则根据fps
计算每一帧的持续时间。 -
subrectangles
(bool, 默认为 False): 是否启用子矩形优化。如果为 True,imageio 将尝试仅保存每帧发生变化的部分,以减小 GIF 文件大小。但请注意,不是所有格式都支持此特性。 -
loop
(int, 默认为 0): 表示动画循环播放的次数。0 或 1 表示循环一次(即播放完后停止),-1 表示无限循环。 -
metadata
(dict, 默认为 None): 可选的元数据字典,用于保存附加的信息。