当前位置: 首页 > 工具软件 > Eigen > 使用案例 >

PCL/Eigen的简单使用

颜举
2023-12-01

*注:本文转载于以下可点开的链接。侵删,谢谢!

点云的基本数据结构

PCL学习笔记->基本用法4(使用一个矩阵转换点云)

Eigen的介绍及简单使用
(详细请点链接进入)
Eigen的下载与安装,可参考下面两个博客:

http://blog.csdn.net/hjx_1000/article/details/8477522

或者:http://blog.csdn.net/abcjennifer/article/details/7781936;

Eigen帮助文档的地址:http://eigen.tuxfamily.org/dox/pages.html,本文中很多例子也是直接摘自这些帮助文档,

另外关于Eigen的论坛可以访问http://forum.kde.org/viewforum.php?f=74

Eigen用源码的方式提供给用户使用,在使用时只需要包含Eigen的头文件即可进行使用。

之所以采用这种方式,是因为Eigen采用模板方式实现,由于模板函数不支持分离编译,所以只能提供源码而不是动态库的方式供用户使用,不过这也也更方面用户使用和研究。关于模板的不支持分离编译的更多内容,请参考:http://blog.csdn.net/hjx_1000/article/details/8093701
如下简单介绍
Eigen是可以用来进行线性代数、矩阵、向量操作等运算的C++库,它里面包含了很多算法。它的License是MPL2。它支持多平台。

Eigen采用源码的方式提供给用户使用,在使用时只需要包含Eigen的头文件即可进行使用。之所以采用这种方式,是因为Eigen采用模板方式实现,由于模板函数不支持分离编译,所以只能提供源码而不是动态库的方式供用户使用。

矩阵的定义:Eigen中关于矩阵类的模板函数中,共有六个模板参数,常用的只有前三个。其前三个参数分别表示矩阵元素的类型、行数和列数。

矩阵定义时可以使用Dynamic来表示矩阵的行列数为未知。

Eigen中无论是矩阵还是数组、向量,无论是静态矩阵还是动态矩阵都提供默认构造函数,也就是定义这些数据结构时都可以不用提供任何参数,其大小均由运行时来确定。矩阵的构造函数中只提供行列数、元素类型的构造参数,而不提供元素值的构造,对于比较小的、固定长度的向量提供初始化元素的定义。

矩阵类型:Eigen中的矩阵类型一般都是用类似MatrixXXX来表示,可以根据该名字来判断其数据类型,比如”d”表示double类型,”f”表示float类型,”i”表示整数,”c”表示复数;Matrix2f,表示的是一个2*2维的,其每个元素都是float类型。

数据存储:Matrix创建的矩阵默认是按列存储,Eigen在处理按列存储的矩阵时会更加高效。如果想修改可以在创建矩阵的时候加入参数,如:

Matrix<int,3, 4, ColMajor> Acolmajor;

Matrix<int,3, 4, RowMajor> Arowmajor;

动态矩阵和静态矩阵:动态矩阵是指其大小在运行时确定,静态矩阵是指其大小在编译时确定。

MatrixXd:表示任意大小的元素类型为double的矩阵变量,其大小只有在运行时被赋值之后才能知道。

Matrix3d:表示元素类型为double大小为3*3的矩阵变量,其大小在编译时就知道。

在Eigen中行优先的矩阵会在其名字中包含有row,否则就是列优先。

Eigen中的向量只是一个特殊的矩阵,其维度为1而已。

矩阵元素的访问:在矩阵的访问中,行索引总是作为第一个参数,Eigen中矩阵、数组、向量的下标都是从0开始。矩阵元素的访问可以通过”()”操作符完成。例如m(2, 3)既是获取矩阵m的第2行第3列元素。

针对向量还提供”[]”操作符,注意矩阵则不可如此使用。

设置矩阵的元素:在Eigen中重载了”<<”操作符,通过该操作符即可以一个一个元素的进行赋值,也可以一块一块的赋值。另外也可以使用下标进行赋值。

重置矩阵大小:当前矩阵的行数、列数、大小可以通过rows()、cols()和size()来获取,对于动态矩阵可以通过resize()函数来动态修改矩阵的大小。注意:(1)、固定大小的矩阵是不能使用resize()来修改矩阵的大小;(2)、resize()函数会析构掉原来的数据,因此调用resize()函数之后将不能保证元素的值不改变;(3)、使用”=”操作符操作动态矩阵时,如果左右两边的矩阵大小不等,则左边的动态矩阵的大小会被修改为右边的大小。

