slam三维空间刚体运动及Eigen库的使用

2024-03-20 02:28

本文主要是介绍slam三维空间刚体运动及Eigen库的使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.理论部分

1.旋转矩阵

旋转矩阵有一些特别的性质。事实上,它是一个行列式为 1 的正交矩阵。反之,行
列式为 1 的正交矩阵也是一个旋转矩阵。所以,我们可以把旋转矩阵的集合定义如下:

由于旋转矩阵为正交阵,显然 RT 刻画了一个相反的旋转。 

我们把一个三维向量的末尾添加 1,变成了四维向量,称为齐次坐标。

齐次坐标。它是射影几何里的概念。通过添加最后一维,我们用四个实数描述了一个三维向量,这显然多了一个自由度,但允许我们把变换写成线性的形式。

这时,忽略掉最后一项,这个点的坐标和欧氏空间就是一样的。依靠齐次坐标和变换矩阵,两次变换的累加就可以有很好的形式:

关于变换矩阵 T ,它具有比较特别的结构:左上角为旋转矩阵,右侧为平移向量,左下角为 0 向量,右下角为 1。这种矩阵又称为特殊欧氏群(Special Euclidean Group):

最后,为了保持符号的简洁,在不引起歧义的情况下,我们以后不区别齐次坐标与普
通的坐标的符号,默认我们使用的是符合运算法则的那一种。例如,当我们写 T a 时,使
用的是齐次坐标(不然没法计算)。而写 Ra 时,使用的是非齐次坐标。如果写在一个等
式中,我们就假设齐次坐标到普通坐标的转换,是已经做好了的——因为齐次坐标和非齐
次坐标之间的转换事实上非常容易。 

2.旋转向量

有了旋转矩阵来描述旋转,有了变换矩阵描述一个六自由度的三维刚体运动。但是,矩阵表示方式至少有以下几个缺点:

1. SO(3) 的旋转矩阵有九个量,但一次旋转只有三个自由度。因此这种表达方式是冗
余的。同理,变换矩阵用十六个量表达了六自由度的变换。

2. 旋转矩阵自身带有约束:它必须是个正交矩阵,且行列式为 1。变换矩阵也是如此。当
我们想要估计或优化一个旋转矩阵/变换矩阵时,这些约束会使得求解变得更困难。

任意旋转都可以用一个旋转轴和一个旋转角来刻画。于是,我们可以使用一个向量,其方向与旋转轴一致,而长度等于旋转角。这种向量,称为旋转向量(或轴角,Axis-Angle)

这种表示法只需一个三维向量即可描述旋转。同样,对于变换矩阵,我们使用一个旋转向量和一个平移向量即可表达一次变换。这时的维数正好是六维。

事实上,旋转向量就是李代数

假设有一个旋转轴为 n,角度为 θ 的旋转,显然,它对应的旋转向
量为 θn。由旋转向量到旋转矩阵的过程由罗德里格斯公式(Rodrigues’s Formula )

我们也可以计算从一个旋转矩阵到旋转向量的转换。对于转角 θ,有

关于转轴 n,由于旋转轴上的向量在旋转后不发生改变,说明

因此,转轴 n 是矩阵 R 特征值 1 对应的特征向量。求解此方程,再归一化,就得到
了旋转轴。

3.欧拉角

而欧拉角则提供了一种非常直观的方式来描述旋转——它使用了三个分离的转角

ZY X 转角相当于把任意旋转分解成
以下三个轴上的转角:
1. 绕物体的 Z 轴旋转,得到偏航角 yaw;
2. 绕旋转之后的 Y 轴旋转,得到俯仰角 pitch;
3. 绕旋转之后的 X 轴旋转,得到滚转角 roll。
此时,我们可以使用 [r, p, y]T 这样一个三维的向量描述任意旋转。

欧拉角的一个重大缺点是会碰到著名的万向锁问题(Gimbal Lock¬ ):在俯仰角为
±90◦ 时,第一次旋转与第三次旋转将使用同一个轴,使得系统丢失了一个自由度(由三次
旋转变成了两次旋转)。这被称为奇异性。

