Eigen中Dense 模块简要介绍和实战应用示例(最小二乘拟合直线、协方差矩阵计算和稀疏求解等)
1、Dense简介
1️.Dense 模块概述
Eigen::Dense
模块是 Eigen 的核心模块之一,主要用于处理 密集矩阵(Dense Matrix)和向量(Dense Vector)。它与 Eigen 的稀疏矩阵模块(Eigen::Sparse
)互补。
特点:
-
支持固定和动态大小
- 固定大小:如
Matrix3d
、Vector4f
- 动态大小:如
MatrixXd
、VectorXd
- 优势:固定大小矩阵在编译期优化,速度快;动态大小矩阵灵活性高。
- 固定大小:如
-
面向表达式模板(Expression Templates)
- Eigen 的运算不是立即计算,而是构建表达式树
- 优点:减少临时变量、延迟计算、优化性能
-
高性能
- 内存连续(RowMajor 或 ColumnMajor,可选)
- 支持 SIMD 向量化(如 SSE、AVX)
- 适合线性代数、最小二乘、矩阵分解、几何变换等场景
-
丰富的线性代数支持
- 基本运算:加减、乘除、转置
- 矩阵分解:LU、QR、SVD、Cholesky、EigenSolver
- 特殊矩阵生成:零矩阵、单位矩阵、全1矩阵
- 块操作:
block()
、row()
、col()
、segment()
-
模板化设计
- 数据类型可选:
float
、double
、int
等 - 支持矩阵和向量混合运算
- 数据类型可选:
2️.Dense 模块核心类型
类型 | 描述 | 备注 |
---|---|---|
Matrix<T, Rows, Cols> | 通用矩阵 | Rows 和 Cols 可固定或动态(用 Dynamic ) |
Vector<T, Size> | 列向量 | 等价于 Matrix<T, Size, 1> |
RowVector<T, Size> | 行向量 | 等价于 Matrix<T, 1, Size> |
Array<T, Rows, Cols> | 元素逐一运算 | 用于逐元素加减乘除等 |
DiagonalMatrix<T, Size> | 对角矩阵 | 可与矩阵相乘或求逆 |
Quaternion<T> | 四元数 | 用于旋转表示 |
AngleAxis<T> | 旋转轴角表示 | 可转换为旋转矩阵 |
3.Dense 模块内部机制
-
内存布局
- 默认按列主序(ColumnMajor)
- 可改为行主序(
Matrix<T, Rows, Cols, RowMajor>
)
-
表达式模板
- 避免临时矩阵
- 支持链式运算
A + B + C
高效执行
-
固定 vs 动态大小
- 固定大小在编译期优化,适合小矩阵(如 2x2, 3x3)
- 动态大小适合大矩阵(如点云处理、最小二乘)
-
SIMD 向量化
- 自动利用 CPU SIMD 指令(SSE/AVX)
- 速度可接近手写优化代码
2、Eigen/Dense 基础
2.1 引入头文件
#include <Eigen/Dense>
#include <iostream>using namespace Eigen;
using namespace std;
Eigen/Dense
会自动包含 Eigen 所有核心模块,适合大部分线性代数操作。- 使用
using namespace Eigen
简化类型书写。
2.2 向量类型
Eigen 中向量是矩阵的特殊情况,行向量或列向量。
Vector3d v1(1.0, 2.0, 3.0); // 列向量 3x1, double 类型
Vector3f v2(1.0f, 2.0f, 3.0f); // float 类型
VectorXd vDynamic(5); // 动态大小向量
vDynamic << 1, 2, 3, 4, 5;
Vector3d
→ 3维 double 列向量VectorXd
→ 动态维度列向量<<
可快速赋值
2.3 矩阵类型
Matrix3d A; // 3x3 double 矩阵
MatrixXd B(2, 3); // 2x3 动态矩阵A << 1, 2, 3,4, 5, 6,7, 8, 9;B << 1, 2, 3,4, 5, 6;
Matrix3d
→ 3x3 固定大小矩阵MatrixXd
→ 动态大小矩阵<<
支持逐行填充
2.4 矩阵操作
Matrix3d M;
M << 1, 2, 3,0, 1, 4,5, 6, 0;// 转置
Matrix3d Mt = M.transpose();// 逆矩阵
Matrix3d Minv = M.inverse();// 矩阵乘法
Matrix3d R = M * Mt;// 元素逐一操作
Matrix3d N = M.array() + 1.0; // 每个元素加1
Matrix3d P = M.array() * 2; // 每个元素乘2
matrix.array()
→ 逐元素操作matrix * matrix2
→ 矩阵乘法matrix.inverse()
→ 求逆(仅对方阵有效)
2.5 特殊矩阵生成
Matrix3d I = Matrix3d::Identity(); // 单位矩阵
MatrixXd Z = MatrixXd::Zero(2, 3); // 零矩阵
MatrixXd O = MatrixXd::Ones(2, 3); // 全1矩阵
2.6 矩阵块操作
Matrix3d M;
M << 1,2,3,4,5,6,7,8,9;// 提取子矩阵
Matrix2d sub = M.block<2,2>(0,0); // 左上角2x2块// 改变子矩阵
M.block<2,2>(1,1) = Matrix2d::Identity();
block<rows,cols>(i,j)
→ 固定大小块block(i,j,rows,cols)
→ 动态块
2.7 特征值与奇异值分解
Matrix3d A;
A << 1, 2, 3,0, 1, 4,5, 6, 0;// Eigen值分解(仅对方阵)
EigenSolver<Matrix3d> es(A);
cout << "Eigenvalues:\n" << es.eigenvalues() << endl;
cout << "Eigenvectors:\n" << es.eigenvectors() << endl;// 奇异值分解
JacobiSVD<MatrixXd> svd(A, ComputeFullU | ComputeFullV);
cout << "U:\n" << svd.matrixU() << endl;
cout << "S:\n" << svd.singularValues() << endl;
cout << "V:\n" << svd.matrixV() << endl;
EigenSolver
→ 特征值与特征向量JacobiSVD
→ 奇异值分解,用于非方阵或最小二乘
3、Eigen 实战示例
示例1:最小二乘拟合直线
int n = 5;
VectorXd x(n), y(n);
x << 0, 1, 2, 3, 4;
y << 1, 3, 7, 13, 21;// 构造 A*x = b
MatrixXd A(n,2);
A.col(0) = VectorXd::Ones(n);
A.col(1) = x;VectorXd coeff = A.colPivHouseholderQr().solve(y);
cout << "y = " << coeff(1) << " * x + " << coeff(0) << endl;
- 用
colPivHouseholderQr()
进行最小二乘求解 - 输出拟合直线参数
示例2:旋转矩阵 + 向量变换(机器人/SLAM常用)
Matrix3d R;
R = AngleAxisd(M_PI/4, Vector3d::UnitZ()).toRotationMatrix();
Vector3d t(1, 2, 3);
Vector3d p(1, 0, 0);// 变换
Vector3d p_trans = R * p + t;
cout << "Transformed point: " << p_trans.transpose() << endl;
AngleAxisd
→ 构造绕某轴旋转的旋转矩阵R*p + t
→ 坐标变换
示例3:点云质心和协方差矩阵
MatrixXd points(3,5);
points << 1,2,3,4,5,0,1,0,1,0,2,3,4,5,6;// 计算质心
Vector3d centroid = points.rowwise().mean();// 去质心
MatrixXd centered = points.colwise() - centroid;// 协方差矩阵
Matrix3d cov = (centered * centered.transpose()) / (points.cols() - 1);
cout << "Covariance matrix:\n" << cov << endl;
- 常用于 PCA、点云处理、SLAM
示例4:动态稀疏求解(大规模线性系统)
MatrixXd A = MatrixXd::Random(1000, 500);
VectorXd b = VectorXd::Random(1000);// 最小二乘解
VectorXd x = A.colPivHouseholderQr().solve(b);
cout << "Residual norm: " << (A*x - b).norm() << endl;
- 大规模系统可直接用 Eigen 的
QR
或SVD
求解 - 高性能场景可使用稀疏模块(
Eigen/Sparse
)
4、️总结与应用场景
Dense 模块特点
- 面向密集矩阵、向量运算
- 支持固定和动态维度
- 支持矩阵运算、分解、块操作
- 高度模板化,性能优秀
实战应用
- 机器人/SLAM:位姿变换、最小二乘优化、点云协方差计算
- 计算机视觉:PCA、SVD、特征提取
- 数值计算:大规模线性方程求解、矩阵分解、特征值问题