如何选择动态矩阵和静态矩阵:对于小矩阵(一般大小小于16)使用固定大小的静态矩阵,它可以带来比较高的效率;对于大矩阵(一般大小大于32)建议使用动态矩阵。注意:如果特别大的矩阵使用了固定大小的静态矩阵则可能会造成栈溢出的问题。

矩阵和向量的算术运算:在Eigen中算术运算重载了C++的+、-、*

(1)、矩阵的运算:提供+、-、一元操作符”-”、+=、-=;二元操作符+/-,表示两矩阵相加(矩阵中对应元素相加/减,返回一个临时矩阵);一元操作符-表示对矩阵取负(矩阵中对应元素取负,返回一个临时矩阵);组合操作法+=或者-=表示(对应每个元素都做相应操作);矩阵还提供与标量(单一数字)的乘除操作,表示每个元素都与该标量进行乘除操作;

(2)、求矩阵的转置、共轭矩阵、伴随矩阵:可以通过成员函数transpose()、conjugate()、adjoint()来完成。注意:这些函数返回操作后的结果,而不会对原矩阵的元素进行直接操作,如果要让原矩阵进行转换,则需要使用响应的InPlace函数,如transpoceInPlace()等;

(3)、矩阵相乘、矩阵向量相乘:使用操作符*,共有=两种操作符;

(4)、矩阵的块操作:有两种使用方法:

matrix.block(i,j, p, q) : 表示返回从矩阵(i, j)开始,每行取p个元素,每列取q个元素所组成的临时新矩阵对象,原矩阵的元素不变;

matrix.block<p,q>(i, j) :<p, q>可理解为一个p行q列的子矩阵,该定义表示从原矩阵中第(i, j)开始,获取一个p行q列的子矩阵,返回该子矩阵组成的临时矩阵对象,原矩阵的元素不变;

(5)、向量的块操作:

获取向量的前n个元素:vector.head(n);

获取向量尾部的n个元素:vector.tail(n);

获取从向量的第i个元素开始的n个元素:vector.segment(i,n);

Map类:在已经存在的矩阵或向量中,不必拷贝对象,而是直接在该对象的内存上进行运算操作。

Eigen库的基本操作
如下

Eigen 矩阵定义
复制代码
 
#include <Eigen/Dense>
 
Matrix<double, 3, 3> A;               // Fixed rows and cols. Same as Matrix3d.
Matrix<double, 3, Dynamic> B;         // Fixed rows, dynamic cols.
Matrix<double, Dynamic, Dynamic> C;   // Full dynamic. Same as MatrixXd.
Matrix<double, 3, 3, RowMajor> E;     // Row major; default is column-major.
Matrix3f P, Q, R;                     // 3x3 float matrix.
Vector3f x, y, z;                     // 3x1 float matrix.
RowVector3f a, b, c;                  // 1x3 float matrix.
VectorXd v;                           // Dynamic column vector of doubles
// Eigen          // Matlab           // comments
x.size()          // length(x)        // vector size
C.rows()          // size(C,1)        // number of rows
C.cols()          // size(C,2)        // number of columns
x(i)              // x(i+1)           // Matlab is 1-based
C(i,j)            // C(i+1,j+1)       //
 
复制代码
 Eigen 基础使用
复制代码
 
// Basic usage
// Eigen        // Matlab           // comments
x.size()        // length(x)        // vector size
C.rows()        // size(C,1)        // number of rows
C.cols()        // size(C,2)        // number of columns
x(i)            // x(i+1)           // Matlab is 1-based
C(i, j)         // C(i+1,j+1)       //
 
A.resize(4, 4);   // Runtime error if assertions are on.
B.resize(4, 9);   // Runtime error if assertions are on.
A.resize(3, 3);   // Ok; size didn't change.
B.resize(3, 9);   // Ok; only dynamic cols changed.
                  
A << 1, 2, 3,     // Initialize A. The elements can also be
     4, 5, 6,     // matrices, which are stacked along cols
     7, 8, 9;     // and then the rows are stacked.
B << A, A, A;     // B is three horizontally stacked A's.
A.fill(10);       // Fill A with all 10's.
 
