草庐IT

旋转矩阵和欧拉角

lyyiangang 2024-12-13 原文

欧拉角介绍

旋转可以参考两种坐标系,内部坐标系(XYZ), 角度 α, β, γ.
外部坐标系(xyz), 角度 ψ, θ, φ.
不考虑参考坐标系情况下, 按照旋转方式可以分为两种:

  • Proper Euler angles
    (z-x-z, x-y-x, y-z-y, z-y-z, x-z-x, y-x-y)

  • Tait–Bryan angles
    (x-y-z, y-z-x, z-x-y, x-z-y, z-y-x, y-x-z).
    与proper方式相比, Tait方式旋转会用上所有坐标轴.
    我们常说的欧拉角指的都是Tait-Bryan angles.

  • 旋转矩阵与欧拉角转换参考Computing Euler angles from a rotation matrix

    维基百科给的公式:

  • 旋转矩阵转换为欧拉角(Tait-Bryan angles)参考代码

#Ref: https://www.learnopencv.com/rotation-matrix-to-euler-angles/
def isRotationMatrix(R):
    ''' checks if a matrix is a valid rotation matrix(whether orthogonal or not)
    '''
    Rt = np.transpose(R)
    shouldBeIdentity = np.dot(Rt, R)
    I = np.identity(3, dtype = R.dtype)
    n = np.linalg.norm(I - shouldBeIdentity)
    return n < 1e-6

def matrix2angle(R):
    ''' get three Euler angles from Rotation Matrix
    Args:
        R: (3,3). rotation matrix
    Returns:
        x: pitch
        y: yaw
        z: roll
    '''
    assert(isRotationMatrix)
    sy = math.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])
     
    singular = sy < 1e-6
 
    if  not singular :
        x = math.atan2(R[2,1] , R[2,2])
        y = math.atan2(-R[2,0], sy)
        z = math.atan2(R[1,0], R[0,0])
    else :
        x = math.atan2(-R[1,2], R[1,1])
        y = math.atan2(-R[2,0], sy)
        z = 0

    # rx, ry, rz = np.rad2deg(x), np.rad2deg(y), np.rad2deg(z)
    rx, ry, rz = x*180/np.pi, y*180/np.pi, z*180/np.pi
    return rx, ry, rz

参考:
rotations_in_3d_part1.html

坐标系旋转

首先坐标系的旋转和点的旋转是相反的. 这里先讨论下坐标系的旋转.
假设在xoy坐标系下有个点p, 那么这个点在sot坐标系下的坐标是多少呢?
这里先假设xoy坐标系下点坐标为X,sot坐标系下点坐标为X’, 这里先假设他们应该有如下关系: R X ′ = X RX'=X RX=X,其中 R = [ s ⃗ , t ⃗ ] R=[\vec{s}, \vec{t}] R=[s ,t ] .
现在开始证明为什么R可以用s和t这么表示. 直观上可以知道, 如果 X ′ = [ 1 , 0 , 0 ] T X'=[1, 0, 0]^T X=[1,0,0]T, 那么就可以取出R的第一列也就是 s ⃗ \vec{s} s , 所以可以反推出R的表示形式.
从上图不难看出, s ⃗ = [ c o s ( θ ) , s i n ( θ ) ] T \vec{s}=[cos(\theta), sin(\theta)]^T s =[cos(θ),sin(θ)]T , t ⃗ = [ − s i n ( θ ) , c o s ( θ ) ] T \vec{t}=[-sin(\theta),cos(\theta)]^T t =[sin(θ),cos(θ)]T, 所以旋转矩阵表示为:
R = [ s ⃗ , t ⃗ ] = [ c o s ( θ ) − s i n ( θ ) s i n ( θ ) c o s ( θ ) ] R=[\vec{s}, \vec{t}]=\begin{bmatrix} cos(\theta) & -sin(\theta) \\ sin(\theta) & cos(\theta) \end{bmatrix} R=[s ,t ]=[cos(θ)sin(θ)sin(θ)cos(θ)]
另一方面可以这么理解, 我们知道一个点是可以通过坐标系的基空间表示的.常见的表示方法:

