Eigen库

前言

  最近在学习计算机图形学的一些知识,里面要大量运用像矩阵运算这样的线性代数知识,而Eigen库就是一个支持我们用c++语言进行线性代数、矩阵和矢量运算的第三方库。想着后续真正开始写代码后这个库用的应该挺多的,于是就先来简单学习一下这个库。另外学习这个之前最好还是先了解一点线性代数相关的知识,不然一些核心概念也是不好理解的,大概知道什么是矩阵、什么是向量、以及矩阵运算的一些知识和性质就差不多了。

 开始

  首先我们需要去官网下载这个第三方库,下载完成后解压会得到完整的目录,就比我我放在了E盘下的c++ku目录,现在我们记下这个目录地址E:\c++ku\eigen-3.4.0,这里我都IDE使用的是Visusl Studio2019,我们新建一个项目,右键项目根目录选择属性选项。

然后把配置和平台选项都改为所有配置所有平台。最后配置属性一栏选择VC++目录,右侧找到包括目录选项,在里面新增我们刚才的Eigen库的目录即可。

  然后我们就可以正常在这个项目中引入使用了。

  进入目录我们会发现这个库中有许多模块,如下图所示。

 这是一些主要模块的内容和作用,因为我们这里只是简单学习一下这个库的基本使用,不会深入讲解,所以只涉及到Core模块,讲解一下里面的矩阵运算。

Matrix类

矩阵创建

  这个类里面主要包含了Matrix(矩阵)和Vector(向量),其实向量也可以看做特殊的矩阵,看作是只有一行或者一列的矩阵。我们首先来看看Matrix模板类,我们创建过程中需要指定一些参数:

  1.第一个参数是指明数据类型,和数组道理一样,我们要说明矩阵里存放的什么类型的数据(比如int,float,double等)

  2.第二个参数是指明行数,可以写一个整数表示具体行数,也可以写Dynamic,表示不确定大小动态创建。

  3.第三个参数是指明列数,和行数一样,可以指明列数也可以动态创建。

Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>

  下面就看一段示例代码。

#include<iostream>
#include<Eigen/Core>
using namespace std;
//定义一个3x3的int类型的矩阵
typedef Eigen::Matrix<int, 3, 3> M33;
//定义一个不确定行和列的int类型的矩阵
typedef Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> MDD;

int main()
{
	//可以像数组那样用大括号赋值
	M33 m1{
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};
	cout<<"m1:3x3"<<endl << m1 << endl;

	//可以用重载后的 << 符号复制
	M33 m2;
	m2 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
	cout << "m2:3x3" << endl << m2 << endl;


	MDD m3{
		{1,2,3,4},
		{2,3,4,5},
		{3,4,5,6},
	};
	cout << "m3:3x4" << endl << m3 << endl;

	//如果是动态创建的,用这种写法创建一个矩阵时必须指定大小,不然无法创建这个矩阵
	MDD m4(3, 4);
	m4 << 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6;
	cout << "m4:3x4" << endl << m4 << endl;

	return 0;
}

  运行结果如上图所示,可以看到我们成功的创建了矩阵并且输出出来,Eigen库对<<>>符号进行了重载,所以我们可以直接用来对矩阵输入输出操作。

  上面的代码展示了两种比较常用的赋值方法,另外要强调的是,一个矩阵声明之后是没有初始化的,所以矩阵声明之后必须初始化后才能使用。

  另外我们还可以对矩阵的元素进行读取和修改。

#include<iostream>
#include<Eigen/Core>
using namespace std;
//定义一个3x3的int类型的矩阵
typedef Eigen::Matrix<int, 3, 3> M33;
//定义一个不确定行和列的int类型的矩阵
typedef Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> MDD;

