来自两个 3D 点的欧拉角和旋转矩阵
Euler Angles and Rotation Matrix from two 3D points
我正在尝试找到允许在 3D space.
中从点 A
到点 B
的变换的欧拉角
考虑归一化向量 A = [1, 0, 0]
和 B = [0.32 0.88 -0.34]
。
我知道通过计算 叉积 A × B
我得到了旋转轴。 A
和 B
之间的 角度 由 tan⁻¹(||cross||, A·B)
给出,其中 A·B
是 点积 在 A
和 B
之间。
这给了我旋转向量 rotvec = [0 0.36 0.93 1.24359531111]
,它是 rotvec = [A × B; angle]
(叉积已归一化)。
现在我的问题是:我如何从这里移动以获得对应于从 A
到 B
的变换的欧拉角?
在 MATLAB 中,函数 vrrotvec2mat receives as input a rotation vector and outputs a rotation matrix. Then the function rotm2eul 应该 return 对应的欧拉角。根据 XYZ
约定,我得到以下结果(以弧度表示):[0.2456 0.3490 1.2216]
。然而,这并不是预期的结果。
正确答案是[0 0.3490 1.2216]
,分别对应Y
和Z
中20°
和70°
的轮换。
当我使用eul2rot([0 0.3490 1.2216])
(eul2rot
取自here)验证生成的旋转矩阵时,这个与我使用[=35=时得到的不同].
我还有一个 Python spinet 可以产生与上述完全相同的结果。
--- Python (2.7) 使用 transform3d ---
import numpy as np
import transforms3d
cross = np.cross(A, B)
dot = np.dot(A, B.transpose())
angle = math.atan2(np.linalg.norm(cross), dot)
rotation_axes = sklearn.preprocessing.normalize(cross)
rotation_m = transforms3d.axangles.axangle2mat(rotation_axes[0], angle, True)
rotation_angles = transforms3d.euler.mat2euler(rotation_m, 'sxyz')
我在这里缺少什么?我应该怎么做?
谢谢
旋转矩阵有 3 个自由度,但你的问题的约束只限制了其中的 2 个自由度。
考虑到我们有一个旋转矩阵 R
从 A
旋转到 B
所以 R*A == B
的情况,这可以变得更具体。如果我们然后构造另一个围绕向量 B
旋转的旋转矩阵 RB
,那么将此旋转应用于 R*A
将不会有任何效果,即 B == R*A == RB*R*A
。但是,它将产生具有不同欧拉角的不同旋转矩阵 RB*R
。
这是 MATLAB 中的示例:
A = [1; 0; 0];
B = [0.32; 0.88; -0.34];
A = A / norm(A);
B = B / norm(B);
ax = cross(A, B);
ang = atan2(norm(ax), dot(A, B)); % ang = acos(dot(A, B)) works too
R = axang2rotm([ax; ang].');
ang_arbitrary = rand()*2*pi;
RB = axang2rotm([B; ang_arbitrary].');
R*A - B
RB*R*A - B
rotm2eul(R)
rotm2eul(RB*R)
结果
ans =
1.0e-15 *
-0.0555
0.1110
0
ans =
1.0e-15 *
0.2220
0.7772
-0.2776
ans =
1.2220 0.3483 0.2452
ans =
1.2220 0.3483 0.7549
我会根据Euler's rotation theorem给你一个解决方案。
这个解法只给了你一个角度,其他的角度都可以推导出来。
import numpy as np
a_vec = np.array([1, 0, 0])/np.linalg.norm(np.array([1, 0, 0]))
b_vec = np.array([0.32, 0.88, -0.34])/np.linalg.norm(np.array([0.32, 0.88, -0.34]))
cross = np.cross(a_vec, b_vec)
ab_angle = np.arccos(np.dot(a_vec,b_vec))
vx = np.array([[0,-cross[2],cross[1]],[cross[2],0,-cross[0]],[-cross[1],cross[0],0]])
R = np.identity(3)*np.cos(ab_angle) + (1-np.cos(ab_angle))*np.outer(cross,cross) + np.sin(ab_angle)*vx
validation=np.matmul(R,a_vec)
这使用公共旋转轴(本例中为特征向量)作为叉积。
矩阵R就是rotation matrix.
这是一般的做法,非常简单。
我正在尝试找到允许在 3D space.
中从点A
到点 B
的变换的欧拉角
考虑归一化向量 A = [1, 0, 0]
和 B = [0.32 0.88 -0.34]
。
我知道通过计算 叉积 A × B
我得到了旋转轴。 A
和 B
之间的 角度 由 tan⁻¹(||cross||, A·B)
给出,其中 A·B
是 点积 在 A
和 B
之间。
这给了我旋转向量 rotvec = [0 0.36 0.93 1.24359531111]
,它是 rotvec = [A × B; angle]
(叉积已归一化)。
现在我的问题是:我如何从这里移动以获得对应于从 A
到 B
的变换的欧拉角?
在 MATLAB 中,函数 vrrotvec2mat receives as input a rotation vector and outputs a rotation matrix. Then the function rotm2eul 应该 return 对应的欧拉角。根据 XYZ
约定,我得到以下结果(以弧度表示):[0.2456 0.3490 1.2216]
。然而,这并不是预期的结果。
正确答案是[0 0.3490 1.2216]
,分别对应Y
和Z
中20°
和70°
的轮换。
当我使用eul2rot([0 0.3490 1.2216])
(eul2rot
取自here)验证生成的旋转矩阵时,这个与我使用[=35=时得到的不同].
我还有一个 Python spinet 可以产生与上述完全相同的结果。
--- Python (2.7) 使用 transform3d ---
import numpy as np
import transforms3d
cross = np.cross(A, B)
dot = np.dot(A, B.transpose())
angle = math.atan2(np.linalg.norm(cross), dot)
rotation_axes = sklearn.preprocessing.normalize(cross)
rotation_m = transforms3d.axangles.axangle2mat(rotation_axes[0], angle, True)
rotation_angles = transforms3d.euler.mat2euler(rotation_m, 'sxyz')
我在这里缺少什么?我应该怎么做?
谢谢
旋转矩阵有 3 个自由度,但你的问题的约束只限制了其中的 2 个自由度。
考虑到我们有一个旋转矩阵 R
从 A
旋转到 B
所以 R*A == B
的情况,这可以变得更具体。如果我们然后构造另一个围绕向量 B
旋转的旋转矩阵 RB
,那么将此旋转应用于 R*A
将不会有任何效果,即 B == R*A == RB*R*A
。但是,它将产生具有不同欧拉角的不同旋转矩阵 RB*R
。
这是 MATLAB 中的示例:
A = [1; 0; 0];
B = [0.32; 0.88; -0.34];
A = A / norm(A);
B = B / norm(B);
ax = cross(A, B);
ang = atan2(norm(ax), dot(A, B)); % ang = acos(dot(A, B)) works too
R = axang2rotm([ax; ang].');
ang_arbitrary = rand()*2*pi;
RB = axang2rotm([B; ang_arbitrary].');
R*A - B
RB*R*A - B
rotm2eul(R)
rotm2eul(RB*R)
结果
ans =
1.0e-15 *
-0.0555
0.1110
0
ans =
1.0e-15 *
0.2220
0.7772
-0.2776
ans =
1.2220 0.3483 0.2452
ans =
1.2220 0.3483 0.7549
我会根据Euler's rotation theorem给你一个解决方案。
这个解法只给了你一个角度,其他的角度都可以推导出来。
import numpy as np
a_vec = np.array([1, 0, 0])/np.linalg.norm(np.array([1, 0, 0]))
b_vec = np.array([0.32, 0.88, -0.34])/np.linalg.norm(np.array([0.32, 0.88, -0.34]))
cross = np.cross(a_vec, b_vec)
ab_angle = np.arccos(np.dot(a_vec,b_vec))
vx = np.array([[0,-cross[2],cross[1]],[cross[2],0,-cross[0]],[-cross[1],cross[0],0]])
R = np.identity(3)*np.cos(ab_angle) + (1-np.cos(ab_angle))*np.outer(cross,cross) + np.sin(ab_angle)*vx
validation=np.matmul(R,a_vec)
这使用公共旋转轴(本例中为特征向量)作为叉积。
矩阵R就是rotation matrix.
这是一般的做法,非常简单。