Eigen 学习笔记

Eigen是一个C++开源库,支持线性代数,矩阵运算,数值分析,矢量计算等一系列算法,方便使用者实现一些复杂的运算

Eigen  头文件说明如下:

 

部分函数用法:

MatrixXd : 定义一个二维矩阵,行列未知,初始化时需指定数组的行和列(double型)

Matrix2cf:定义2x2的方阵(复数,float型)

Matrix2f :定义2x2的方阵(float型)
Matrix2i: 定义2x2的方阵(int型)
Matrix2Xf : 定义2行N列的矩阵(float型,N值不确定)
 
数字代表nn方阵的大小,‘X’代表这个矩阵不是方阵,是一个mn的矩阵,‘d’代表double,‘f’代表float, ‘i’代表整数,‘c’代表complex,即复数;
 
简单用法:
1、数据初始化与访问
 MatrixXf tmp = MatrixXf::Random(3,4);   //定义3x4的float型的随机数矩阵
 cout<<"tmp:\n"<<tmp<<endl;

 

 

 Matrix4f result = Matrix4f();  //定义一个4*4的 float 的方阵
 result(0,1)=1;  //单个元素访问赋值
 cout<<"result\n"<<result<<endl;

 

 

 Matrix2Xd res= Matrix2Xd(2,3);  //初始化一个2行n列的数组,第一个参数必须是2,否则报错
 cout<<"res\n"<<res<<endl<<" res.szie:"<<res.size()<<" " <<"res.row\\col:"<<res.rows()<<","<<res.cols()<<endl;
 //res.size() 返回的是总的元素个数,不是矩阵的shape (获取行列用res.rows(),res.cols())

 

  MatrixXd m = MatrixXd::Constant(7, 7, 0); //初始化一个矩阵7*7 初始值全为0
  cout << "EigenMat:" << endl << m << endl;
  m(1,1) =1; //直接访问修改
  m(2,2) = m(0,0)+m(0,1); //矩阵元素做加法
  cout << "EigenModify:" << endl << m << endl;
  MatrixXd m1 = MatrixXd::Random(3, 3);  //初始化3*3 大小的随机矩阵,范围都在(-1,1)之间
  m1 = (m1 + MatrixXd::Constant(3, 3, 2)) * 50;  //将m1每个元素加上常数2再乘50,随机数会变为(50,150)之间

 

 

 

 

2、元素级操作(取绝对值,开方),将Matrix矩阵与常数比较

 float th =0.2;  //比较阈值
 MatrixXf p1= MatrixXf::Constant(3, 4, 0.5);  //定义一个3*4的常量数组0.5
 cout<<"tmparr: \n"<<tmp.array()<<endl<<"sqrt(temp):\n"<<sqrt(abs(tmp.array()))<<endl;//元素级别操作需要转换到array ,这里的tmp 上面已经定义过
 cout<<p1.array().min(tmp.array().abs().sqrt())<<endl;   //返回p1和tmp.abs().sqrt()两个数组中对应元素较小的那个值(这里即将所有元素和0.5进行比较,取小的值)
 MatrixXf p2 = p1.array().min(tmp.array().abs().sqrt()).matrix(); //将得到的比较结果转换回MatrixXf类型
 cout<<"p2 -MatrixXf\n"<<p2<<endl;
 auto mapp = tmp.array()>th; //将整个矩阵和某个阈值比较,满足条件,返回1,否者返回0
 cout<<"mapp:\n"<<mapp<<endl;

 

 

3、tensor 定义及操作,Matrix转换成Tensor

Eigen::Tensor<float,2> pd1(3,4); //定义一个3*4的tensor ,2代表维度
 pd1(0,2) = 3;
 pd1(1,2) = 4;
 auto cmp = pd1>2;   //auto自动接收类型 找出pd1中值大于2的元素,其余值赋0 ,tensor可以直接和常数比较,Matrix 不行,需要先转成array
 cout<<"pd1: \n"<<pd1<<endl;
 Eigen::Tensor<float, 2> cmp2 = cmp.cast<float>();  //有文档说需要实例化变量类型转换一下,否则会编译报错(不过我这里直接输出cmp也是可以的)
 cout<<"cmp: \n"<<cmp<<endl;    //直接输出比较矩阵
 cout<<"cmp2: \n"<<cmp2<<endl;   //将auto 转换为 Tensor<float,2> 2维张量输出

 

 

Matrix矩阵转换成tensor (TensorMap)
TensorMap<Tensor<float,2>> MatrixXtoTensor(tmp.data(),3,4);//将MatrixXf 转换为3*4的二维tensor 
cout<<"MatrixXtoTensor :\n"<<MatrixXtoTensor<<endl;

 

4、向量初始化与操作,向量转换成tensor 或 Matrix

VectorXd v(3);//初始化一条向量(长度为3)
v<<1,2,3;
cout<<"v:\n"<<v<<endl;
  
Vector3f v1(5.5,4.3,6.7);//定义三行1列的向量,数据个数要和变量类型对应上
cout<<"v1= "<<v1<<endl;
auto eigenTensorMap =TensorMap<Tensor<float, 2, Eigen::RowMajor>> (v1.data(), 2,2); //将vector v1 转换成2*2的Tensor   行优先,不足的元素,会自动填充
cout<<"eigenTensorMap RowMajor: \n"<<eigenTensorMap<<endl;
auto eigenTensorMap1 =TensorMap<Tensor<float, 2, Eigen::ColMajor>> (v1.data(), 2,2);//将vector v1 转换成2*2的Tensor  列优先 ,不足的元素,会自动填充
cout<<"eigenTensorMap ColMajor: \n"<<eigenTensorMap1<<endl;
auto eigenMap = Eigen::Map<MatrixX<float>> (v1.data(), 3,3); //将vector v1转换为MatrixX类型 3*3的
cout<<"eigenMap :\n"<<eigenMap<<endl;

 

 

5、Opencv::Mat 与 Eigen::MatrixX 互相转换 ,Matrix数据块操作  
注意:头文件顺序不能写反,否则编译失败

#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
 cv::Mat ImageMat, OutPutMat;
 ImageMat =  cv::imread("D:/pic/test.png", 0);
 cv::imshow("原图", ImageMat);
 cv::waitKey(0);
 
 Mat Min=Mat(round(ImageMat.rows*0.1),round(ImageMat.cols*0.1),CV_16S);  //定义缩小后的图片大小  short型16bit
 cv::Size dsize = cv::Size(Min.rows,Min.cols); // cv::Size 定义
 cv::resize(ImageMat,Min,dsize,0.1,0.1);   //resize ImageMat大小变为1/10,行、列分别缩小1/10
 imshow("min",Min);
 cv::waitKey(0);
 
Eigen::MatrixXd Matrixs(Min.rows, Min.cols);
cv2eigen(Min, Matrixs);  //将缩小后的图像Min 转换为eigen::MatrixXd
cout<<"cv2eigen:"<<endl<<Min<<endl;  //如下所示为行列各缩小为1/10 后的图像数据

 

 

 MatrixXd mmm = MatrixXd::Constant(30,30,0); //定义30*30的0矩阵
 mmm(1,1)=1;
 mmm(1,2)=1;
 mmm(2,1)=1;
 mmm(2,2)=1 ;
 mmm.block(3,3,10,10) = MatrixXd::Constant(10,10,1);  //块操作 以(3,3)为起点(左上角点),10x10块区域内赋值常数1
 mmm.block<4,4>(15,15) = MatrixXd::Constant(4,4,1);   //和上面一样也是块操作,另一种表达方式,以(15,15)为起点,4x4区域内赋值常数1
 cv::Mat cvm = Mat(30, 30, CV_8U); //定义Mat大小,接收数据
 eigen2cv(mmm, cvm);      
 imshow("cvm",cvm);
 waitKey(0);
 cout << "cvMat:" << endl << cvm << endl;
如下图所示在30*30区域内显示为白色的,就是修改为1的部分。

 

 

 

 

 6、Matrix 行列单独操作, 矩阵边角矩阵获取(左上,右下,前N行,后N列)

MatrixXd tt = MatrixXd::Constant(4,4,1);
tt.row(1)+= tt.row(2);
cout<<"行列操作:\n"<<tt<<endl;
//边角子矩阵提取 左上角:topLeftCorner(p,q) 左下角:bottomLeftCorner(p,q) 右上角:topRightCorner(p,q) 右下角:topRightCorner(p,q)
//前p行:topRows(p)  后p行:bottomRows(p)   前q列:leftCols(q)  后q列:leftCols(q)
cout<<"tt左上(2,2):\n"<<tt.topLeftCorner(2,2)<<"\ntt前两行:\n"<<tt.topRows(2)<<endl;

 

 

7、切片操作,向量vector和Matrix矩阵切片都是通过 Map 实现   (Eigen默认采用列主导(column major)的数据存储形式)

    RowVectorXf p = RowVectorXf::LinSpaced(20,0,19);  //行向量  长度20,范围[0,19]
    cout << "Input:" << endl << p << endl;
    Map<RowVectorXf,0,InnerStride<2> > v2(p.data(), p.size()/2);  //步长为2进行获取 v.data() 长度为v.size/2  
    //参数0代表数据对其格式,参数InnerStride代表沿着数据存储的方向间隔2步长取值
    cout << "Even:" << v2 << endl;
 
    MatrixXf M1 = MatrixXf::Random(3,8);    //默认存储方式列优先
    //innerStride既表示沿着矩阵的数据存储方向移动一个元素的位置,在内存中需要移动的次数。outerStride的含义就是不沿着数据存储方向移动一个位置,在内存中需要移动的次数
    cout << "Column major input:" << endl << M1 << "\n";
    cout<<"innerStride="<<M1.innerStride()<<endl;  
    cout<<"outerstride=" <<M1.outerStride()<<endl;
    Map<MatrixXf,0,OuterStride<> > M2(M1.data(), M1.rows(), (M1.cols()+2)/3,OuterStride<>(M1.outerStride() * 3));
    //代表 将M1矩阵的元素映射到M2,行不变,列为间隔3列取,在M1上取元素需要在行方向上一次移动步长为原来的3倍(因为是列优先存储的,间隔9个才取下一列)
    cout << "间隔3列切片 M2" << endl << M2 << endl;

 

 

 


 

 

 

 

posted @ 2022-12-18 22:08  victorywr  阅读(1376)  评论(0编辑  收藏  举报