基于python的李代数实现方法

本文介绍了如何在Python中通过pySophus库操作李代数,重点讲解了so3类的源码解析,并新增了李代数到四元数的转换方法。适合SLAM开发者和对李群李代数感兴趣的读者。
该文章已生成可运行项目,


前言

有好久没更新博客,比较惭愧,这次索性给出一个深入一点的文章——在python中实现李代数。

一、李代数是什么?

简而言之,李代数可以用来描述物体在某个参考系下的状态(姿态或者位姿),可以用一个多维(三维或者六维)矢量来表示。说到李代数,就不得不提到李群,每个李群都有与之对应的李代数。懂的人都懂,我就不详细阐述了,对于做slam的人,这都是基础知识。
在此祭出《视觉slam十四讲》中的一个关系图:
李群和李代数的对应关系
在C++中有专用的sophus库,可以非常方便地调用李代数。在python中,该如何使用李代数呢?笔者在github上搜到了一个开源库,基于numpy定义了李代数,且实现了与李群的转换,使用非常方便,因此在此贡献出来。
https://github.com/franciscodominguezmateos/pySophus

二、源码解析

以旋转矩阵对应的李代数so3为例:

代码如下:

class so3(Algebra):
    """3D rotation Lie algebra"""
    G1 = np.matrix([[0, 0, 0],
                    [0, 0, -1],
                    [0, 1, 0]])
    G2 = np.matrix([[0, 0, 1],
                    [0, 0, 0],
                    [-1, 0, 0]])
    G3 = np.matrix([[0, -1, 0],
                    [1, 0, 0],
                    [0, 0, 0]])

    def __init__(self, **kwargs):
        """Algebra element constructor
        :param kwargs: must be `matrix = ndarray` with dimensions 3x3 or `vector = ndarray` with dimensions 1x3
        :type kwargs
        :raises TypeError, if the needed argument (matrix or vector) is not given
        """
        if "vector" in kwargs:
            self.w = kwargs["vector"]
        elif "matrix" in kwargs:
            m = kwargs["matrix"]
            self.w = np.array([0, 0, 0])
            self.w[0] = m[2, 1]
            self.w[1] = m[0, 2]
            self.w[2] = m[1, 0]
        else:
            raise TypeError("Argument must be matrix or vector")

    def __add__(self, other):
        """Returns the algebra element for the equivalent rotation as applying the given ones one after the other
        :param other: element to add this element to
        :type other: so3
        :return: equivalent algebra element
        :rtype: so3
        """
        R1 = self.exp()
        R2 = other.exp()
        R = R1 * R2
        return R.log()

    def magnitude(self):
        """Given the vector w=(wx,wy,wz) returns its norm, which is how many radians this rotation makes around the normalized vector
        :return: radians this rotation makes
        :rtype: float
        """
        return np.linalg.norm(self.w)

    def exp(self):
        """
        :return: group element associated with this algebra element
        :rtype: SO3
        """
        wx = self.matrix()
        theta = np.linalg.norm(self.w)
        cs = np.cos(theta)
        sn = np.sin(theta)
        I = np.eye(3)
        a = (sn / theta) if theta != 0 else 1
        b = ((1 - cs) / theta ** 2) if theta != 0 else 1 / 2.0
        R = I + a * wx + b * wx.dot(wx)
        return SO3(R)

    def vector(self):
        """
        :return: this algebra element represented as vector (1x3)
        :rtype: ndarray
        """
        return self.w

    def matrix(self):
        """
        :return: this algebra element represented as skew matrix (3x3)
        :rtype: ndarray
        """
        return so3.G1 * self.w[0] + so3.G2 * self.w[1] + so3.G3 * self.w[2]

1. __init__

定义了李代数so3的实现方式:vector或者matrix,分别表示可以通过一个三维向量或者其反对称矩阵来生成李代数。

2. __add__

两个so3相加,等于其对应的李群(exp)相乘,然后再变成李代数(log)。

3. magnitude

给出对应的旋转角度。

4. exp

将李代数变成对应的李群,即:旋转矩阵R。

5. vector

给出李代数的矢量形式。

6. matrix

给出李代数的反对称矩阵形式。

三、二次开发

该库并没有实现李代数或者李群与四元数的转换,在此笔者自己增加了该内容,如下所示:

    def quaternion(self):
        """
        :return:  this algebra element represented as quaternion (1x4)
        """
        theta = np.linalg.norm(self.w[:3])
        u = self.w[:3] / theta
        q = np.zeros(4)
        q[0] = np.cos(0.5 * theta)
        q[1] = u[0] * np.sin(0.5 * theta)
        q[2] = u[1] * np.sin(0.5 * theta)
        q[3] = u[2] * np.sin(0.5 * theta)
        return q

基于so3给出了其到四元数的转换。方法非常简单,利用旋转向量来定义四元数:
q = [ c o s θ 2 , n ⃗ s i n θ 2 ] q=[cos\frac{\theta}{2}, \vec n sin\frac{\theta}{2}] q=[cos2θ,n sin2θ]

总结

本文分享了一种在python中实现李代数的方法,源码简单明了,只依赖于numpy库,非常实用,也便于在次基础上做二次开发。

本文章已经生成可运行项目
### 群到代数的转换 对于从群到代数的转换,在数学上通常涉及到指数映射和对数映射的概念。这些概念可以应用于各种具体的群实例,比如旋转矩阵构成的特殊正交群 SO(3),或者平移加旋转组成的 SE(3)。 在 Python实现这一过程时,`scipy.spatial.transform.Rotation` 提供了一些方便的功能来处理三维空间中的旋转操作[^1]。然而,针对更广泛的群及其对应的代数之间的变换,则可能需要用到专门库如 `Lie` 或者手动编写相应的函数来进行计算。 下面给出一段简单的代码片段用于演示如何基于 Rodrigues' formula 将 SO(3) 的元素近似转化为其对应的小量生成元(即 so(3) 上的一个向量),这实际上是从群到代数的一种具体化: ```python import numpy as np from scipy.linalg import logm def rotation_matrix_to_so3(rot_mat): """ Convert a Rotation Matrix (SO(3)) into its corresponding element in the Lie Algebra so(3). Parameters: rot_mat : ndarray shape=(3, 3) The input rotation matrix. Returns: omega_vec : ndarray shape=(3,) Vector representation of an element from lie algebra so(3), representing axis-angle form. """ skew_symmetric = logm(rot_mat)[:3, :3] omega_vec = np.array([skew_symmetric[2, 1], skew_symmetric[0, 2], skew_symmetric[1, 0]]) return omega_vec / 2.0j * (-1) # Example usage with random valid rotation matrices generated via scipy if __name__ == "__main__": from scipy.spatial.transform import Rotation as R # Generate some example rotations represented by their DCMs r = R.random() dcm_example = r.as_matrix() print("Rotation Matrix:\n", dcm_example) result = rotation_matrix_to_so3(dcm_example).real print("\nCorresponding vector in so(3): ", result) ``` 上述代码展示了利用矩阵对数运算将给定的旋转矩阵转为相应于该位置处的速度矢量形式的过程。这里采用的是复数域下的定义方式以便更好地理解物理意义;实际应用中可根据需求调整输出格式。 值得注意的是,这段程序仅适用于特定类型的群——也就是三维欧式几何里的刚体运动所形成的那些子集。如果要扩展至其他种类的连续变换群体,则需依据具体情况设计不同的算法逻辑并选取合适的工具包支持。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值