scipy.spatial.transform.

Rotation#

class scipy.spatial.transform.Rotation(quat, normalize=True, copy=True, scalar_first=False)[source]#

三维空间中的旋转。

此类提供了一个接口,用于通过以下方式初始化和表示旋转:

  • 四元数 (Quaternions)

  • 旋转矩阵 (Rotation Matrices)

  • 旋转向量 (Rotation Vectors)

  • 修正罗德里格参数 (Modified Rodrigues Parameters)

  • 欧拉角 (Euler Angles)

  • 达文波特角 (Davenport Angles,广义欧拉角)

支持以下旋转运算:

  • 应用于向量

  • 旋转合成

  • 旋转求逆

  • 旋转索引

Rotation 实例可以包含单个旋转变换或具有多个前导维度的旋转。例如,可以拥有 (N, M, K) 个旋转的 N 维数组。当应用于其他旋转或向量时,遵循标准的广播规则。

支持旋转内部索引,以访问 Rotation 实例中存储的旋转子集。

要创建 Rotation 对象,请使用 from_... 方法(见下文示例)。不应直接实例化 Rotation(...)

参数:
quatarray_like, shape (…, 4)

表示旋转的四元数。

normalizebool, optional

如果为 True,则使用奇异值分解对旋转矩阵进行正交归一化。如果为 False,则不对旋转矩阵进行正交性或右手性的检查。

copybool,可选

如果为 True,则复制输入矩阵。如果为 False,则使用对输入矩阵的引用。如果 normalize 为 True,则无论 copy 的值如何,都会复制输入矩阵。

scalar_firstbool, 可选

如果 True,则期望 quat 采用标量在前 (scalar-first) 的格式,否则期望采用标量在后 (scalar-last) 的格式。默认为 False

属性:
单个

该实例是否表示单个旋转。

方法

__len__()

此对象中包含的旋转数量。

from_quat(quat, *[, scalar_first])

通过四元数初始化。

from_matrix(matrix, *[, assume_valid])

通过旋转矩阵初始化。

from_rotvec(rotvec[, degrees])

通过旋转向量初始化。

from_mrp(mrp)

通过修正罗德里格参数 (MRP) 初始化。

from_euler(seq, angles[, degrees])

通过欧拉角初始化。

from_davenport(axes, order, angles[, degrees])

通过达文波特角初始化。

as_quat([canonical, scalar_first])

表示为四元数。

as_matrix()

表示为旋转矩阵。

as_rotvec([degrees])

表示为旋转向量。

as_mrp()

表示为修正罗德里格参数 (MRP)。

as_euler(seq[, degrees, suppress_warnings])

表示为欧拉角。

as_davenport(axes, order[, degrees, ...])

表示为达文波特角。

concatenate(rotations)

将一系列 Rotation 对象拼接成单个对象。

apply(vectors[, inverse])

将此旋转应用于一组向量。

__mul__(other)

将此旋转与其他旋转进行合成。

__pow__(n[, modulus])

将此旋转与其自身合成 n 次。

inv()

此旋转求逆。

magnitude()

获取旋转的大小。

approx_equal(other[, atol, degrees])

确定另一个旋转是否与当前旋转近似相等。

mean([weights, axis])

获取旋转的平均值。

reduce([left, right, return_indices])

利用提供的旋转组简化此旋转。

create_group(group[, axis])

创建一个三维旋转组。

__getitem__(indexer)

从对象中提取给定索引处的旋转。

identity([num, shape])

获取单位旋转 (Identity Rotation)。

random([num, rng, shape, random_state])

生成在球面上均匀分布的旋转。

align_vectors(a, b[, weights, ...])

估计一个旋转以最优地对齐两组向量。

另请参阅

球面线性插值

附注

在 1.2.0 版本中添加。

数组 API 标准支持

Rotation 除了 NumPy 之外,还对符合 Python Array API 标准的后端提供了实验性支持。请考虑通过设置环境变量 SCIPY_ARRAY_API=1 并提供 CuPy、PyTorch、JAX 或 Dask 数组作为数组参数来测试这些功能。支持后端和设备(或其他功能)的以下组合。

CPU

GPU

NumPy

不适用

CuPy

不适用

PyTorch

JAX

Dask

不适用