复制代码
Eigen 特殊矩阵生成
复制代码
 
// Eigen                            // Matlab
MatrixXd::Identity(rows,cols)       // eye(rows,cols)
C.setIdentity(rows,cols)            // C = eye(rows,cols)
MatrixXd::Zero(rows,cols)           // zeros(rows,cols)
C.setZero(rows,cols)                // C = ones(rows,cols)
MatrixXd::Ones(rows,cols)           // ones(rows,cols)
C.setOnes(rows,cols)                // C = ones(rows,cols)
MatrixXd::Random(rows,cols)         // rand(rows,cols)*2-1        // MatrixXd::Random returns uniform random numbers in (-1, 1).
C.setRandom(rows,cols)              // C = rand(rows,cols)*2-1
VectorXd::LinSpaced(size,low,high)  // linspace(low,high,size)'
v.setLinSpaced(size,low,high)       // v = linspace(low,high,size)'
 
复制代码
Eigen 矩阵分块
复制代码
 
// Matrix slicing and blocks. All expressions listed here are read/write.
// Templated size versions are faster. Note that Matlab is 1-based (a size N
// vector is x(1)...x(N)).
// Eigen                           // Matlab
x.head(n)                          // x(1:n)
x.head<n>()                        // x(1:n)
x.tail(n)                          // x(end - n + 1: end)
x.tail<n>()                        // x(end - n + 1: end)
x.segment(i, n)                    // x(i+1 : i+n)
x.segment<n>(i)                    // x(i+1 : i+n)
P.block(i, j, rows, cols)          // P(i+1 : i+rows, j+1 : j+cols)
P.block<rows, cols>(i, j)          // P(i+1 : i+rows, j+1 : j+cols)
P.row(i)                           // P(i+1, :)
P.col(j)                           // P(:, j+1)
P.leftCols<cols>()                 // P(:, 1:cols)
P.leftCols(cols)                   // P(:, 1:cols)
P.middleCols<cols>(j)              // P(:, j+1:j+cols)
P.middleCols(j, cols)              // P(:, j+1:j+cols)
P.rightCols<cols>()                // P(:, end-cols+1:end)
P.rightCols(cols)                  // P(:, end-cols+1:end)
P.topRows<rows>()                  // P(1:rows, :)
P.topRows(rows)                    // P(1:rows, :)
P.middleRows<rows>(i)              // P(i+1:i+rows, :)
P.middleRows(i, rows)              // P(i+1:i+rows, :)
P.bottomRows<rows>()               // P(end-rows+1:end, :)
P.bottomRows(rows)                 // P(end-rows+1:end, :)
P.topLeftCorner(rows, cols)        // P(1:rows, 1:cols)
P.topRightCorner(rows, cols)       // P(1:rows, end-cols+1:end)
P.bottomLeftCorner(rows, cols)     // P(end-rows+1:end, 1:cols)
P.bottomRightCorner(rows, cols)    // P(end-rows+1:end, end-cols+1:end)
P.topLeftCorner<rows,cols>()       // P(1:rows, 1:cols)
P.topRightCorner<rows,cols>()      // P(1:rows, end-cols+1:end)
P.bottomLeftCorner<rows,cols>()    // P(end-rows+1:end, 1:cols)
P.bottomRightCorner<rows,cols>()   // P(end-rows+1:end, end-cols+1:end)
 
复制代码
Eigen 矩阵元素交换
 
// Of particular note is Eigen's swap function which is highly optimized.
// Eigen                           // Matlab
R.row(i) = P.col(j);               // R(i, :) = P(:, i)
R.col(j1).swap(mat1.col(j2));      // R(:, [j1 j2]) = R(:, [j2, j1])
 
Eigen 矩阵转置
复制代码
 
// Views, transpose, etc; all read-write except for .adjoint().
// Eigen                           // Matlab
R.adjoint()                        // R'
R.transpose()                      // R.' or conj(R')
R.diagonal()                       // diag(R)
x.asDiagonal()                     // diag(x)
R.transpose().colwise().reverse(); // rot90(R)
R.conjugate()                      // conj(R)
 
复制代码
Eigen 矩阵乘积
复制代码
 
