我可能有点晚了,zabop 的回答已经指向了正确的方向。我只想澄清两件事。
当我们使用可能使事情变得更加混乱的转换时,有几个模棱两可。可能使这里的代码有点混乱的两件事是:
我从你上面的例子开始:
import numpy as np
r_0 = np.array([[-0.02659679, -0.00281247, 0.99964229],
[ 0.76308514, -0.64603356, 0.01848528],
[ 0.64575048, 0.76330382, 0.01932857]])
r_1 = np.array([[ 0.05114056, -0.03815443, 0.99796237],
[-0.30594799, 0.95062582, 0.05202294],
[-0.95067369, -0.30798506, 0.03694226]])
我计算旋转r_0到的旋转矩阵r_1的方式如下(与您的代码不同!):
r0_to_r1 = r_1.dot(r_0.T)
r0_to_r1
结果:
array([[ 0.99635252, 0.08212126, 0.0231898 ],
[ 0.05746796, -0.84663889, 0.52905579],
[ 0.06308011, -0.52579339, -0.84827012]])
我使用外部约定来连接旋转矩阵,即r_1在r_0.T. (如果r_0和r_1是实数,我们将编写r_1 - r_0以获得一个转换r_0为的数字r_1。)
您可以验证从到r0_to_r1旋转:r_0r_1
from numpy.testing import assert_array_almost_equal
# verify correctness: apply r0_to_r1 after r_0
assert_array_almost_equal(r_1, r0_to_r1.dot(r_0))
# would raise an error if test fails
无论如何,内在约定也可以工作:
r0_to_r1_intrinsic = r_0.T.dot(r_1)
assert_array_almost_equal(r_1, r_0.dot(r0_to_r1_intrinsic))
由于zabop引入了pytransform3d,我还要澄清一下scipy使用主动旋转矩阵,而pytransform3d.rotations.euler_xyz_from_matrix产生的旋转矩阵是被动旋转矩阵!这在以前的版本中没有如此清楚地记录。您可以使用矩阵转置将主动旋转矩阵转换为被动旋转矩阵,反之亦然。pytransform3d 的函数和 scipy 都Rotation.to_euler("xyz", ...)使用内部连接约定。
from scipy.spatial.transform import Rotation as R
r = R.from_matrix(r0_to_r1)
euler_xyz_intrinsic_active_degrees = r.as_euler('xyz', degrees=True)
euler_xyz_intrinsic_active_degrees
结果:array([-148.20762964, -3.6166255 , 3.30106818])
您可以使用 pytransform3d 获得相同的结果(请注意,我们通过 获得被动旋转矩阵.T):
import pytransform3d.rotations as pr
euler_xyz_intrinsic_active_radians = pr.euler_xyz_from_matrix(r0_to_r1.T)
np.rad2deg(euler_xyz_intrinsic_active_radians)
结果:array([-148.20762951, -3.61662542, 3.30106799])
您还可以使用 pytransform3d 从欧拉角获取旋转矩阵(请注意,我们通过 获取活动旋转矩阵.T):
r0_to_r1_from_euler = pr.matrix_from_euler_xyz(euler_xyz_intrinsic_active_radians).T
r0_to_r1_from_euler
结果:
array([[ 0.99635251, 0.08212125, 0.0231898 ],
[ 0.05746796, -0.84663889, 0.52905579],
[ 0.06308011, -0.52579339, -0.84827013]])