画像処理・CVに関するメモ

画像処理、コンピュータビジョン、時系列データとかに興味があります

Eigen、 Sophusまとめ

3年目くらいに書いたものだからアップデートが必要かも

Eigen

  • Rotation matrix: Eigen::Matrix3d
  • Rotation vector: Eigen::AngleAxisd
  • Euler angle: Eigen::Vector3d
  • Quaternion: Eigen::Quaterniond
  • Euclidean transform: Eigen::Isometry3d
  • Affine transform: Eigen::Affine3d
  • Perspective transformation: Eigen::Projective3d

参考 https://github.com/gaoxiang12/slambook-en

  • メンバ変数に用いる場合はpublicでマクロを定義する
class Foo
{
  ...
  Eigen::Vector2d v;
  ...
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW // このマクロを追加.
  ...
};
  • STLコンテナを用いる場合にはallocatorを利用
    • typedefしとくと楽
#include<Eigen/StdVector> 
typedef std::vector<Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d>> VecVector2d;

参考 https://qiita.com/vs4sh/items/2032fd1a5dab780d432c

Gauss-Newton

例えばDirect法でGauss-Newtonを用いるとして

$$x_{t+1} = x_t + \Delta$$

$$\Delta = - {({J}^T J)}^{-1} {J}^T r $$

で$J$、$r$が求められていたら、

Eigen::VectorXf xi = Eigen::VectorXf::Zero(6); // 姿勢のベクトル

Eigen::MatrixXf J = Eigen::MatrixXf::Zero(width*height, 6);
Eigen::VectorXf residuals = Eigen::VectorXf::Zero(width*height);

// ここでJとresidualsを求める

Eigen::MatrixXf Jt = J.transpose();
Eigen::VectorXf b = Jt * residuals;

Eigen::Matrix<float, 6, 6> H = Jt * J;
Eigen::Matrix<float, 6, 1> inc = -(H.ldlt().solve(b));  // 逆行列は使わない

xi = (Sophus::SE3f::exp(xi) * Sophus::SE3f::exp(inc)).log();

で$\Delta$が求まり$x_{t+1}$が計算できる

行列計算で逆行列は使うべきではない

行列の分解

  • LU分解
    • 一般の行列$A$を左下三角行列$L$と右上三角行列$U$の積$A=LU$に分解
    • PartialPivLU
    • FullPivLU 精度がPartialPivLUよりいい
  Eigen::PartialPivLU<Eigen::MatrixXd> lu(A);
  x = lu.solve(b);

  // もしくは
  Eigen::PartialPivLU<Eigen::MatrixXd> lu;
  lu.compute(A);
  x = lu.solve(b);
  • コレスキー分解

    • $A$が対称正定値行列の場合のLU分解$A=L{L}^T$
    • LU分解より2倍計算量が小さい
    • $y={L}^T\delta x$として$A\delta x = L{L}^T \delta x=Ly=a$から$A\delta L=a$を解く
    • LLT
    • LDLT 精度がLLTよりいい
  • QR分解

    • 最小二乗法により長方形の係数行列をもつ方程式$Ax=b$を解く場合はQR分解を用いる
    • HouseholderQR
    • ColPivHouseholderQR
    • FullPivHouseholderQR
  • 固有値分解

    • EigenSolver 実数行列
    • ComplexEigenSolver 複素数行列
    • SelfAdjointEigenSolver 実対称、自己随伴行列
    • GeneralizedEigenSolver
    • GeneralizedSelfAdjointEigenSolver
  • SVD

    • JacobiSVD 精度がいい サイズが増えると遅い
    • BDCSVD 速い
      • singularValues() 特異値
      • matrixU() 左特異ベクトルを並べた行列
      • matrixV() 右特異ベクトルを並べた行列
      • solve() 方程式を解く
      • compute() 分解

参考 https://qiita.com/MusicScience37/items/13fefa6bed25ab8fb6e9

Sophus

Lie群、Lie代数のライブラリ Eigenとの相性がいい

Use logarithmic map to get the Lie algebra

// Rotation matrix with 90 degrees along Z axis  
Matrix3d R = AngleAxisd(M_PI/2, Vector3d(0, 0, 1)).toRotationMatrix();  
Sophus::SO3d SO3_R(R);  
Vector3d so3 = SO3_R.log();  
cout << "so3 hat=\n" << Sophus::SO3d::hat(so3) << endl;  
cout << "so3 hat vee= " << Sophus::SO3d::vee(Sophus::SO3d::hat(so3)). transpose() << endl;  
  
// SE3  
Vector3d t(1, 0, 0);  
Sophus::SE3d SE3_Rt(R, t);  
// Lie Algebra is 6d vector  
typedef Eigen::Matrix<double, 6, 1> Vector6d;  
Vector6d se3 = SE3_Rt.log();  

se3からSE3の変換は$\exp(\hat{\xi})$だけどSophusはexp()に$\xi$をそのまま渡せば計算してくれる
log()も同様

クオータニオンと並進ベクトルからSE3への変換

Eigen::Quaternionf q(w, x, y, z);  
Eigen::Vector3f t(1.f, 0.f, 0.f);  
Sophus::SE3f pose(q, t);