由于这种原理,欧拉角不适于插值和迭代,往往只用于人机交互中。我们也很少在 SLAM程序中直接使用欧拉角表达姿态,同样不会在滤波或优化中使用欧拉角表达旋转(因为它
具有奇异性)。不过,若你想验证自己算法是否有错时,转换成欧拉角能够快速辨认结果的
正确与否

4.四元数

旋转矩阵用九个量描述三自由度的旋转,具有冗余性;欧拉角和旋转向量是紧凑的,但
具有奇异性。事实上,我们找不到不带奇异性的三维向量描述方式。三维旋转是一个三维流形,想要无奇异性地表达它,用三个量是不够的。

在表达三维空间旋转时,也有一种类似于复数的代数:四元数(Quaternion)。四元数
是 Hamilton 找到的一种扩展的复数. 它既是紧凑的,也没有奇异性。

一个四元数 q 拥有一个实部和三个虚部

从旋转向量到四元数

四元数到旋转矩阵的转换方式

最后,无论是四元数、旋转矩阵还是轴角,它们都可以用来描述同一个旋转。我们应
该在实际中选择对我们最为方便的形式

5.相似、仿射、射影变换
1. 相似变换

相似变换比欧氏变换多了一个自由度,它允许物体进行均匀的缩放,其矩阵表示为:

注意到旋转部分多了一个缩放因子 s,表示我们在对向量旋转之后,可以在 x, y, z 三个坐标上进行均匀的缩放。由于含有缩放,相似变换不再保持图形的面积不变。

2. 仿射变换

3. 射影变换
 从真实世界到相机照片的变换是一个射影变换。

2.Eigen线性代数模块

Eigen¬ 是一个 C++ 开源线性代数库。它提供了快速的有关矩阵的线性代数运算,还
包括解方程等功能。许多上层的软件库也使用 Eigen 进行矩阵运算,包括 g2o、Sophus 等。

比于其他库,Eigen 特殊之处在于,它是一个纯用头文件搭建起来的
库(这非常神奇!)。这意味着你只能找到它的头文件,而没有.so 或.a 那样的二进制文件。
我们在使用时,只需引入 Eigen 的头文件即可,不需要链接它的库文件(因为它没有库文
件)。