对与sot坐标系则有:
o p ⃗ = [ s s , t t ] T \vec{op}=[ss, tt]^T op =[ss,tt]T , 而基向量st又是用xoy坐标系表示的, 所以, 矩阵 [ s ⃗ , t ⃗ ] [\vec{s}, \vec{t}] [s ,t ]有了将sot坐标系点转到xoy坐标系点的能力.
opengl中有个lookat函数, 能够将世界坐标系的点转换为相机坐标系下,可以注意下里面的R.

def lookat_camera(vertices, eye, at = None, up = None):
    """ 'look at' transformation: from world space to camera space
    standard camera space: 
        camera located at the origin. 
        looking down negative z-axis. 
        vertical vector is y-axis.
    Xcam = R(X - C)
    Homo: [[R, -RC], [0, 1]]
    Args:
      vertices: [nver, 3] 
      eye: [3,] the XYZ world space position of the camera.
      at: [3,] a position along the center of the camera's gaze.
      up: [3,] up direction 
    Returns:
      transformed_vertices: [nver, 3]
    """
    if at is None:
      at = np.array([0, 0, 0], np.float32)
    if up is None:
      up = np.array([0, 1, 0], np.float32)

    eye = np.array(eye).astype(np.float32)
    at = np.array(at).astype(np.float32)
    z_aixs = -normalize(at - eye) # look forward
    x_aixs = normalize(np.cross(up, z_aixs)) # look right
    y_axis = np.cross(z_aixs, x_aixs) # look up
    R = np.stack((x_aixs, y_axis, z_aixs))#, axis = 0) # 3 x 3
    transformed_vertices = vertices - eye # translation
    transformed_vertices = transformed_vertices.dot(R.T) # rotation
    return transformed_vertices

但是如果是旋转点, 假如旋转后点的坐标X’与旋转前X有如下关系:
R X ′ = X RX'=X RX=X
那么, 这个R矩阵则为:
R = [ s ⃗ , t ⃗ ] = [ c o s ( θ ) s i n ( θ ) − s i n ( θ ) c o s ( θ ) ] R=[\vec{s}, \vec{t}]=\begin{bmatrix} cos(\theta) & sin(\theta) \\ -sin(\theta) & cos(\theta) \end{bmatrix} R=[s ,t ]=[cos(θ)sin(θ)sin(θ)cos(θ)]

台大机器人学之运动学-林沛群对旋转的介绍

旋转矩阵转为欧拉角时有两种方式,该视频将欧拉角分为Fixed AngelsEular angels.

  • Fixed angles(先做的旋转放后面, 参考外部坐标系)
    旋转时参考坐标系为一个固定坐标系( X A , Y A , Z A X_A,Y_A,Z_A XA,YA,ZA),


其中 R B A R^A_B RBA代表从B到A的旋转,上图沿着X-Y-Z顺序做的旋转,所以旋转矩阵定义为:
R Z R Y R X R_ZR_YR_X RZRYRX,先做的旋转放后面, 假如有点 P a P_a Pa, 那么可以通过公式 P b = R Z R Y R X P a P_b=R_ZR_YR_XP_a Pb=RZRYRXPa将点p从a转到b坐标系。

  • Eular Angles(先做的旋转放前面, 参考内部坐标系)
    Euler Angels指的是每次旋转参考的都是自身坐标系。这里以ZYX旋转顺序为例,可以看出 R B A R^A_B RBA的构成是先做的旋转放前面。

    其实两种旋转方式调换顺序可以表示同一种旋转。

代码实现

可以使用scipy库中的Rotation 模块来做欧拉角到matrix的转换.
小写字母xyz代码参考坐标系为外部坐标系, 大写则为内部坐标系.

  • 外部坐标系的转换测试
from scipy.spatial.transform import Rotation
import numpy as np
mat_x = Rotation.from_euler('x', 30, degrees = True).as_matrix()
mat_y = Rotation.from_euler('y', 40, degrees = True).as_matrix()
mat_z = Rotation.from_euler('z', 50, degrees = True).as_matrix()
my_rot_mat = mat_z @ mat_y @ mat_x
print(my_rot_mat)