// All the same as Matlab, but matlab doesn't have *= style operators.
// Matrix-vector.  Matrix-matrix.   Matrix-scalar.
y  = M*x;          R  = P*Q;        R  = P*s;
a  = b*M;          R  = P - Q;      R  = s*P;
a *= M;            R  = P + Q;      R  = P/s;
                   R *= Q;          R  = s*P;
                   R += Q;          R *= s;
                   R -= Q;          R /= s;
 
复制代码
Eigen 矩阵单个元素操作
复制代码
 
// Vectorized operations on each element independently
// Eigen                  // Matlab
R = P.cwiseProduct(Q);    // R = P .* Q
R = P.array() * s.array();// R = P .* s
R = P.cwiseQuotient(Q);   // R = P ./ Q
R = P.array() / Q.array();// R = P ./ Q
R = P.array() + s.array();// R = P + s
R = P.array() - s.array();// R = P - s
R.array() += s;           // R = R + s
R.array() -= s;           // R = R - s
R.array() < Q.array();    // R < Q
R.array() <= Q.array();   // R <= Q
R.cwiseInverse();         // 1 ./ P
R.array().inverse();      // 1 ./ P
R.array().sin()           // sin(P)
R.array().cos()           // cos(P)
R.array().pow(s)          // P .^ s
R.array().square()        // P .^ 2
R.array().cube()          // P .^ 3
R.cwiseSqrt()             // sqrt(P)
R.array().sqrt()          // sqrt(P)
R.array().exp()           // exp(P)
R.array().log()           // log(P)
R.cwiseMax(P)             // max(R, P)
R.array().max(P.array())  // max(R, P)
R.cwiseMin(P)             // min(R, P)
R.array().min(P.array())  // min(R, P)
R.cwiseAbs()              // abs(P)
R.array().abs()           // abs(P)
R.cwiseAbs2()             // abs(P.^2)
R.array().abs2()          // abs(P.^2)
(R.array() < s).select(P,Q);  // (R < s ? P : Q)
 
复制代码
Eigen 矩阵化简
复制代码
 
// Reductions.
int r, c;
// Eigen                  // Matlab
R.minCoeff()              // min(R(:))
R.maxCoeff()              // max(R(:))
s = R.minCoeff(&r, &c)    // [s, i] = min(R(:)); [r, c] = ind2sub(size(R), i);
s = R.maxCoeff(&r, &c)    // [s, i] = max(R(:)); [r, c] = ind2sub(size(R), i);
R.sum()                   // sum(R(:))
R.colwise().sum()         // sum(R)
R.rowwise().sum()         // sum(R, 2) or sum(R')'
R.prod()                  // prod(R(:))
R.colwise().prod()        // prod(R)
R.rowwise().prod()        // prod(R, 2) or prod(R')'
R.trace()                 // trace(R)
R.all()                   // all(R(:))
R.colwise().all()         // all(R)
R.rowwise().all()         // all(R, 2)
R.any()                   // any(R(:))
R.colwise().any()         // any(R)
R.rowwise().any()         // any(R, 2)
 
复制代码
Eigen 矩阵点乘
 
// Dot products, norms, etc.
// Eigen                  // Matlab
x.norm()                  // norm(x).    Note that norm(R) doesn't work in Eigen.
x.squaredNorm()           // dot(x, x)   Note the equivalence is not true for complex
x.dot(y)                  // dot(x, y)
x.cross(y)                // cross(x, y) Requires #include <Eigen/Geometry>
 
Eigen 矩阵类型转换
复制代码
 
 Type conversion
// Eigen                           // Matlab
A.cast<double>();                  // double(A)
A.cast<float>();                   // single(A)
A.cast<int>();                     // int32(A)
A.real();                          // real(A)
A.imag();                          // imag(A)
// if the original type equals destination type, no work is done
 
复制代码
Eigen 求解线性方程组 Ax = b
复制代码
 
// Solve Ax = b. Result stored in x. Matlab: x = A \ b.
x = A.ldlt().solve(b));  // A sym. p.s.d.    #include <Eigen/Cholesky>
x = A.llt() .solve(b));  // A sym. p.d.      #include <Eigen/Cholesky>
x = A.lu()  .solve(b));  // Stable and fast. #include <Eigen/LU>
x = A.qr()  .solve(b));  // No pivoting.     #include <Eigen/QR>
x = A.svd() .solve(b));  // Stable, slowest. #include <Eigen/SVD>
// .ldlt() -> .matrixL() and .matrixD()
// .llt()  -> .matrixL()
// .lu()   -> .matrixL() and .matrixU()
// .qr()   -> .matrixQ() and .matrixR()
// .svd()  -> .matrixU(), .singularValues(), and .matrixV()
 