// 包含标准输入输出流库,用于控制台输入输出
#include <iostream>
// 使用std命名空间,避免在每次使用标准库时都需要前缀std::
using namespace std;// 包含C++时间库,用于计算代码运行时间
#include <ctime>
// 引入Eigen库的核心部分,定义了矩阵、向量等基本数据结构
#include <Eigen/Core>
// 引入Eigen库用于进行稠密矩阵的代数运算(如求逆、求特征值等)
#include <Eigen/Dense>// 使用Eigen命名空间,简化类型名称
using namespace Eigen;// 定义一个宏,用作矩阵大小的常量,这里设置为50
#define MATRIX_SIZE 50int main(int argc, char **argv) {// Eigen库中所有向量和矩阵都是Eigen::Matrix的实例,这是一个模板类。// 它的前三个参数为:数据类型,行数,列数// 声明一个2x3的float矩阵Matrix<float, 2, 3> matrix_23;// Eigen通过typedef提供了许多内置类型,但底层仍是Eigen::Matrix// 例如,Vector3d实际上是Eigen::Matrix<double, 3, 1>,即三维向量Vector3d v_3d;// 同样的,这是另一个三维向量Matrix<float, 3, 1> vd_3d;// Matrix3d实际上是Eigen::Matrix<double, 3, 3>Matrix3d matrix_33 = Matrix3d::Zero(); // 初始化为零// 对于不确定大小的矩阵,可以使用动态大小的矩阵Matrix<double, Dynamic, Dynamic> matrix_dynamic;// 更简单的动态矩阵声明方式MatrixXd matrix_x;// 接下来是对Eigen矩阵的一些操作// 输入数据(初始化)matrix_23 << 1, 2, 3, 4, 5, 6;// 输出矩阵内容cout << "matrix 2x3 from 1 to 6: \n" << matrix_23 << endl;// 使用()访问矩阵中的元素cout << "print matrix 2x3: " << endl;for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++)cout << matrix_23(i, j) << "\t";cout << endl;}// 矩阵和向量相乘(实际上是矩阵和矩阵)v_3d << 3, 2, 1;vd_3d << 4, 5, 6;// 在Eigen中不能混合不同类型的矩阵,需要类型转换Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;cout << "[1,2,3;4,5,6]*[3,2,1]=" << result.transpose() << endl;Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;cout << "[1,2,3;4,5,6]*[4,5,6]: " << result2.transpose() << endl;// 对矩阵的一些基本运算matrix_33  << 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0;cout << "matrix 3x3: \n" << matrix_33 << endl;cout << "transpose: \n" << matrix_33.transpose() << endl; // 矩阵转置cout << "sum: " << matrix_33.sum() << endl;               // 矩阵所有元素的和cout << "trace: " << matrix_33.trace() << endl;           // 矩阵的迹(对角线元素之和)cout << "times 10: \n" << 10 * matrix_33 << endl;         // 矩阵的每个元素乘以10cout << "inverse: \n" << matrix_33.inverse() << endl;     // 矩阵的逆cout << "det: " << matrix_33.determinant() << endl;       // 矩阵的行列式值// 求解特征值和特征向量,这里使用SelfAdjointEigenSolver求解自伴矩阵的特征问题// 由于matrix_33.transpose() * matrix_33总是自伴的,因此可以这样做SelfAdjointEigenSolver<Matrix3d> eigen_solver(matrix_33.transpose() * matrix_33);cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;// 解线性方程组// 我们要解的方程是 matrix_NN * x = v_Nd// 其中 matrix_NN 是一个随机的正定矩阵,v_Nd 是一个随机向量// MATRIX_SIZE是之前定义的50,表示我们用50x50的矩阵和50维向量Matrix<double, MATRIX_SIZE, MATRIX_SIZE> matrix_NN = MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);matrix_NN = matrix_NN * matrix_NN.transpose();  // 乘以其转置以确保是半正定Matrix<double, MATRIX_SIZE, 1> v_Nd = MatrixXd::Random(MATRIX_SIZE, 1);// 记录当前时间clock_t time_stt = clock();// 直接使用矩阵逆求解Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse() * v_Nd;cout << "time of normal inverse is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;cout << "x = " << x.transpose() << endl;// 使用QR分解求解,通常比直接求逆快很多time_stt = clock();x = matrix_NN.colPivHouseholderQr().solve(v_Nd);cout << "time of QR decomposition is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;cout << "x = " << x.transpose() << endl;// 对于正定矩阵,还可以使用cholesky分解来求解time_stt = clock();x = matrix_NN.ldlt().solve(v_Nd);cout << "time of ldlt decomposition is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;cout << "x = " << x.transpose() << endl;return 0;
}

out