方法 as_davenportapplyalign_vectors 在 cupy<14.* 中不受支持。

有关更多信息,请参阅 对数组 API 标准的支持

示例

>>> from scipy.spatial.transform import Rotation as R
>>> import numpy as np

Rotation 实例可以使用上述任何格式初始化,并转换为其他任何格式。基础对象独立于初始化时使用的表示形式。

考虑绕 z 轴逆时针旋转 90 度。这对应于以下四元数(采用标量在后格式)

>>> r = R.from_quat([0, 0, np.sin(np.pi/4), np.cos(np.pi/4)])

该旋转可以用其他任何格式表示

>>> r.as_matrix()
array([[ 2.22044605e-16, -1.00000000e+00,  0.00000000e+00],
[ 1.00000000e+00,  2.22044605e-16,  0.00000000e+00],
[ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])
>>> r.as_rotvec()
array([0.        , 0.        , 1.57079633])
>>> r.as_euler('zyx', degrees=True)
array([90.,  0.,  0.])

同样的旋转可以使用旋转矩阵进行初始化

>>> r = R.from_matrix([[0, -1, 0],
...                    [1, 0, 0],
...                    [0, 0, 1]])

其他格式的表示

>>> r.as_quat()
array([0.        , 0.        , 0.70710678, 0.70710678])
>>> r.as_rotvec()
array([0.        , 0.        , 1.57079633])
>>> r.as_euler('zyx', degrees=True)
array([90.,  0.,  0.])

对应于此旋转的旋转向量由下式给出

>>> r = R.from_rotvec(np.pi/2 * np.array([0, 0, 1]))

其他格式的表示

>>> r.as_quat()
array([0.        , 0.        , 0.70710678, 0.70710678])
>>> r.as_matrix()
array([[ 2.22044605e-16, -1.00000000e+00,  0.00000000e+00],
       [ 1.00000000e+00,  2.22044605e-16,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])
>>> r.as_euler('zyx', degrees=True)
array([90.,  0.,  0.])

from_euler 方法在其支持的输入格式范围方面非常灵活。此处我们初始化绕单轴的单个旋转

>>> r = R.from_euler('z', 90, degrees=True)

同样,该对象独立于表示形式,可以转换为任何其他格式

>>> r.as_quat()
array([0.        , 0.        , 0.70710678, 0.70710678])
>>> r.as_matrix()
array([[ 2.22044605e-16, -1.00000000e+00,  0.00000000e+00],
       [ 1.00000000e+00,  2.22044605e-16,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])
>>> r.as_rotvec()
array([0.        , 0.        , 1.57079633])

还可以使用任何 from_... 函数在单个实例中初始化多个旋转。此处我们使用 from_euler 方法初始化一组 3 个旋转

>>> r = R.from_euler('zyx', [
... [90, 0, 0],
... [0, 45, 0],
... [45, 60, 30]], degrees=True)

其他表示形式现在也返回一组 3 个旋转。例如

>>> r.as_quat()
array([[0.        , 0.        , 0.70710678, 0.70710678],
       [0.        , 0.38268343, 0.        , 0.92387953],
       [0.39190384, 0.36042341, 0.43967974, 0.72331741]])

将上述旋转应用于向量

>>> v = [1, 2, 3]
>>> r.apply(v)
array([[-2.        ,  1.        ,  3.        ],
       [ 2.82842712,  2.        ,  1.41421356],
       [ 2.24452282,  0.78093109,  2.89002836]])

Rotation 实例可以像 ND 数组一样进行索引和切片

>>> r.as_quat()
array([[0.        , 0.        , 0.70710678, 0.70710678],
       [0.        , 0.38268343, 0.        , 0.92387953],
       [0.39190384, 0.36042341, 0.43967974, 0.72331741]])
>>> p = r[0]
>>> p.as_matrix()
array([[ 2.22044605e-16, -1.00000000e+00,  0.00000000e+00],
       [ 1.00000000e+00,  2.22044605e-16,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])
>>> q = r[1:3]
>>> q.as_quat()
array([[0.        , 0.38268343, 0.        , 0.92387953],
       [0.39190384, 0.36042341, 0.43967974, 0.72331741]])

事实上,它可以转换为 numpy.array

>>> r_array = np.asarray(r)
>>> r_array.shape
(3,)
>>> r_array[0].as_matrix()
array([[ 2.22044605e-16, -1.00000000e+00,  0.00000000e+00],
       [ 1.00000000e+00,  2.22044605e-16,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])

可以使用 * 运算符组合多个旋转

>>> r1 = R.from_euler('z', 90, degrees=True)
>>> r2 = R.from_rotvec([np.pi/4, 0, 0])
>>> v = [1, 2, 3]
>>> r2.apply(r1.apply(v))
array([-2.        , -1.41421356,  2.82842712])
>>> r3 = r2 * r1 # Note the order
>>> r3.apply(v)
array([-2.        , -1.41421356,  2.82842712])

可以使用 ** 运算符将旋转与其自身组合

>>> p = R.from_rotvec([1, 0, 0])
>>> q = p ** 2
>>> q.as_rotvec()
array([2., 0., 0.])

最后,也可以对旋转求逆

>>> r1 = R.from_euler('z', [[90], [45]], degrees=True)
>>> r2 = r1.inv()
>>> r2.as_euler('zyx', degrees=True)
array([[-90.,   0.,   0.],
       [-45.,   0.,   0.]])

以下函数可用于通过显示旋转如何变换标准 x、y、z 坐标轴来使用 Matplotlib 绘制旋转

>>> import matplotlib.pyplot as plt
>>> def plot_rotated_axes(ax, r, name=None, offset=(0, 0, 0), scale=1):
...     colors = ("#FF6666", "#005533", "#1199EE")  # Colorblind-safe RGB
...     loc = np.array([offset, offset])
...     for i, (axis, c) in enumerate(zip((ax.xaxis, ax.yaxis, ax.zaxis),
...                                       colors)):
...         axlabel = axis.axis_name
...         axis.set_label_text(axlabel)
...         axis.label.set_color(c)
...         axis.line.set_color(c)
...         axis.set_tick_params(colors=c)
...         line = np.zeros((2, 3))
...         line[1, i] = scale
...         line_rot = r.apply(line)
...         line_plot = line_rot + loc
...         ax.plot(line_plot[:, 0], line_plot[:, 1], line_plot[:, 2], c)
...         text_loc = line[1]*1.2
...         text_loc_rot = r.apply(text_loc)
...         text_plot = text_loc_rot + loc[0]
...         ax.text(*text_plot, axlabel.upper(), color=c,
...                 va="center", ha="center")
...     ax.text(*offset, name, color="k", va="center", ha="center",
...             bbox={"fc": "w", "alpha": 0.8, "boxstyle": "circle"})

创建三个旋转 - 单位旋转以及使用内禀 (intrinsic) 和外禀 (extrinsic) 约定的两个欧拉旋转

>>> r0 = R.identity()
>>> r1 = R.from_euler("ZYX", [90, -30, 0], degrees=True)  # intrinsic
>>> r2 = R.from_euler("zyx", [90, -30, 0], degrees=True)  # extrinsic

将所有三个旋转添加到同一绘图中

>>> ax = plt.figure().add_subplot(projection="3d", proj_type="ortho")
>>> plot_rotated_axes(ax, r0, name="r0", offset=(0, 0, 0))
>>> plot_rotated_axes(ax, r1, name="r1", offset=(3, 0, 0))
>>> plot_rotated_axes(ax, r2, name="r2", offset=(6, 0, 0))
>>> _ = ax.annotate(
...     "r0: Identity Rotation\n"
...     "r1: Intrinsic Euler Rotation (ZYX)\n"
...     "r2: Extrinsic Euler Rotation (zyx)",
...     xy=(0.6, 0.7), xycoords="axes fraction", ha="left"
... )
>>> ax.set(xlim=(-1.25, 7.25), ylim=(-1.25, 1.25), zlim=(-1.25, 1.25))
>>> ax.set(xticks=range(-1, 8), yticks=[-1, 0, 1], zticks=[-1, 0, 1])
>>> ax.set_aspect("equal", adjustable="box")
>>> ax.figure.set_size_inches(6, 5)
>>> plt.tight_layout()

显示绘图

>>> plt.show()
../../_images/scipy-spatial-transform-Rotation-1_00_00.png

这些示例概述了 Rotation 类并突出了主要功能。有关支持的输入和输出格式范围的更详尽示例,请查阅各个方法的示例。