Eigen库完全教程——从入门到入魂

1.eigen库介绍

eigen库是C++中的线性代数库,实现了线性代数以及矩阵分析中所有计算方法。既然已经要学eigen库了,想必,线性代数的基本知识肯定是有的。如果你是做三维重建的,那么这个库必学。
另外,eigen库内部实现的操作基本都是高度优化的,计算顺序可能并不像我们平时计算那样从左到右,一般情况下,我们是不需要去管这个的。
eigen官方库使用官方教程链接: link

2.matrix对象创建

只有一个模板类Matrix,其他的所有数据类型3阶矩阵、2维向量等等都是由这个类模板定义的。如typedef Matrix<int,2,1> Vector2i;typedef Matrix<float,3,3> Matrix3f;

    //固定大小的矩阵
    Eigen::Matrix<int, 2, 2> mat1;
    Eigen::Matrix2i mat2;
    cout << "mat1:"<<endl<<mat1 << endl;
    cout << "mat2:" << endl<<mat2 << endl;
    //mat不支持构造时初始化,vec是可以构造时初始化
    mat2 << 1, 2,
        3, 4;
    cout << "输入值后,mat2:" << endl << mat2 << endl;
    Eigen::Vector2f vec2f(99.9, 88.8);
    cout << "输入值后,vec2f:" << endl << vec2f << endl;

    //如果支持C++11特性,则mat和vec都可以用列表初始化
    Eigen::MatrixXi dymat{{1, 2, 3}, { 4,5,6 }};
    cout << "dymat:" << endl << dymat << endl;

运行结果:
在这里插入图片描述

矩阵元素的访问

#include <iostream>
#include <Eigen/Dense>
 
int main()
{
  Eigen::MatrixXd m(2,2);
  m(0,0) = 3;
  m(1,0) = 2.5;
  m(0,1) = -1;
  m(1,1) = m(1,0) + m(0,1);
  std::cout << "Here is the matrix m:\n" << m << std::endl;
  Eigen::VectorXd v(2);
  v(0) = 4;
  v(1) = v(0) - 1;
  std::cout << "Here is the vector v:\n" << v << std::endl;
}

动态矩阵–即矩阵维度是不确定的

用Eigen::MatrixXi来定义(其实是Eigen::Matrix<int,dynamic,dynamic>)。动态矩阵时可以改变大小的resize函数。

    //如果支持C++11特性,则mat和vec都可以用列表初始化
    Eigen::MatrixXi dymat{{1, 2, 3}, { 4,5,6 }};
    cout << "dymat:" << endl << dymat << endl;
    cout << "行数:"<<dymat.rows() << endl;
    dymat.resize(3, 2);
    cout << "dymat:" << endl << dymat << endl;
    cout << "行数:" << dymat.rows() << endl;

注意:Eigen中矩阵的元素存储默认是列主序,即dymat在内存中是 1,4,2,5,3,6
在这里插入图片描述

可能有人会问,什么时候用动态矩阵。什么时候用固定矩阵?
这个没有必然的答案,只有更合适。比如,在你知道矩阵大小,且维度小于16的情况下,使用固定矩阵对于性能计算会更好。反之则使用动态矩阵。另外,动态矩阵是在堆上申请的,固定矩阵是在栈上申请的。

3.矩阵四则运算

eigen库通过运算符重载来实现类似于普通常数的四则运算,当然也有一些函数方法。注意: Eigen库不支持数据类型的自动提升,所以执行四则运算的矩阵必须是相同数据类型,可以使用cast()成员函数进行数据类型强转。

加减

    Eigen::Matrix2d a;
    a << 1, 2,
        3, 4;
    Eigen::MatrixXd b(2, 2);
    b << 2, 3,
        1, 4;
    std::cout << "a + b =\n" << a + b << std::endl;
    std::cout << "a - b =\n" << a - b << std::endl;
    std::cout << "Doing a += b;" << std::endl;
    a += b;
    std::cout << "Now a =\n" << a << std::endl;
    Eigen::Vector3d v(1, 2, 3);
    Eigen::Vector3d w(1, 0, 0);
    std::cout << "-v + w - v =\n" << -v + w - v << std::endl;