matrix 2x3 from 1 to 6: 
1 2 3
4 5 6
print matrix 2x3: 
1	2	3	
4	5	6	
[1,2,3;4,5,6]*[3,2,1]=10 28
[1,2,3;4,5,6]*[4,5,6]: 32 77
random matrix: 
1 2 3
4 5 6
7 8 9
transpose: 
1 4 7
2 5 8
3 6 9
sum: 45
trace: 15
times 10: 
10 20 30
40 50 60
70 80 90
inverse: 
-inf  inf -infinf -inf  inf
-inf  inf -inf
det: 0
Eigen values = 
9.30184e-161.14141283.859
Eigen vectors = -0.408248  -0.776691   0.4796710.816497 -0.0756865   0.572368-0.408248   0.625318   0.665064
time of normal inverse is 0.079ms
x =   2.91155   10.6997   3.43027   -2.6258  -1.14637   1.55867   1.03946   3.68188  -13.0695   1.87163   2.80044   9.72767   9.88619  -6.15914   2.10578  0.450982  -3.58146  -3.01118   8.34067   10.5629 -0.681178   4.72464  -6.14278 -0.191873   3.41807  -3.36318   2.64461  -8.38439  0.620947  -5.11558  -7.43408  -2.18593  -3.23169  0.194099  -2.69517    7.2354  -4.10885  -3.74595  -4.52556  -11.9484   8.27016   7.33514  0.384987   3.41304    -1.809   9.19733 -0.121441  -8.20668   1.72084     4.577
time of Qr decomposition is 0.046ms
x =   2.91155   10.6997   3.43027   -2.6258  -1.14637   1.55867   1.03946   3.68188  -13.0695   1.87163   2.80044   9.72767   9.88619  -6.15914   2.10578  0.450982  -3.58146  -3.01118   8.34067   10.5629 -0.681178   4.72464  -6.14278 -0.191873   3.41807  -3.36318   2.64461  -8.38439  0.620947  -5.11558  -7.43408  -2.18593  -3.23169  0.194099  -2.69517    7.2354  -4.10885  -3.74595  -4.52556  -11.9484   8.27016   7.33514  0.384987   3.41304    -1.809   9.19733 -0.121441  -8.20668   1.72084     4.577
time of ldlt decomposition is 0.021ms
x =   2.91155   10.6997   3.43027   -2.6258  -1.14637   1.55867   1.03946   3.68188  -13.0695   1.87163   2.80044   9.72767   9.88619  -6.15914   2.10578  0.450982  -3.58146  -3.01118   8.34067   10.5629 -0.681178   4.72464  -6.14278 -0.191873   3.41807  -3.36318   2.64461  -8.38439  0.620947  -5.11558  -7.43408  -2.18593  -3.23169  0.194099  -2.69517    7.2354  -4.10885  -3.74595  -4.52556  -11.9484   8.27016   7.33514  0.384987   3.41304    -1.809   9.19733 -0.121441  -8.20668   1.72084     4.577

矩阵论前置知识

1.特征值和特征向量

2.自伴矩阵

自伴矩阵:在数学中,特别是线性代数中,自伴矩阵(也称为Hermite矩阵或对称矩阵,在实数域上)是指其转置矩阵和共轭矩阵等于其本身的矩阵。在这个代码示例中,通过matrix_33.transpose() * matrix_33生成一个自伴矩阵,因为任何矩阵与其转置的乘积都是自伴的。

 3.正定矩阵

正定矩阵应用

优化问题

在优化问题中,目标函数的Hessian矩阵(二次导数矩阵)如果在某点正定,那么该点是一个局部最小点。这一性质被广泛用于确定优化算法是否达到了局部最小值,尤其是在梯度下降法和牛顿法等方法中。

机器学习

在机器学习中,核函数(Kernel)矩阵或称为克拉默矩阵(Gram matrix)在支持向量机(SVM)等算法中扮演关键角色,其必须是半正定的,以确保优化问题的凸性,从而保证找到全局最优解。

信号处理

在信号处理和统计学中,协方差矩阵描述了各个变量间的协方差,是一个半正定矩阵。协方差矩阵的性质被用来分析数据的分布和变量之间的关系。

控制理论

在控制理论中,系统的稳定性可以通过Lyapunov函数来分析,其二次形式的正定性是判断系统稳定性的一个重要工具。

量子力学

在量子力学中,密度矩阵描述了量子系统的状态,它是半正定的。这一性质用于确保概率解释的一致性和物理可行性。

4.正交矩阵

正交矩阵性质

  1. 行列向量的正交性:正交矩阵的行和列都是标准正交基,即它们的内积为0(对不同行或列),自身的内积为1。
  2. 保持内积和长度:正交变换保持向量的内积和长度不变,因此也保持了向量间的角度。
  3. 行列式的值:正交矩阵的行列式值为+1+1或−1−1,表示经过正交变换后,空间的体积(或面积)保持不变,仅方向可能发生改变。

