视觉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笔记(8) 齐次坐标
视觉SLAM笔记(7) 欧氏变换
视觉SLAM笔记(6) 坐标系
视觉SLAM笔记(5) 编程基础
视觉SLAM笔记(4) SLAM的数学表述
谢谢!