mat_gt = Rotation.from_euler('xyz', [30, 40, 50], degrees = True).as_matrix()
print(mat_gt)

打印结果:

[[ 0.49240388 -0.45682599  0.74084306]
 [ 0.58682409  0.80287234  0.10504046]
 [-0.64278761  0.38302222  0.66341395]]
 
[[ 0.49240388 -0.45682599  0.74084306]
 [ 0.58682409  0.80287234  0.10504046]
 [-0.64278761  0.38302222  0.66341395]]

可以看出from_eular(‘xyz’)指的是先做x,后做y,最后z的变换, 对应矩阵上的操作就是mat_z @ mat_y @ mat_x

  • 内部坐标系的转换测试
    mat_x = Rotation.from_euler('X', 30, degrees = True).as_matrix()
    mat_y = Rotation.from_euler('Y', 40, degrees = True).as_matrix()
    mat_z = Rotation.from_euler('Z', 50, degrees = True).as_matrix()
    my_rot_mat =  mat_x @ mat_y @ mat_z
    print(my_rot_mat)

    mat_gt = Rotation.from_euler('XYZ', [30, 40, 50], degrees = True).as_matrix()
    print(mat_gt)

打印:

[[ 0.49240388 -0.58682409  0.64278761]
 [ 0.8700019   0.31046846 -0.38302222]
 [ 0.02520139  0.74782807  0.66341395]]
 
[[ 0.49240388 -0.58682409  0.64278761]
 [ 0.8700019   0.31046846 -0.38302222]
 [ 0.02520139  0.74782807  0.66341395]]

也就印证了前面台大机器人学之运动学对而这转换的介绍.
总结下就是, 旋转参考坐标系为固定的外部坐标系时, 我们说的xyz旋转a,b,c度, 那么这个旋转矩阵就是: RzRyRz.如果参考坐标系为自身坐标系时, 这个旋转矩阵就是 RxRyRz.

有关旋转矩阵和欧拉角的更多相关文章

  1. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  2. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  3. 华为OD机试真题 C++ 实现【带传送阵的矩阵游离】【2023 Q2 | 200分】 - 2

            所有题目均有五种语言实现。C实现目录、C++实现目录、Python实现目录、Java实现目录、JavaScript实现目录题目n行m列的矩阵,每个位置上有一个元素你可以上下左右行走,代价是前后两个位置元素值差的绝对值.另外,你最多可以使用一次传送阵(只能从一个数跳到另外一个相同的数)求从走上角走到右下角最少需要多少时间。输入描述:第一行两个整数n,m,分别代表矩阵的行和列。后面n行,每行m个整数,分别代表矩阵中的元素。输出描述:一个整数,表示最少需要多少时间。

  4. 欧拉角表示的姿态矩阵(313和312转序) - 2

    一、习惯约定图片来自PSINS(高精度捷联惯导算法)PSINS工具箱入门与详解.pptx二、基本旋转矩阵绕x轴逆时钟旋转α\alphaα角度Rx(α)=[ 1000cos⁡αsin⁡α0−sin⁡αcos⁡α]R_x(\alpha)=\begin{bmatrix}\1&0&0\\0&\cos\alpha&\sin\alpha\\0&-\sin\alpha&\cos\alpha\end{bmatrix}Rx​(α)=​ 100​0cosα−sinα​0sinαcosα​​绕y轴逆时钟旋转α\alphaα角度Ry(α)=[ cos⁡α0−sin⁡α010sin⁡α0cos⁡α]R_y(\alpha

  5. 欧拉角、旋转矩阵及四元数 - 2

    欧拉角、旋转矩阵及四元数1.简介2.欧拉角2.1欧拉角定义2.2右手系和左手系2.3转换流程3.旋转矩阵4.四元数4.1四元数与欧拉角和旋转矩阵之间等效变换4.2测试Matlab代码5.总结1.简介常用姿态参数表达方式包括方向余弦矩阵、欧拉轴/角参数、欧拉角、四元数以及罗德里格参数等。高分辨率光学遥感卫星主要采用欧拉角与四元数对姿态参数进行描述。这里着重讲解欧拉角、旋转矩阵和四元数。2.欧拉角2.1欧拉角定义欧拉角是表征刚体旋转的一种方法之一,由莱昂哈德·欧拉引入的三个角度,用于描述刚体相对于固定坐标系的方向。在摄影测量、空间科学或其它技术领域,一般用一组(三个)欧拉角描述两个空间坐标之间的旋

  6. ruby - 如何修改矩阵(Ruby std-lib Matrix 类)? - 2

    我理解RubystdlibMatrix是不可修改的,也就是说,例如。m=Matrix.zero(3,4)不会写m[0,1]=7但我非常想做...我可以用笨拙的编程来做,比如defmodify_value_in_a_matrix(matrix,row,col,newval)ary=(0...m.row_size).map{|i|m.rowi}.map(&:to_a)ary[row][col]=newvalMatrix[*ary]end...或者作弊,比如Matrix.send:[]=,0,1,7但我想知道,这一定是人们一直遇到的问题。有没有一些标准的、习惯的方法可以做到这一点,而不必使用

  7. 欧拉系统安装与部署NextCloud及数据迁移 - 2

    欧拉系统部署NextCloud与常见部署问题解决以及数据盘迁移一、欧拉系统安装二、openEuler安装图形界面Ukui三、yum安装的npm包进行本地保存设置(个人任务需要)四、部署nextCloud4.1构建LAMP环境基础4.1.1开启httpd,防火墙端口号4.1.2开启MariaDB服务4.1.3安装并测试php4.2下载安装nextCloud4.2.1创建nextCloud数据库,存放网盘文件索引与用户信息4.2.2拷贝NextCloud并创建data目录,目录赋予权限五、离线npm包方式部署NextCloud(个人需要,正常联网状态搭建LAMP环境后,拷贝NextCloud安装即

  8. 线性代数让我想想:快速求三阶矩阵的逆矩阵 - 2

    快速求三阶矩阵的逆矩阵前言一般情况下,我们求解伴随矩阵是要注意符号问题和位置问题的(如下所示)A−1=1[  ][−[  ]−[  ]−[  ]  −[  ]]=A−1=1[  ][   M11−[M12]   M13−[M21]   M22−[M23]     M31−[M32]   M33]⊤\begin{aligned}&A^{-1}=\frac{1}{[\\]}\left[\begin{array}{cccccc}&-[\\]&\\-[\\]&&-[\\]\\\\&-[\\]&\\\end{array}\right]=\\\\&A^{-1}=\frac{1}{[\\]}\left[\b

  9. 相机校准—外参矩阵 - 2

    在本文中,我们将探讨摄影机的外参,并通过Python中的一个实践示例来加强我们的理解。相机外参摄像头可以位于世界任何地方,并且可以指向任何方向。我们想从摄像机的角度来观察世界上的物体,这种从世界坐标系到摄像机坐标系的转换被称为摄像机外参。那么,我们怎样才能找到相机外参呢?一旦我们弄清楚相机是如何变换的,我们就可以找到从世界坐标系到相机坐标系的基变换的变化。我们将详细探讨这个想法。具体来说,我们需要知道相机是如何定位的,以及它在世界空间中的位置,有两种转换可以帮助我们:有助于确定摄影机方向的旋转变换。有助于移动相机的平移变换。让我们详细看看每一个。旋转通过旋转改变坐标让我们看一下将点旋转一个角度

  10. ruby - 欧拉计划 1 :Find the sum of all the multiples of 3 or 5 below 1000 - 2

    我正在尝试使用ProjectEuler中的Ruby解决数学问题。Here是我尝试的第一个:Ifwelistallthenaturalnumbersbelow10thataremultiplesof3or5,weget3,5,6and9.Thesumofthesemultiplesis23.Findthesumofallthemultiplesof3or5below1000.请帮助我改进我的代码。total=0(0...1000).eachdo|i|total+=iif(i%3==0||i%5==0)endputstotal 最佳答案

随机推荐