正交矩阵用途

  1. 几何变换:在几何中,正交矩阵用于表示各种保持长度和角度不变的变换,如旋转、反射。这在图形处理、计算机视觉等领域尤其重要。

  2. 数值稳定的算法:在数值线性代数中,正交矩阵因其数值稳定性特别有用。例如,QR分解就是将矩阵分解为一个正交矩阵和一个上三角矩阵的乘积,广泛应用于求解线性方程组、计算特征值等。

  3. 信号处理:在信号处理领域,正交矩阵用于设计正交滤波器和进行正交变换(如离散傅立叶变换、离散余弦变换),以实现有效的信号分析和数据压缩。

  4. 通信理论:在通信理论中,正交码被用来设计抗干扰的通信系统,确保信号传输的准确性。

  5. 量子计算:在量子计算中,量子位的操作可以通过酉矩阵(正交矩阵的复数推广)来表示,这对于设计和理解量子算法至关重要。

求解线性方程组

1.使用矩阵逆求解

这种求解线性方程组的方法简单直接,但在实际应用中,尤其是对于大规模矩阵,直接计算矩阵的逆可能不是最高效或最稳定的方法。原因包括:

  • 计算复杂度:求一个矩阵的逆的复杂度较高,尤其是对于大矩阵,可能会导致计算成本过大。
  • 数值稳定性:直接求逆可能会引入数值不稳定性,尤其是当矩阵条件数(condition number)较大时。

在实践中,更倾向于使用如LU分解、QR分解或者奇异值分解(SVD)等数值稳定的算法来求解线性方程组。这些方法不仅能提高计算效率,还能增加数值计算的稳定性。

  • 这种方法直接应用了线性代数中的公式x = A^(-1) * b,其中A是系数矩阵,b是结果向量,x是未知向量。
2.QR分解

QR分解是将矩阵分解为一个正交矩阵(Q)和一个上三角矩阵(R)的乘积。对于任何矩阵A,都可以分解为A = QR,其中Q是一个具有正交列的矩阵,而R是一个上三角矩阵。

当用于求解线性方程组Ax = b时,通过将A分解为QR,原方程变为QRx = b。由于Q是正交的,即Q^TQ = I(其中I是单位矩阵),我们可以两边同时左乘Q^T得到R x = Q^T b。由于R是上三角矩阵,这个新的方程组可以通过回代法(back substitution)高效解决。

回代法(Back Substitution)是一种用于求解上三角线性方程组的算法。在上三角矩阵中,所有的未知数都排列在方程的对角线及其右侧,这使得可以从最后一个方程开始依次解出每个未知数。

3.Cholesky(LDLT)分解

因此,在知道矩阵是对称正定的情况下,优先考虑使用Cholesky分解,因为它更高效且数值稳定。在矩阵类型未知或不满足Cholesky分解条件时,使用LU分解。

3.Eigen几何模块