在这里插入图片描述

标量乘除

    Eigen::Matrix2d a{{1, 2}, { 3, 4 }};
    cout << a << endl;
    cout << "************" << endl;
    auto a1 = a * 2;
    auto a2 = a / 2;
    cout << a1 << endl;
    cout << "************" << endl;
    cout << a2 << endl;

在这里插入图片描述

矩阵乘除

    Eigen::Matrix2d a{{1, 2}, { 3, 4 }};
    Eigen::Matrix2d b = a.transpose();
    cout << "a:" << endl << a << endl;
    cout << "b:" << endl << b << endl;
    cout << "a*b:" << endl << a * b << endl;

    Eigen::Vector2d c(1, 1);
    cout << "a * b * c" << endl << a * b * c << endl;

在这里插入图片描述

内积和外积–dot、cross

    Eigen::Vector3d a(1, 1,1);
    Eigen::Vector3d b(3, 4,5);
    cout << "内积:" << a.dot(b) << endl;
    cout << "内积另一种计算:" << a.transpose()*b << endl;
    cout << "叉乘:" <<endl<< a.cross(b) << endl;

在这里插入图片描述

4. Array类实现逐元素的操作。类似于numpy中的广播机制。

只要记住是逐元素操作就行,其它的所有操作都跟Matrix差不多。

    Eigen::Array<int, 2, 3> a{{-1, -2, -1}, { 6,6,6 }};
    Eigen::Array<int, 2, 3> b{{2, 2, 2}, { 2,3,2 }};
    cout << "a:" << endl << a << endl;
    cout << "b:" << endl << b << endl;
    cout << "a+1:" << endl << a + 1 << endl;
    cout << "a+b:" << endl << a + b << endl;
    cout << "a*b:" << endl << a * b << endl;
    cout << "a的绝对值:" << a.abs() << endl;
    cout << "b的平方根:" << b.sqrt() << endl;
    cout << "返回a和b中对应元素位置最大的元素组成的array:" << endl << a.max(b) << endl;

在这里插入图片描述

5.矩阵块操作–block、()重载

    Eigen::MatrixXf m(4, 4);
    m << 1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16;
    //block方法返回值做右值
    auto t = m.block<2, 2>(1, 1);
    cout << t << endl;
    //左值
    m.block(1, 1, 2, 2) = Eigen::Array22f::Constant(0.5);
    cout << "m:\n" << m << endl;

在这里插入图片描述
注意: 块操作结果是可以作为左值的,即block函数返回的是引用。
取块的其他操作:

    Eigen::MatrixXf m(4, 4);
    m << 1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16;
    //block方法返回值做右值
    auto t = m.block<2, 2>(1, 1);
    cout << t << endl;
    //左值
    m.block(1, 1, 2, 2) = Eigen::Array22f::Constant(0.5);
    cout << "m:\n" << m << endl << endl;
    //取第2行
    cout << "第2行:" << m.row(1) << endl;
    //左上角2*3,并+1
    m.topLeftCorner(2, 3) = m.topLeftCorner(2, 3).array() + 1;
    cout << endl << "左上角+1后:\n" << m << endl;

在这里插入图片描述

6.切片-seq,seqN,lastN,all,其它数组

切片和块操作差不多,都支持左值和右值计算。不同的是,切片更灵活,切片得到的矩阵布局跟切片时输入的行列顺序一样。

    Eigen::MatrixXf m(4, 4);
    m << 1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16;
    //matrix的切片
    //用seq()生成数组
    cout << m(Eigen::seq(1, 2),Eigen::seq(0,1) ) << endl;
    cout << "********" << endl;
    //用seqN()生成间隔数组
    cout << m(Eigen::seqN(0, 2, 2), Eigen::last) << endl;
    cout << "********" << endl;
    //用一般的可遍历容器生成数组
    int col[2] = { 0,1 };
    cout << m(vector<int>{1, 2, 3}, col) << endl;
    cout << "********" << endl;
    //用lastN生成后面的数组
    cout << m(Eigen::lastN(2), Eigen::all) << endl;
    cout << "********" << endl;

