Eigen(安装与使用)

如何使用Eigen来表示矩阵、向量,随后引申到旋转矩阵与变换矩阵的计算

Eigen是一个C++开源线性代数库。它提供了快速的有关矩阵的线性代数运算,还包括解方程等功能。g2o、Sophus也都使用Eigen来进行矩阵计算。

安装Eigen
sudo apt-get install libeigen3-dev

查找Eigen在哪里

sudo updatedb
locate eigen3
  • Eigen有一个神奇的地方:它是一个纯用头文件搭建起来的库
  • 这意味着你只能找到它的头文件,而没有.so或.a这样的二进制文件。我们在使用的时候,只需要引入Eigen的头文件即可,不需要链接它的库(因为它没有库文件)。
练习使用Eigen
#include
#include
using namespace std;

//Eigen
#include
//稠密矩阵的代数运算(逆,特征值等)
#include

#define MATRIX_SIZE 50

/*******************
*演示Eigen基本类型使用
********************/

int main( int argc, char** argv)
{
   //Eigen以矩阵为基本数据单元。它的前三个参数为:数据类型、行、列(请记住)
   //声明一个2*3的float矩阵
   Eigen::Matrix<float, 2, 3> matrix_23;
   //同时,Eigen通过typedef提供了许多内置类型,不过底层仍是Eigen::Matrix
   //例如Vector3d实则上是Eigen::Matrix
   Eigen::Vector3d v_3d;
   //还有Matrix3d实质上是Eigen::Matrix
   Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero();//初始化为零
   //如果不确定矩阵大小,可以使用动态大小的矩阵
   Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_dynamic;
   //更简单的
   Eigen::MatrixXd matrix_x;
   //这种类型还有很多,我们不一一列举

   //下面是对矩阵的操作
   //输入数据
   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)<<endl;

   v_3d << 3, 2, 1;
   //矩阵和向量相乘(实际上仍是矩阵与矩阵相乘)
   //但是在这里你不能混合两种不同类型的矩阵,下面这样是错的
   //Eigen::Matrixresult_wrong_type = matrix_23 * v_3d;

   //应该显式转换
   Eigen::Matrix<double, 2, 1>result = matrix_23.cast<double>()*v_3d;
   cout << result << endl;
   
   //同样,你不能搞错矩阵的维度
   //试着取消下面的注释,看看会报什么错
   //Eigen::Matrixresult_wrong_dimension = matrix_23.cast() * v_3d;
   
   //一些矩阵运算
   //四则运算就不演示了,直接用对应的运算符即可。
   matrix_33 = Eigen::Matrix3d::Random();
   cout << matrix_33 << endl << endl;

   cout << matrix33.transpose() << endl;
   cout << matrix_33.sum() << endl;
   cout << matrix_33.trace() << endl;
   cout << 10*matrix_33 << endl;
   cout << matrix_33.inverse() << endl;
   cout << matrix_33.determinant() << endl;

   //特征值
   //实对称矩阵可以保证对角化成功
   Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver ( matrix_33.transpose()*matrix_33 );
   cout << "Eigen values = " << eigen_solver.eigenvalues() << endl;
   cout << "Eigen vectors = " << eigen_solver.eigenvectors() << endl;

   //解方程
   //我们求解matrix_NN * x = x_Nd这个方程
   //N的大小在前边的宏里定义,矩阵由随机数生成
   //直接求逆自然是最直接的,但是求逆运算量大

   Eigen::Matrix< double, MATRIX_SIZE, MATRIX_SIZE> matrix_NM;
   matrix_NN = Eigen::MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
   Eigen::Matrix<double, MATRIX_SIZE, 1> v_Nd;
   v_Nd = Eigen::Matrix::Random( MATRIX_SIZE, 1);
   clock_t time_stt = clock();//计时
   //直接求逆
   Eigen::Matrix<double, MATRIX_SIZE, 1> x = matrix_NM.inverse() * v_Nd;
   cout << "time use in normal invers is "<<1000*(clock() - time_stt)/(double)CLOCK_PER_SEC << "MS"<<endl;
   //通常用矩阵分解来求,例如QR分解,速度会快很多
   time_stt = clock();
   x = matrix_NM.colPivHouseholderQr().solve(v_Nd);
   cout << "time use in Qr compsition is " << 1000*(clock() - time_stt)/(double)CLOCK_PER_SEC << "MS" << endl;

   return 0;
}

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

#添加头文件
include_directories("/usr/include/eigen3")

重复提醒大家一下,因为Eigen库只有头文件,我们不需要再用target_link_libraries语句将程序链接到库上。不过大多数其他库需要用到链接命令。

接下来希望大家去跑一跑这个示例。

总结

  1. Eigen提供的矩阵,几乎所有的数据都当作矩阵来处理。但是,为了实现更好的效率,在Eigen中你需要指定矩阵的大小和类型。对于在编译时期就知道大小的矩阵,处理起来会比动态变化大小的矩阵更快一点。因此,像旋转矩阵、变换矩阵这样的数据,完全可在编译时期确定它们的大小和数据类型。
  2. 大家使用Eigen的时候,希望你像使用float、double那样的内置数据类型使用Eigen的矩阵
  3. Eigen矩阵不支持自动类型提升,这和C++内建数据类型有较大差异。在C++程序中,我们可以把一个float数据和double数据相加、相乘,编译器会自动把数据类型转换为最合适的那种。而在Eigen中,出于性能的考虑,必须显示地对矩阵类型进行转换(示例里有错误示范)。而如果忘了,则会报错:“YOU MIXED DIFFERENT NUMERIC TYPES …"
  4. 同理,你需要保证矩阵维数的正确性。报错类型:“YOU MIXED MATRICES OF DIFFERENT SIZES”
  5. 大家可以去http://eigen.tuxfamily.org/dox-devel/modules.html学习更多的Eigen知识
  6. 最后一段比较了求逆与求QR分解的运行效率,朋友可以去对比一下差异。
  7. 广义上从运动来解释特征值就是速度,特征向量就是运动的方向。
  8. 矩阵上来解释特征值就是对特征向量进行伸缩或者旋转的度量(实数是伸缩,虚数是旋转,复数是伸缩加旋转),特征向量是在矩阵变换下只进行“规则”变换的向量,规则也就是特征值。
  9. QR分解也就是正交三角分解。

本博客内容整理自高博的《SLAM十四讲》,欢迎大家交流讨论。

你可能感兴趣的:(Eigen(安装与使用))