#include <iostream> // 引入标准输入输出流库
#include <cmath> // 引入数学函数库using namespace std; // 使用标准命名空间#include <Eigen/Core> // 引入Eigen的核心部分
#include <Eigen/Geometry> // 引入Eigen的几何模块using namespace Eigen; // 使用Eigen命名空间int main(int argc, char **argv) {Matrix3d rotation_matrix = Matrix3d::Identity(); // 初始化一个3x3的单位旋转矩阵// 定义旋转向量,表示沿Z轴旋转45度
//AngleAxisd是Eigen中用于表示旋转的一种方式,其构造函数接收两个参数:旋转角度和旋转轴
//(在这个例子中是Z轴,即向量(0, 0, 1))。AngleAxisd rotation_vector(M_PI / 4, Vector3d(0, 0, 1));// 输出旋转矩阵cout.precision(3); // 设置输出精度cout << "rotation matrix =\n" << rotation_vector.matrix() << endl; // 转换旋转向量为旋转矩阵并输出// 将AngleAxis对象转换为旋转矩阵rotation_matrix = rotation_vector.toRotationMatrix();// 使用旋转向量对向量(1,0,0)进行旋转Vector3d v(1, 0, 0);Vector3d v_rotated = rotation_vector * v;cout << "(1,0,0) after rotation (by angle axis) = " << v_rotated.transpose() << endl;// 使用旋转矩阵对向量进行旋转v_rotated = rotation_matrix * v;cout << "(1,0,0) after rotation (by matrix) = " << v_rotated.transpose() << endl;// 将旋转矩阵转换为欧拉角Vector3d euler_angles = rotation_matrix.eulerAngles(2, 1, 0); // 按照Z, Y, X顺序转换为欧拉角cout << "yaw pitch roll = " << euler_angles.transpose() << endl;// 定义一个Isometry3d对象T,用于表示3D空间中的旋转和平移Isometry3d T = Isometry3d::Identity();T.rotate(rotation_vector); // 应用旋转T.pretranslate(Vector3d(1, 3, 4)); // 应用平移cout << "Transform matrix = \n" << T.matrix() << endl; // 输出变换矩阵// 使用变换矩阵T对向量v进行变换Vector3d v_transformed = T * v;cout << "v transformed = " << v_transformed.transpose() << endl;// 定义一个四元数q,从旋转向量初始化Quaterniond q = Quaterniond(rotation_vector);cout << "quaternion from rotation vector = " << q.coeffs().transpose() << endl;// 也可以从旋转矩阵初始化四元数qq = Quaterniond(rotation_matrix);cout << "quaternion from rotation matrix = " << q.coeffs().transpose() << endl;// 使用四元数q对向量v进行旋转v_rotated = q * v; // 注意,这里使用的是四元数的旋转操作cout << "(1,0,0) after rotation = " << v_rotated.transpose() << endl;// 计算等价的四元数乘法,应与上面的旋转结果相同cout << "should be equal to " << (q * Quaterniond(0, 1, 0, 0) * q.inverse()).coeffs().transpose() << endl;return 0;
}

out

rotation matrix =0.707 -0.707      00.707  0.707      00      0      1
(1,0,0) after rotation (by angle axis) = 0.707 0.707     0
(1,0,0) after rotation (by matrix) = 0.707 0.707     0
yaw pitch roll = 0.785    -0     0
Transform matrix = 0.707 -0.707      0      10.707  0.707      0      30      0      1      40      0      0      1
v tranformed = 1.71 3.71    4
quaternion from rotation vector =     0     0 0.383 0.924
quaternion from rotation matrix =     0     0 0.383 0.924
(1,0,0) after rotation = 0.707 0.707     0
should be equal to 0.707 0.707     0     0

Eigen 中对各种形式的表达方式总结如下。请注意每种类型都有单精度和双精度两种
数据类型,而且和之前一样,不能由编译器自动转换。下面以双精度为例,你可以把最后
的 d 改成 f,即得到单精度的数据结构。
• 旋转矩阵(3 × 3)
:Eigen::Matrix3d。
• 旋转向量(3 × 1)
:Eigen::AngleAxisd。
• 欧拉角(3 × 1)
:Eigen::Vector3d。
• 四元数(4 × 1)
:Eigen::Quaterniond。
• 欧氏变换矩阵(4 × 4)
:Eigen::Isometry3d。
• 仿射变换(4 × 4)
:Eigen::Affine3d。
• 射影变换(4 × 4)
:Eigen::Projective3d。

4.Pangolin库和Eigen库可视化

Pangolin是一个轻量级的3D视觉化库,常用于计算机视觉和机器人项目中。