int main()
{
	//如果是动态创建的,用这种写法创建一个矩阵时必须指定大小,不然无法创建这个矩阵
	MDD m4(3, 4);
	m4 << 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6;
	cout << "m4:3x4" << endl << m4 << endl;
	cout << "m4(0,0)=" << m4(0, 0) << endl;//获取矩阵元素
	m4(0, 0) = 0;//修改矩阵元素
	cout << "m4:3x4" << endl << m4 << endl;
	cout << "m4(0,0)=" << m4(0, 0) << endl;

	return 0;
}

  我们可以通过m(r,c)的形式获取到矩阵中的任意元素,并进行修改。下图中可以看到我们以及成功的修改了矩阵中的元素的值。

矩阵运算

  库中重载了 +、-、*、/等基本的四则运算,可以支持矩阵之间运算和矩阵与数字运算,但是不能直接将两个矩阵相除,矩阵可以除以一个常数。

#include<iostream>
#include<Eigen/Core>
using namespace std;
//定义一个3x3的int类型的矩阵
typedef Eigen::Matrix<int, 3, 3> M33;
//定义一个不确定行和列的int类型的矩阵
typedef Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> MDD;

int main()
{
	//可以像数组那样用大括号赋值
	M33 m1{
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};

	M33 m2{
	{2,2,2},
	{2,2,2},
	{2,2,2}
	};

	cout << "m1+m2=" << endl << m1 + m2 << endl;
	cout << "m1-m2=" << endl << m1 - m2 << endl;
	cout << "m1*m2=" << endl << m1 * m2 << endl;
	cout << "m1/m2=" << endl << m2/ 2 << endl;

	return 0;
}

Vector类

    我们可以把向量看做特殊的矩阵,这个矩阵只有一行或者一列。所以我们既可以用上面的Matrix模板类创建向量,只需要设置行或者列为1即可,也可以用Vector模板类创建向量。

#include<iostream>
#include<Eigen/Core>
using namespace std;

//通过Vecort模板类创建
typedef Eigen::Vector<int, 3> V3;
//通过Matrix模板创建
typedef Eigen::Matrix<int, 1, 3> MV3;

int main()
{
	V3 v1;
	v1 << 1, 2, 3;
	cout << "v1=" << endl << v1 << endl;

	MV3 mv1;
	mv1 << 2, 3, 4;
	cout << "mv1=" << endl << mv1 << endl;

	//用封装好的创建
	Eigen::Vector2i v;
	v << 1, 2;
	cout << "v=" << endl << v << endl;

	return 0;
}

  另外库里面也有已经封装好的一些类型,就比如代码中用到的Vector2i,就表示int类型的2维向量。类似的封装还有很多,矩阵中也有封装好的类型,大家可以自行查看,这里不再过多叙述。

Array类

  Eigen库还为我们提供了Array模板类,在矩阵运算中加减操作只能是矩阵之间的运算,一个矩阵不能加或者减一个数字,这可能会导致矩阵运算不能完全满足我们的需求,因此有了这么一个类。他的加减乘除运算只是数字意义上的运算,并不是前面的线性运算,比如两个矩阵相乘的结果是两个矩阵相同位置的元素相乘,和矩阵相乘结果并不相同,而且还可以直接对数字进行加减运算,比如Array加上2,结果就是里面所有元素都加2。

  其创建方式和矩阵一样,同样需要指定数据类型,行数和列数。

Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
#include<iostream>
#include<Eigen/Core>
using namespace std;

typedef Eigen::Array<int, 3, 3> Ai3;

int main()
{
	Ai3 a1{
		{1,2,3},
		{2,3,4},
		{3,4,5}
	};

	Ai3 a2{
	{2,2,2},
	{2,2,2},
	{2,2,2}
	};

	cout << "a1+a2=" << endl << a1 + a2 << endl;
	cout << "a1+2=" << endl << a1 + 2 << endl;
	cout << "a1*a2=" << endl << a1 * a2 << endl;
	cout << "a1/a2=" << endl << a1 / a2 << endl;


	return 0;
}

  同样里面也有封装好的供我们直接使用的类型,这里不再过多叙述。

posted @ 2024-01-16 16:52  小明同学404  阅读(82)  评论(0编辑  收藏  举报