在这里插入图片描述

    cout <<"m:\n"<< m << endl;
    cout << "********" << endl;
    //逆序切片
    cout << m(Eigen::seq(Eigen::last, 1, -1), vector<int>{1, 2}) << endl;
    //任意行列切片
    cout << "********" << endl;
    Eigen::Array3i ainx{1, 3, 2};
    cout << m(vector<int>{2, 1, 2}, ainx) << endl;

在这里插入图片描述

7.初始化的其它方法–用matrix初始化

    //用matrix来初始化,实现堆叠
    MatrixXi mat1(2, 2);
    mat1 << 1, 2, 3, 4;
    MatrixXi mat2(2, 3);
    mat2 << 1, 1, 1, 2, 2, 2;
    cout << "mat1:\n" << mat1 << endl;
    cout << "mat2:\n" << mat2 << endl;

    MatrixXi mat3(2, 5);
    mat3 << mat1, mat2;
    cout << "mat3:\n" << mat3 << endl;

    MatrixXi mat4(5, 5);
    mat4.row(0) << mat3.row(1);
    mat4.row(1).head(4) << 4, 4, 4, 4;
    mat4.row(1).tail(1) << 100;
    mat4.block(2, 0, 3, 5) << mat3, mat3.row(0);
    cout << "mat4:\n" << mat4 << endl;

在这里插入图片描述

8.常见的一些基本矩阵幅值

零矩阵、单位阵、常矩阵、随机矩阵

    //零矩阵
    MatrixXi mat1 = MatrixXi::Zero(2, 3);
    cout << "mat1:\n" << mat1 << endl;
    Matrix3i mat2 = Matrix3i::Zero();
    cout << "mat2:\n" << mat2 << endl;
    
    //常数矩阵
    MatrixXf mat3 = MatrixXf::Constant(2, 3, 6.6);
    cout << "mat3:\n" << mat3 << endl;
    
    //随机矩阵
    RowVectorXf vec1 = RowVector3f::Random();//-1~1随机浮点数
    cout << "vec1:\n" << vec1 << endl;

    //单位阵
    MatrixXi mat4 = Matrix3i::Identity();
    cout << "mat4:\n" << mat4 << endl;

在这里插入图片描述
分块的常见矩阵赋值or原地赋值操作

    const int size = 6;
    MatrixXd mat1(size, size);
    mat1.topLeftCorner(size / 2, size / 2) = MatrixXd::Zero(size / 2, size / 2);
    mat1.topRightCorner(size / 2, size / 2) = MatrixXd::Identity(size / 2, size / 2);
    mat1.bottomLeftCorner(size / 2, size / 2) = MatrixXd::Identity(size / 2, size / 2);
    mat1.bottomRightCorner(size / 2, size / 2) = MatrixXd::Zero(size / 2, size / 2);
    std::cout << mat1 << std::endl << std::endl;

    MatrixXd mat2(size, size);
    mat2.topLeftCorner(size / 2, size / 2).setZero();
    mat2.topRightCorner(size / 2, size / 2).setIdentity();
    mat2.bottomLeftCorner(size / 2, size / 2).setIdentity();
    mat2.bottomRightCorner(size / 2, size / 2).setZero();
    std::cout << mat2 << std::endl << std::endl;

    MatrixXd mat3(size, size);
    mat3 << MatrixXd::Zero(size / 2, size / 2), MatrixXd::Identity(size / 2, size / 2),
        MatrixXd::Identity(size / 2, size / 2), MatrixXd::Zero(size / 2, size / 2);
    std::cout << mat3 << std::endl;

在这里插入图片描述

  • 9
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值