You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

欧拉角与四元数双向转换结果不一致的问题求助

欧拉角与四元数双向转换结果不一致的问题求助

大家好,我最近在调试代码时碰到了个头疼的问题:把欧拉角转成四元数再转回欧拉角,结果和原始的欧拉角对不上,有没有大佬能帮我看看咋解决呀?

下面是我的测试代码:

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

# Define test rotation in degrees
testrotation = np.zeros([2, 2, 3])
testrotation[0, 0] = [45, 30, 60]
testrotation[0, 1] = [10, 20, 30]
testrotation[1, 0] = [90, 0, 45]
testrotation[1, 1] = [90, 45, 30]

#################### Euler -> Quaternions using SciPy
scipy_quaternions_temp = R.from_euler("ZYX", np.radians(testrotation.reshape(-1, 3)))
scipy_quaternions = np.roll(scipy_quaternions_temp.as_quat(), shift=1, axis=-1).reshape(testrotation.shape[0], testrotation.shape[1], 4)

print("Quaternions (wxyz format):\n", scipy_quaternions, "\n")

#################### Quaternions -> Euler using SciPy
scipy_euler_angles = np.rad2deg(scipy_quaternions_temp.as_euler('zyx', degrees=False)).reshape(testrotation.shape[0], testrotation.shape[1], 3)

print("Euler angles after conversion and normalization:\n", scipy_euler_angles, "\n")

#################### Euler -> Quaternions (back conversion) using SciPy
scipy_quat_reconverted = R.from_euler('zyx', np.radians(scipy_euler_angles.reshape(-1, 3))).as_quat().reshape(testrotation.shape[0], testrotation.shape[1], 4)
scipy_quat_reconverted = np.roll(scipy_quat_reconverted, shift=1, axis=-1)

print("Reconverted quaternions (wxyz format):\n", scipy_quat_reconverted, "\n")
sys.exit()

运行后输出的结果里,转回的欧拉角和原始值明显不一样:

Quaternions (wxyz format):
 [[[ 0.82236317  0.36042341  0.39190384  0.20056212]
  [ 0.95154852  0.23929834  0.18930786  0.03813458]]

 [[ 0.65328148  0.27059805  0.27059805  0.65328148]
  [ 0.70105738 -0.09229596  0.43045933  0.56098553]]] 

Euler angles after conversion and normalization:
 [[[ 4.42303689e+00  5.21060674e+01  4.51703838e+01]
  [-1.11605468e+00  2.22421809e+01  2.84517753e+01]]

 [[ 9.00000000e+01  4.50000000e+01  1.27222187e-14]
  [ 9.00000000e+01  3.00000000e+01 -4.50000000e+01]]] 

Reconverted quaternions (wxyz format):
 [[[ 0.82236317  0.36042341  0.39190384  0.20056212]
  [ 0.95154852  0.23929834  0.18930786  0.03813458]]

 [[ 0.65328148  0.27059805  0.27059805  0.65328148]
  [ 0.70105738 -0.09229596  0.43045933  0.56098553]]]

不过奇怪的是,把转回的欧拉角再转成四元数,结果又和第一次的四元数完全一致,这说明旋转本身是对的,但欧拉角的数值为啥不一样呢?


问题解析与解决思路

嗨,这个问题我之前也踩过坑!核心原因其实是欧拉角的表示不唯一——同一个旋转状态可以对应多组不同的欧拉角,而SciPy在把四元数转回欧拉角时,会自动将角度归一化到行业通用的标准范围内,你的原始欧拉角可能不在这个范围内,或者存在等价的角度组合。

咱们具体拆解一下:

  1. 欧拉角的多义性:比如绕Z轴转90°+绕Y轴转45°+绕X轴转0°,和绕Z轴转90°+Y轴转45°+X轴转360°是完全相同的旋转,但欧拉角数值不一样。另外当中间旋转轴(比如ZYX顺序里的Y轴)角度接近±90°时,还会出现万向锁,这时候另外两个轴的角度可以有无数种组合表示同一个旋转。
  2. SciPy的归一化规则:as_euler方法默认会把欧拉角调整到标准区间,以ZYX顺序为例:
    • Z轴角度:[-180°, 180°]
    • Y轴角度:[-90°, 90°]
    • X轴角度:[-180°, 180°]

看你的输出,比如第三组原始欧拉角[90, 0, 45]转回后变成了[90, 45, ~0],这其实是同一个旋转的不同欧拉角表示——当Y轴角度为0时,Z轴和X轴的旋转顺序可以交换,组合出等价的旋转效果。

验证旋转一致性的方法

如果想确认旋转本身是正确的,可以对比两次旋转对同一个向量的变换结果:

# 取一个测试向量
vec = np.array([1, 0, 0])
# 原始欧拉角对应的旋转
rot_original = R.from_euler("ZYX", np.radians(testrotation[1,0]))
# 转回的欧拉角对应的旋转
rot_reconverted = R.from_euler("ZYX", np.radians(scipy_euler_angles[1,0]))
# 对比变换后的向量
print("Original transformed vec:", rot_original.apply(vec))
print("Reconverted transformed vec:", rot_reconverted.apply(vec))

运行后会发现两个向量几乎完全一致(误差是浮点计算导致的),这就说明转换是正确的。

如何让转回的欧拉角和原始值一致?

如果业务场景必须让转回的欧拉角和原始数值一致,你需要自定义角度的归一化逻辑:比如对SciPy返回的角度加上/减去360°的整数倍,或者针对万向锁场景做特殊处理,但这需要结合你的具体应用场景来实现。

总结一下:

  • 四元数转回欧拉角出现数值差异是正常现象,根源是欧拉角的表示不唯一
  • 只要旋转对向量的变换结果一致,就说明转换逻辑没有问题
  • 若需要和原始欧拉角数值完全匹配,需自定义角度归一化规则

备注:内容来源于stack exchange,提问作者Kong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:28:07