Home [데브코스] 17주차 - Visual-SLAM Eigen tutorial
Post
Cancel

[데브코스] 17주차 - Visual-SLAM Eigen tutorial


Eigen tutorial

참고 자료 : Eigen 사이트 공식 문서


1. Simply Class

Eigen 사이트 공식 문서 reference guide

  • Matrix2f, Matrix2d, Matrix3f, Matrix3d, MatrixXd …
  • Vector2f, Vector2d, Vector3f, Vector3d, VectorXd …


Vector와 Matrix의 사용 형태는 거의 동일하니 Matrix에 대해서만 다루려고 한다. 기본적인 변수 선언은 다음과 같다. Zero를 통해 0으로 구성된 Matrix를 구성할 수 있고, Random을 통해 무작위의 값으로 구성할 수 있다.

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <Eigen/Dense>

int main()
{
  Eigen::Matrix3d m1 = Eigen::Matrix3d::Zero();
  Eigen::MatrixXd m2 = Eigen::MatrixXd::Zero(3,3);
  Eigen::Matrix2f m3 = Eigen::Matrix2f::Random();
  Eigen::MatrixXf m4 = Eigen::Matrix2f::Random(2,2);
}


이런 Matrix에서의 element를 참조하는 방법은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
  m1(0, 1) = 3;
  m1(2, 2) = 9;

  std::cout << m1 << std::endl;
  

  std::cout << "\n m4 before : \n" << m4 << std::endl;
  
  m4(1,1) = m4(0,0) + m4(0,1);
  
  std::cout << "\n m4 after : \n" << m4 << std::endl;
}

/*
0 3 0
0 0 0
0 0 9


 m4 before :
 0.823295 -0.329554
-0.604897  0.536459

 m4 after :
 0.823295 -0.329554
-0.604897   0.49374
*/


추가적인 사용방법은 아래 표와 같다.


matrix나 vector에 값을 입력할 때는 comma initializer(<<)를 사용하면 편하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
    Eigen::Matrix3d intrinsic_matrix = Eigen::Matrix3d::Zero();

    intrinsic_matrix << 422.037858, 0.0,        245.895397,
                        0.0,        435.589734, 163.625535,
                        0.0,        0.0,        1.0;

    std::cout << intrinsic_matrix << std::endl;
}
/*  
422.037858 0.0        245.895397
0.0        435.589734 163.625535
0.0        0.0        1.0
*/

추가적인 것들은 공식 문서를 참고하길 바란다.



Eigen - Linear Algebra


