Advertisement

视觉SLAM笔记(9) Eigen

阅读量:

Eigen 是一个高效的 C++ 开源线性代数库,广泛应用于视觉 SLAM 和计算机视觉领域。它通过模板类提供向量和矩阵操作,并支持多种基本运算如加减乘、转置及逆矩阵等。Eigen 的纯头文件设计使其实现简单且易于集成。例如,在 eigenMatrix.cpp 中展示了如何初始化 2x3 矩阵并进行输入输出操作;通过 matrix23 << 1, 2, 3, 4, 5, 6; 可以将数据直接注入矩阵中,并通过 cout << matrix23 << endl; 显示结果。此外,Eigen 还支持复杂的矩阵分解(如 QR 分解)以提高计算效率。其强大的功能使其成为现代工程和科学计算中的不可或缺工具。

视觉SLAM笔记(9) Eigen

开源线性代数工具包

模块概述

核心组件

向量与矩阵

内置数据类型

初始化方法

动态内存管理

输入处理

输出配置

元数据获取

向量化运算

算术运算支持

随机数值生成

转置处理

区域求和

  • 3. 编译
  • 4. 输出结果

1. 开源线性代数库

Eigen被视为一个高效的C++线性代数库资源

未被Eigen库成功包含的情况下,请按照以下指令运行相应的操作以完成Eigen库的安装过程。为了完成Eigen库的安装,请参考官方文档中的详细指导。

复制代码
    $ sudo apt-get install libeigen3-dev
    
    
      
    
    AI助手

相较于大多数库而言,Eigen 的独特之处在于

在使用时,只需引入 Eigen 的头文件即可 ,不需要链接它的库文件


2. 基本操作与运算

下面写一段代码 VSLAM_note/009/eigenMatrix.cpp ,实际练习一下 Eigen 的使用:


2.1. 向量和矩阵

在Eigen库中,所有的向量与矩阵均属于Eigen::Matrix模板类。其前三者分别为数据类型、行数与列数。创建一个大小为2×3的浮点数矩阵。

复制代码
    Eigen::Matrix<float, 2, 3> matrix_23;
    
    
      
    
    AI助手

2.2. 内置类型

然而,在Eigen框架中借助关键字 typedef 我们能够定义许多内置类型,在底层层次上其本质仍然是一个名为 Eigen::Matrix 的核心数据结构。举个例子来说,
Vector3d 这样的类型实际上等同于 Eigen::Matrix<double, 3, 1>
这正是三维向量的数学表示形式。

复制代码
    Eigen::Vector3d v_3d;
    
    
      
    
    AI助手

这是一样的

复制代码
    Eigen::Matrix<float,3,1> vd_3d;
    
    
      
    
    AI助手

2.3. 初始化

Matrix3d 实质上是 Eigen::Matrix<double, 3, 3>
初始化为零

复制代码
    Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero(); 
    
    
      
    
    AI助手

2.4. 动态大小

如果不确定矩阵大小,可以使用动态大小的矩阵

复制代码
    Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > matrix_dynamic;
    
    
      
    
    AI助手

更简单的

复制代码
    Eigen::MatrixXd matrix_x;
    
    
      
    
    AI助手

2.5. 输入数据

输入数据(初始化)

复制代码
    matrix_23 << 1, 2, 3, 4, 5, 6;
    
    
      
    
    AI助手

2.6. 输出数据

复制代码
    cout << matrix_23 << endl;
    
    // 1 2 3
    // 4 5 6
    
    
      
      
      
      
    
    AI助手

2.7. 访问矩阵中的元素

用()访问矩阵中的元素

复制代码
    for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++)
        cout << matrix_23(i, j) << "\t";
    cout << endl;
    }
    
    // 1	2	3	
    // 4	5	6
    
    
      
      
      
      
      
      
      
      
    
    AI助手

2.8. 矩阵和向量相乘

矩阵和向量相乘,实际上仍是矩阵和矩阵

复制代码
    v_3d << 3, 2, 1;
    vd_3d << 4, 5, 6;
    
    
      
      
    
    AI助手

但是在Eigen里不能混合两种不同类型的矩阵,像这样是错的

复制代码
    Eigen::Matrix<double, 2, 1> result_wrong_type = matrix_23 * v_3d;
    
    
      
    
    AI助手

应该显式转换

复制代码
    Eigen::Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;
    cout << result << endl;
    
    // 10
    // 28
    
    
      
      
      
      
      
    
    AI助手
复制代码
    Eigen::Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;
    cout << result2 << endl;
    
    // 32
    // 77
    
    
      
      
      
      
      
    
    AI助手

同样不能搞错矩阵的维度
如果这样就会报错

复制代码
    Eigen::Matrix<double, 2, 3> result_wrong_dimension = matrix_23.cast<double>() * v_3d;
    
    
      
    
    AI助手

2.9. 四则运算

直接用 + - * / 即可


2.10. 随机数矩阵

通过 Random() 产生随机数矩阵

复制代码
    matrix_33 = Eigen::Matrix3d::Random();
    cout << matrix_33 << endl << endl;
    
    //  0.680375   0.59688 -0.329554
    // -0.211234  0.823295  0.536459
    //  0.566198 -0.604897 -0.444451
    
    
      
      
      
      
      
      
    
    AI助手

2.11. 转置

通过transpose() 进行转置