#include <iostream> // 引入标准输入输出流库
#include <iomanip> // 引入输入输出流格式控制库using namespace std; // 使用标准命名空间#include <Eigen/Core> // 引入Eigen的核心部分
#include <Eigen/Geometry> // 引入Eigen的几何模块,用于处理3D空间的旋转和变换using namespace Eigen; // 使用Eigen命名空间#include <pangolin/pangolin.h> // 引入Pangolin库// 定义旋转矩阵结构体,封装了Eigen的Matrix3d作为成员变量
struct RotationMatrix {Matrix3d matrix = Matrix3d::Identity(); // 默认初始化为单位矩阵
};// 重载输出流运算符,用于输出旋转矩阵
ostream &operator<<(ostream &out, const RotationMatrix &r) {out.setf(ios::fixed); // 设置输出格式为固定点表示法Matrix3d matrix = r.matrix; // 获取旋转矩阵// 格式化输出矩阵元素out << '=';out << "[" << setprecision(2) << matrix(0, 0) << "," << matrix(0, 1) << "," << matrix(0, 2) << "],"<< "[" << matrix(1, 0) << "," << matrix(1, 1) << "," << matrix(1, 2) << "],"<< "[" << matrix(2, 0) << "," << matrix(2, 1) << "," << matrix(2, 2) << "]";return out;
}// 由于没有定义输入格式,该重载的输入流运算符仅返回输入流对象
istream &operator>>(istream &in, RotationMatrix &r) {return in;
}// 定义平移向量结构体,封装了Eigen的Vector3d作为成员变量
struct TranslationVector {Vector3d trans = Vector3d(0, 0, 0); // 默认初始化为零向量
};// 重载输出流运算符,用于输出平移向量
ostream &operator<<(ostream &out, const TranslationVector &t) {// 格式化输出向量元素out << "=[" << t.trans(0) << ',' << t.trans(1) << ',' << t.trans(2) << "]";return out;
}// 同样,由于没有定义输入格式,该重载的输入流运算符仅返回输入流对象
istream &operator>>(istream &in, TranslationVector &t) {return in;
}// 定义四元数绘制结构体,封装了Eigen的Quaterniond作为成员变量
struct QuaternionDraw {Quaterniond q;
};// 重载输出流运算符,用于输出四元数
ostream &operator<<(ostream &out, const QuaternionDraw quat) {auto c = quat.q.coeffs(); // 获取四元数的系数// 格式化输出四元数的系数,注意四元数的系数顺序为(x, y, z, w)out << "=[" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << "]";return out;
}// 同样,由于没有定义输入格式,该重载的输入流运算符仅返回输入流对象
istream &operator>>(istream &in, const QuaternionDraw quat) {return in;
}int main(int argc, char **argv) {// 创建一个名为"visualize geometry"的Pangolin窗口,尺寸为1000x600pangolin::CreateWindowAndBind("visualize geometry", 1000, 600);

out

这篇关于slam三维空间刚体运动及Eigen库的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/828004

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

Toolbar+DrawerLayout使用详情结合网络各大神

最近也想搞下toolbar+drawerlayout的使用。结合网络上各大神的杰作,我把大部分的内容效果都完成了遍。现在记录下各个功能效果的实现以及一些细节注意点。 这图弹出两个菜单内容都是仿QQ界面的选项。左边一个是drawerlayout的弹窗。右边是toolbar的popup弹窗。 开始实现步骤详情: 1.创建toolbar布局跟drawerlayout布局 <?xml vers

C#中,decimal类型使用

在Microsoft SQL Server中numeric类型,在C#中使用的时候,需要用decimal类型与其对应,不能使用int等类型。 SQL:numeric C#:decimal

探索Elastic Search:强大的开源搜索引擎,详解及使用

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选,相信大家多多少少的都听说过它。它可以快速地储存、搜索和分析海量数据。就连维基百科、Stack Overflow、

flask 中使用 装饰器

因为要完成毕业设计,我用到fountain code做数据恢复。 于是在github上下载了fountain code的python原代码。 github上的作者用flask做了fountain code的demo。 flask是面向python的一个网站框架。 里面有用到装饰器。 今天笔试的时候,我也被问到了python的装饰器。

mathematica的使用

因为做实验用到Bloom filter这一技术,Bloom filter里面的数学公式可以用来画图。 那么用什么画图软件比较好呢? 当然是Mathematica啦。 利用代码Plot[{y=x},{x,0,100}] 就可以画出比较好的图 简直nice