复制代码
Eigen 矩阵特征值
复制代码
 
// Eigenvalue problems
// Eigen                          // Matlab
A.eigenvalues();                  // eig(A);
EigenSolver<Matrix3d> eig(A);     // [vec val] = eig(A)
eig.eigenvalues();                // diag(val)
eig.eigenvectors();               // vec
// For self-adjoint matrices use SelfAdjointEigenSolver<>
 
复制代码

Eigen3详细使用教程
如下

#include <iostream>
#include <ctime>
#include <Eigen/Dense>              // 稠密矩阵的代数运算
using namespace std;
 
#define MATRIX_SIZE 100
 
int main()
{
	// Eigen 以矩阵为基本数据单元,它是一个模板类,它的前三个参数为: 数据类型,行,列
	Eigen::Matrix<float, 2, 3> matrix_23;          // 声明一个2*3的float矩阵
	// 同时Eigen通过typedef 提供了许多内置类型,不过底层仍是Eigen::Matrix
	// 例如Vector3d实质上是Eigen::Matrix<double,3,1>,即三维向量
	Eigen::Vector3d v_3d;
	// 这是一样的
	Eigen::Matrix<float, 3, 1> vd_3d;
 
	// Matrix3d 实质上是Eigen::Matrix<double,3,3>
	Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero();    // 初始化为零
 
	// 如果不确定矩阵大小,可以使用动态大小的矩阵
	Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_dynamic;
	// 下面是一种更简单的写法
	Eigen::MatrixXd matrix_x;
 
	// 下面是对Eigen矩阵的操作
	// 输入数据(初始化)
	matrix_23 << 1, 2, 3, 4, 5, 6;            
	// 输出
	cout << matrix_23 << endl;           
 
	// 用()访问矩阵中的元素
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 3; j++)
			cout << matrix_23(i, j) << "\t";
 
	cout << endl;
 
	// 矩阵和向量的相乘(实际上仍然是矩阵和矩阵)
	v_3d << 3, 2, 1;
	vd_3d << 4, 5, 6;
 
	// 但是在Eigen里你不能混合两种不同类型的矩阵,像这样是错的,下面是double和float
	// Eigen::Matrix<double, 2, 1> result_wrong_type = matrix_23 * v_3d;
	// 应该显式转换
	Eigen::Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;
	cout << result << endl;
 
	// 标准的矩阵乘法
	Eigen::Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;
	cout << result2 << endl;
 
	// 矩阵的维数不对,会报错
	// Eigen::Matrix<double, 2, 3> result_wrong_dimension = matrix_23.cast<double>() * v_3d;
 
	// 一些矩阵运算
	// 四则运算就不演示了,直接用+-*/即可。
	matrix_33 = Eigen::Matrix3d::Random();      // 随机数矩阵
	cout << matrix_33 << endl;                  // 输出矩阵
	cout << "-------------------------" << endl;
	cout << matrix_33.transpose() << endl;      // 矩阵转置
	cout << "-------------------------" << endl;
	cout << matrix_33.sum() << endl;            // 各元素的和
	cout << "-------------------------" << endl;
	cout << matrix_33.trace() << endl;          // 矩阵的迹
	cout << "-------------------------" << endl;
	cout << 10 * matrix_33 << endl;             // 数乘
	cout << "-------------------------" << endl;
	cout << matrix_33.inverse() << endl;        // 矩阵求逆
	cout << "-------------------------" << endl;
	cout << matrix_33.determinant() << endl;    // 行列式
 
	// 特征值
	// 实对称矩阵可以保证对角化成功
	Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(matrix_33.transpose()*matrix_33);
	cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;
	cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;   // 特征值对应的特征向量列排列’
 
	Eigen::Matrix< double, MATRIX_SIZE, MATRIX_SIZE > matrix_NN;           // 声明一个MATRIX_SIZE*MATRIX_SIZE矩阵
 
	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;
 
	// 通常用矩阵分解来求,例如QR分解,速度会快很多
	time_stt = clock();
	x = matrix_NN.colPivHouseholderQr().solve(v_Nd);                       // QR分解
	cout << "time use in Qr decomposition is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;
	return 0;
}
 类似资料: