強(qiáng)大的C++矩陣處理庫-Eigen

Eigen介紹

Eigen是可以用來進(jìn)行線性代數(shù)、矩陣、向量操作等運(yùn)算的C++庫,它里面包含了很多算法。它的License是MPL2。它支持多平臺。使用類似Matlab的方式操作矩陣,單純講和Matlab的對應(yīng)的話,可能不如Armadillo(http://arma.sourceforge.net/)對應(yīng)的好,但功能絕對強(qiáng)大。
Eigen包含了絕大部分你能用到的矩陣算法,同時(shí)提供許多第三方的接口。Eigen一個(gè)重要特點(diǎn)是采用源碼的方式提供給用戶使用,在使用時(shí)只需要包含Eigen的頭文件即可進(jìn)行使用。之所以采用這種方式,是因?yàn)镋igen采用模板方式實(shí)現(xiàn),由于模板函數(shù)不支持分離編譯,所以只能提供源碼而不是動(dòng)態(tài)庫的方式供用戶使用,因此非常輕量而易于跨平臺。你要做的就是把用到的頭文件和你的代碼放在一起就可以了。

Eigen的一些特性:

  • 支持整數(shù)、浮點(diǎn)數(shù)、復(fù)數(shù),使用模板編程,可以為特殊的數(shù)據(jù)結(jié)構(gòu)提供矩陣操作。比如在用ceres-solver進(jìn)行做優(yōu)化問題(比如bundle adjustment)的時(shí)候,有時(shí)候需要用模板編程寫一個(gè)目標(biāo)函數(shù),ceres可以將模板自動(dòng)替換為內(nèi)部的一個(gè)可以自動(dòng)求微分的特殊的double類型。而如果要在這個(gè)模板函數(shù)中進(jìn)行矩陣計(jì)算,使用Eigen就會非常方便。
  • 支持逐元素、分塊、和整體的矩陣操作。
  • 內(nèi)含大量矩陣分解算法包括LU,LDLt,QR、SVD等等。
  • 支持使用Intel MKL加速
  • 部分功能支持多線程
  • 稀疏矩陣支持良好,到今年新出的Eigen3.3,已經(jīng)自帶了SparseLU、SparseQR、共軛梯度(ConjugateGradient solver)、bi conjugate gradient stabilized solver等解稀疏矩陣的功能。同時(shí)提供SPQR、UmfPack等外部稀疏矩陣庫的接口。
  • 支持常用幾何運(yùn)算,包括旋轉(zhuǎn)矩陣、四元數(shù)、矩陣變換、AngleAxis(歐拉角與Rodrigues變換)等等。
  • 更新活躍,用戶眾多(Google、WilliowGarage也在用),使用Eigen的比較著名的開源項(xiàng)目有ROS(機(jī)器人操作系統(tǒng))、PCL(點(diǎn)云處理庫)、Google Ceres(優(yōu)化算法)。OpenCV自帶到Eigen的接口。
    總體來講,如果經(jīng)常做一些比較復(fù)雜的矩陣計(jì)算的話,或者想要跨平臺的話,非常值得一用。

Eigen是C++中可以用來調(diào)用并進(jìn)行矩陣計(jì)算的一個(gè)庫,里面封裝了一些,需要的頭文件和功能如下:

Eigen的主頁上有一些更詳細(xì)的Eigen介紹。

Eigen的下載

這里是官網(wǎng)主頁,可自行下載需要的版本,是個(gè)code包,不用安裝。

Eigen的配置

這里以VS2015為例,C/C++ -> Additional Include Directories填上Eigen解壓文件夾的位置即可,也可將文件夾放在Solution目錄下,寫作:$(SolutionDir)\eigen3

Eigen:矩陣(Matrix)類的介紹及使用

在Eigen中,所有矩陣和向量均為Matrix模板類的對象,向量是矩陣的行(或列)為1是的特殊情況。

1、矩陣的三參數(shù)模板
Matrix類有六個(gè)模板參數(shù),其中三個(gè)有默認(rèn)值,因此只要學(xué)習(xí)三個(gè)參數(shù)就足夠了。

/* 強(qiáng)制性的三參數(shù)模板的原型 (三個(gè)參數(shù)分別表示:標(biāo)量的類型,編譯時(shí)的行,編譯時(shí)的列) */
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> 

/* 用typedef定義了很多模板,例如:Matrix4f 表示 4×4 的floats 矩陣 */ 
typedef Matrix<float, 4, 4> Matrix4f;

2、向量(Vectors)
向量是矩陣的特殊情況,也是用矩陣定義的。

typedef Matrix<float, 3, 1> Vector3f;  
typedef Matrix<int, 1, 2> RowVector2i;

3、特殊動(dòng)態(tài)值(special value Dynamic)
Eigen的矩陣不僅能夠在編譯是確定大?。╢ixed size),也可以在運(yùn)行時(shí)確定大小,就是所說的動(dòng)態(tài)矩陣(dynamic size)。

typedef Matrix<double, Dynamic, Dynamic> MatrixXd;  
typedef Matrix<int, Dynamic, 1> VectorXi;  

/* 也可使用‘行’固定‘列’動(dòng)態(tài)的矩陣 */
Matrix<float, 3, Dynamic>

4、構(gòu)造函數(shù)(Constructors)
可以使用默認(rèn)的構(gòu)造函數(shù),不執(zhí)行動(dòng)態(tài)分配內(nèi)存,也沒有初始化矩陣參數(shù):

Matrix3f a;   // a是3-by-3矩陣,包含未初始化的 float[9] 數(shù)組
MatrixXf b;   // b是動(dòng)態(tài)矩陣,當(dāng)前大小為 0-by-0, 沒有為數(shù)組的系數(shù)分配內(nèi)存

/* 矩陣的第一個(gè)參數(shù)表示“行”,數(shù)組只有一個(gè)參數(shù)。根據(jù)跟定的大小分配內(nèi)存,但不初始化 */
MatrixXf a(10,15);    // a 是10-by-15陣,分配了內(nèi)存,沒有初始化
VectorXf b(30);       // b是動(dòng)態(tài)矩陣,當(dāng)前大小為 30, 分配了內(nèi)存,沒有初始化

/* 對于給定的矩陣,傳遞的參數(shù)無效 */
Matrix3f a(3,3); 

/* 對于維數(shù)最大為4的向量,可以直接初始化 */
Vector2d a(5.0, 6.0);  
Vector3d b(5.0, 6.0, 7.0);  
Vector4d c(5.0, 6.0, 7.0, 8.0);

5、系數(shù)訪問
系數(shù)都是從0開始,矩陣默認(rèn)按列存儲

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

int main()
{
    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);
    cout << "Here is the matrix m:" << endl;
    cout << m << endl;

    VectorXd v(2);
    v(0) = 4;
    v[1] = v[0] - 1;     //operator[] 在 vectors 中重載,意義和()相同
    cout << "Here is the vector v:" << endl;
    cout << v << endl;

    getchar();
    getchar();
}

6、逗號分隔的初始化

Matrix3f m;
m << 1, 2, 3,   4, 5, 6,   7, 8, 9;
cout << m;

7、Resizing
可以用rows(), cols() and size() 改變現(xiàn)有矩陣的大小。這些類方法返回行、列、系數(shù)的數(shù)值。也可以用resize()來改變動(dòng)態(tài)矩陣的大小。

test代碼

#include <iostream>  
#include "Eigen/Eigen"  
using namespace std;  
using namespace Eigen;  
  
void foo(MatrixXf& m)  
{  
    Matrix3f m2=Matrix3f::Zero(3,3);  
    m2(0,0)=1;  
    m=m2;  
}  
int main()  
{  
    /* 定義,定義時(shí)默認(rèn)沒有初始化,必須自己初始化 */  
    MatrixXf m1(3,4);   //動(dòng)態(tài)矩陣,建立3行4列。  
    MatrixXf m2(4,3);   //4行3列,依此類推。  
    MatrixXf m3(3,3);  
    Vector3f v1;        //若是靜態(tài)數(shù)組,則不用指定行或者列  
    /* 初始化 */  
    m1 = MatrixXf::Zero(3,4);       //用0矩陣初始化,要指定行列數(shù)  
    m2 = MatrixXf::Zero(4,3);  
    m3 = MatrixXf::Identity(3,3);   //用單位矩陣初始化  
    v1 = Vector3f::Zero();          //同理,若是靜態(tài)的,不用指定行列數(shù)  
  
    m1 << 1,0,0,1,        //也可以以這種方式初始化  
        1,5,0,1,  
        0,0,9,1;  
    m2 << 1,0,0,  
        0,4,0,  
        0,0,7,  
        1,1,1;  
      
    /* 元素的訪問 */  
    v1[1] = 1;  
    m3(2,2) = 7;  
    cout<<"v1:\n"<<v1<<endl;  
    cout<<"m3:\n"<<m3<<endl;  
    /* 復(fù)制操作 */  
    VectorXf v2=v1;             //復(fù)制后,行數(shù)與列數(shù)和右邊的v1相等,matrix也是一樣,  
                                //也可以通過這種方式重置動(dòng)態(tài)數(shù)組的行數(shù)與列數(shù)  
    cout<<"v2:\n"<<v2<<endl;  
  
    /* 矩陣操作,可以實(shí)現(xiàn) + - * / 操作,同樣可以實(shí)現(xiàn)連續(xù)操作(但是維數(shù)必須符合情況), 
    如m1,m2,m3維數(shù)相同,則可以m1 = m2 + m3 + m1; */  
    m3 = m1 * m2;  
    v2 += v1;  
    cout<<"m3:\n"<<m3<<endl;  
    cout<<"v2:\n"<<v2<<endl;  
    //m3 = m3.transpose();  這句出現(xiàn)錯(cuò)誤,估計(jì)不能給自己賦值  
    cout<<"m3轉(zhuǎn)置:\n"<<m3.transpose()<<endl;  
    cout<<"m3行列式:\n"<<m3.determinant()<<endl;  
    m3 = m3.inverse();  
    cout<<"m3求逆:\n"<<m3<<endl;  
  
    system("pause");  
  
    return 0;  
}  

本文同時(shí)發(fā)布在個(gè)人主頁fangda.me上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容