linear algebra - linear solver - [https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html](https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html) - SVD - [https://eigen.tuxfamily.org/dox/group__LeastSquares.html](https://eigen.tuxfamily.org/dox/group__LeastSquares.html) - sparse matrix - [https://eigen.tuxfamily.org/dox/group__TutorialSparse.html](https://eigen.tuxfamily.org/dox/group__TutorialSparse.html) - [https://eigen.tuxfamily.org/dox/group__TopicSparseSystems.html](https://eigen.tuxfamily.org/dox/group__TopicSparseSystems.html) - [https://eigen.tuxfamily.org/dox/group__SparseQuickRefPage.html](https://eigen.tuxfamily.org/dox/group__SparseQuickRefPage.html)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//
// Created by dkssu on 2022-06-12.
//
// reference : https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html

#include <iostream>
#include <Eigen/Dense>

void linear_solve()
{
    // 1. Ax = b ( ColPivHouseholderQr solver )
    // refence : https://eigen.tuxfamily.org/dox/classEigen_1_1ColPivHouseholderQR.html
    // performs rank-revealing QR decomposition of matrix A, permutation matrix P, unitary matrix Q, upper triangular matrix R
    // A P = Q R
    // this decomposition performs column pivoting in order to be rank-revealing
    Eigen::Matrix3f A = Eigen::Matrix3f::Zero();
    Eigen::Vector3f b = Eigen::Vector3f::Zero();

    A << 1,2,3,
         4,5,6,
         7,8,10;
    b << 3, 3, 4;

    Eigen::Vector3f x = A.colPivHouseholderQr().solve(b);
    std::cout << "colpivhouseholderQr solution is : \n" << x << std::endl;

    // we can predefine decomposition constructor size
    Eigen::HouseholderQR<Eigen::MatrixXf> qr(50,50);
    Eigen::MatrixXf p = Eigen::MatrixXf::Random(50, 50);
    qr.compute(p); // no dynamic memory allocation



    // 2. Ax = b ( LDLT )
    Eigen::Matrix2f A2, b2;
    A2 << 2, -1,
          -1, 3;
    b2 << 1, 2,
          3, 1;

    Eigen::Matrix2f x2 = A2.ldlt().solve(b2);
    std::cout << "LDLT solution is : \n" << x2 << std::endl;
};



/*
 this is describes how to solve linear least squares systems using Eigen. define Ax = b, has no solution.
 it makes to search for the vector x which is closest to being a solution in the difference Ax - b is as small as possible.
 if Euclidean norm is used, x is called the least square solution.
 */
void least_squares()
{
    // Ax = b ( normal equations - A_T * A * x = A^T * b )
    Eigen::MatrixXf A = Eigen::MatrixXf::Random(3, 2);
    Eigen::VectorXf b = Eigen::VectorXf::Random(3);
    Eigen::VectorXf x = (A.transpose() * A).ldlt().solve(A.transpose() * b);
    std::cout << "The solution using normal equations is : \n" << x << std::endl;

    /*
     ldlt perform a robust 'Cholesky decomposition' of positive or negative matrix A such that A = P^T * L * D * L * P
     where, permutation matrix P, lower triangular matrix(하삼각행렬) with unit diagonal L, diagonal matrix D

     cholesky decomposition are not rank-revealing.

     because using ldlt() instead of LU is lower computation. L^T is upper triangular matrix(상삼각행렬), so U convert to DL^T in 'A = LU'
     therefore, exists lower triangular matrix L, symmetric matrix D for symmetric matrix A
     reference : https://freshrimpsushi.github.io/posts/ldu-decomposition-of-symmetric-matrix/
     */




    // Ax = b ( SVD decomposition - BDCSVD )
    Eigen::MatrixXf svd_A = Eigen::MatrixXf::Random(3, 2);
    Eigen::VectorXf svd_b = Eigen::VectorXf::Random(3);
    std::cout << "Here is the matrix A : \n" << svd_A << "\n"
        << "Here is the right side vector b : \n" << svd_b << std::endl;
    std::cout << "The least squares solution is : \n"
        << svd_A.template bdcSvd<Eigen::ComputeThinU | Eigen::ComputeThinV>().solve(svd_b) << std::endl;





    // Ax = b ( QR decomposition )
    Eigen::MatrixXf qr_A = Eigen::MatrixXf::Random(3, 2);
    Eigen::MatrixXf qr_b = Eigen::VectorXf::Random(3);
    Eigen::MatrixXf qr_x = qr_A.colPivHouseholderQr().solve(qr_b);
    std::cout << "The solution using the QR decomposition is : \n" << qr_x << std::endl;




    // Ax = b ( fullPivLu ) -> check if matrix is singular
    Eigen::MatrixXd fullLu_A = Eigen::MatrixXd::Random(100, 100);
    Eigen::MatrixXd fullLu_b = Eigen::MatrixXd::Random(100, 50);
    Eigen::MatrixXd fullLu_x = fullLu_A.fullPivLu().solve(fullLu_b);
    double relative_error = ( fullLu_A * fullLu_x - fullLu_b ).norm() / fullLu_b.norm(); // norm is L2 norm
    std::cout << "the relative error is : \n" << relative_error << std::endl;




    // Ax = b ( LLT ) -> separate computation , all decompositions have a compute(matrix) method that does the computation, and that can called again on an already-computed decomposition
    Eigen::Matrix2f llt_A, llt_b;
    Eigen::LLT<Eigen::Matrix2f> llt; // predefine size to the decomposition constructor
    llt_A << 2, -1,
             -1, 3;
    llt_b << 1, 2,
             3, 1;

    // computing LLT decomposition
    llt.compute(llt_A);
    std::cout << "The solution is:\n" << llt.solve(llt_b) << std::endl;

    // +1 at (1,1) in A3 matrix
    llt_A(1,1)++;
    llt.compute(llt_A);
    std::cout << "The solution is:\n" << llt.solve(llt_b) << std::endl;
};


This post is licensed under CC BY 4.0 by the author.