复制代码
    cout << matrix_33.transpose() << endl;
    
    //  0.680375 -0.211234  0.566198
    //   0.59688  0.823295 -0.604897
    // -0.329554  0.536459 -0.444451
    
    
      
      
      
      
      
    
    AI助手

2.12. 求和

通过sum() 进行转置

复制代码
    cout << matrix_33.sum() << endl;
    
    // 1.61307
    
    
      
      
      
    
    AI助手

2.13. 求迹

一个n×n矩阵A在其主元素对角线上(即从左上至右下的对角线)的所有元素之和被称为该矩阵A的迹。

通过trace() 进行求迹

复制代码
    cout << matrix_33.trace() << endl;
    
    // 1.05922
    
    
      
      
      
    
    AI助手

2.14. 数乘

复制代码
    cout << 10 * matrix_33 << endl;
    
    //  6.80375   5.9688 -3.29554
    // -2.11234  8.23295  5.36459
    //  5.66198 -6.04897 -4.44451
    
    
      
      
      
      
      
    
    AI助手

2.15. 逆矩阵

令A为数域上的一个n阶方阵;如果在相同的数域内存在另一个n阶方阵B,则满足AB=BA=E时,则称B为A的逆矩阵。

通过inverse() 进行求逆矩阵

复制代码
    cout << matrix_33.inverse() << endl; 
    
    // -0.198521   2.22739    2.8357
    //   1.00605 -0.555135  -1.41603
    //  -1.62213   3.59308   3.28973
    
    
      
      
      
      
      
    
    AI助手

2.16. 行列式

一个n×n的方阵A的行列式记为 det(A) 或者 |A|
一个2×2矩阵的行列式可表示如下:

在这里插入图片描述

通过determinant() 进行行列式

复制代码
    cout << matrix_33.determinant() << endl;
    
    // 0.208598
    
    
      
      
      
    
    AI助手

2.17. 特征值

令矩阵A为n \times n阶方阵,则若存在标量\lambda及其对应的非零向量x满足等式Ax=\lambda x成立,则定义\lambda为矩阵A的特征值

在这里插入图片描述

实对称矩阵可以保证对角化成功

复制代码
    Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(matrix_33.transpose()*matrix_33);
    cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;
    
    // Eigen values = 
    // 0.0242899
    //  0.992154
    //   1.80558
    
    
      
      
      
      
      
      
      
    
    AI助手

2.18. 特征向量

令A为n阶矩阵。若存在标量λ和非零的n维列向量x满足Ax=λx,则称λ为矩阵A的一个特征值,并称其对应的非零解x为该特征值的特征向量。

复制代码
    cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;
    
    // Eigen vectors = 
    // -0.549013 -0.735943  0.396198
    //  0.253452 -0.598296 -0.760134
    // -0.796459  0.316906 -0.514998
    
    
      
      
      
      
      
      
    
    AI助手

2.19. 解方程

对该矩阵方程 matrix_NN * x = v_Nd 进行解析求解

复制代码
    #define MATRIX_SIZE 50
    
    
      
    
    AI助手

直接求逆自然是最直接的,但是求逆运算量大

复制代码
    Eigen::Matrix< double, MATRIX_SIZE, MATRIX_SIZE > matrix_NN;
    matrix_NN = Eigen::MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
    Eigen::Matrix< double, MATRIX_SIZE, 1> v_Nd;
    v_Nd = Eigen::MatrixXd::Random(MATRIX_SIZE, 1);
    // 计时
    clock_t time_stt = clock(); 
    // 直接求逆
    Eigen::Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse()*v_Nd;
    cout << "time use in normal inverse is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;
    
    // time use in normal inverse is 3.092ms
    
    
      
      
      
      
      
      
      
      
      
      
      
    
    AI助手

2.20. 矩阵分解

通常用矩阵分解来求
例如:QR分解,速度会快很多

复制代码
    time_stt = clock();
    x = matrix_NN.colPivHouseholderQr().solve(v_Nd);
    cout << "time use in Qr decomposition is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;
    
    // time use in Qr decomposition is 0.06ms
    
    
      
      
      
      
      
    
    AI助手

3. 编译

要编译它,需要在 CMakeLists.txt 里指定 Eigen 的头文件目录:

复制代码
    # 添加Eigen头文件
    include_directories( "/usr/include/eigen3" )
    
    
      
      
    
    AI助手

由于Eigen库仅提供头文件接口,在编译时无需额外运行target_link_libraries命令即可完成链接操作。然而,在大多数情况下,默认编译选项即可满足需求。这种做法未必是最优的,因为为了避免因Eigen库安装路径变更导致的编译问题,在实际项目中我们通常会手动指定包含目录以确保编译正确性

在之后的工作中,会使用 find_package 命令去搜索库

使用 cmake 编译整个工程

复制代码
    $ mkdir build
    $ cd build
    $ cmake ..
    $ make
    
    
      
      
      
      
    
    AI助手

4. 输出结果

编译好这个程序后,运行它,看到各矩阵的输出结果

复制代码
    $ ./eigenMatrix
    
    
      
    
    AI助手
在这里插入图片描述

参考:

《视觉SLAM十四讲》


相关推荐:

视觉SLAM笔记(8) 齐次坐标
视觉SLAM笔记(7) 欧氏变换
视觉SLAM笔记(6) 坐标系
视觉SLAM笔记(5) 编程基础
视觉SLAM笔记(4) SLAM的数学表述


谢谢!

全部评论 (0)

还没有任何评论哟~