赞
踩
旋转轴/旋转角、旋转矩阵、四元数、李代数都可以表示旋转,那么这几者的转换是如何实现的呢?
绕一个轴,旋转角度的旋转,例如,在三维空间中,以为轴,旋转45°,表示为,注意,旋转轴模长要化为1,旋转角度乘旋转轴即为旋转向量
假如有一个点P(1,2,3), 那么点P绕轴(0,0.7071,0.7071)转,后的位置,R为旋转矩阵,旋转向量到旋转矩阵的转化通过罗德里格斯公式实现
n右上面一个小帽子表示将向量 n(n1, n2, n3) 转化为反对称矩阵(skew-symmetirc)
从 旋转矩阵 转化回 旋转轴和旋转角 的方法是对旋转矩阵求迹tr(R)
转轴n是旋转矩阵R特征值1所对应的特征向量。通过特征向量的求解方法求解旋转轴(Eigen库中有现成的轮子)
旋转轴/旋转角到四元数的方法
四元数到旋转矩阵的转换方法
下面说明 旋转矩阵 到 李代数 的转化方法,介绍李代数之前,先说明李群的概念,一种集合加上一种运算,就构成了群,比如:旋转矩阵和矩阵乘法构成一个群,如果一个群,具有连续(光滑)性质,则称为李群,旋转矩阵和矩阵乘法构成一个李群。每个李群,都有一个与之对应的李代数,因此,每个旋转矩阵,都有一个与之对应的李代数。
旋转矩阵R所属的李群用SO(3)表示,它对应的李代数用表示(应该用哥特体写,但是我不知道csdn怎么打哥特体),李代数体现为一个三维向量。
,即:旋转角乘旋转轴得到的旋转向量,就是旋转矩阵R对应的李代数。
已知李代数,转为旋转矩阵,首先将转成模长为1的旋转轴和旋转角,在根据旋转轴和旋转角求旋转矩阵。
上面说明了旋转,如果一个旋转加上平移该如何求解?(比如沿向量进行平移)
将旋转和平移结合,将三维坐标末尾加1,变成四维向量,成为齐次坐标。
对于一个点,经过平移和旋转,得到点
变换矩阵T同样属于李群,用SE(3)表示,同理,每一个T都有对应的李代数,体现为一个六维向量,式中,是旋转矩阵的李代数,通过平移向量t求解。
(注意,求J的公式里的是旋转轴,这里把字母换成了)
c++ Eigen库代码示例如下:注,Eigen库中没有李代数,再引用Sophus库
- #include <iostream>
- #include <cmath>
- #include <Eigen/Core>
- // Eigen 几何模块
- #include <Eigen/Geometry>
- #include <Eigen/Eigen>
-
- // Sophus库中李群和李代数运算
- #include "so3.cpp"
- #include "se3.cpp"
-
- #define M_PI 3.1415926
- using namespace std;
-
- int main(int argc, char** argv){
- double theta = M_PI / 4; // 旋转角
- Eigen::Vector3d a = Eigen::Vector3d(0, 0.7071, 0.7071); // 旋转轴
- Eigen::AngleAxisd rotation_vector(theta, a); // 旋转向量
- // 旋转向量到旋转矩阵
- Eigen::Matrix3d R = rotation_vector.toRotationMatrix();
- // 旋转矩阵到旋转向量
- cout << "theta=" << acos((R.trace() - 1) / 2) << endl;
- Eigen::EigenSolver<Eigen::MatrixXd> es(R);
- cout << "第一种:" << endl;
- cout << "特征值为:" << endl;
- cout << es.eigenvalues() << endl;
- cout << "特征向量为:" << endl;
- cout << es.eigenvectors() << endl << endl;
- // se(3)中J的求解
- Eigen::Matrix3d I = Eigen::Matrix3d::Identity();
- Eigen::Matrix3d J = sin(theta) / theta * I + (1 - sin(theta) / theta) * a * a.transpose() + (1 - cos(theta)) / theta * Sophus::SO3::hat(a);
- Eigen::Vector3d t = Eigen::Vector3d(1, 3, 4)
- Eigen::Vector3d rho = J.inverse() * t;
- cout << "rho:\n" << endl;
- cout << rho << endl;
-
- // 直接用Sophus库求李代数
- Sophus::SO3 SO3_R(R);
- Eigen::Vector3d so3 = SO3_R.log();
-
- // 四元数
- // 可以直接把AngleAxis赋值给四元数,反之亦然
- Eigen::AngleAxisd rotation_vector(M_PI / 4, Eigen::Vector3d(0, 0.7071, 0.7071));
- Eigen::Matrix3d rotation_matrix = rotation_vector.toRotationMatrix();
-
- Eigen::Quaterniond q = Eigen::Quaterniond(rotation_vector);
- cout << "quaternion = \n" << q.coeffs() << endl; // 请注意coeffs的顺序是(x,y,z,w),w为实部,前三者为虚部
- // 也可以把旋转矩阵赋给它
- q = Eigen::Quaterniond(rotation_matrix);
- cout << "quaternion = \n" << q.coeffs() << endl;
- // 使用四元数旋转一个向量,使用重载的乘法即可
- v_rotated = q * v; // 注意数学上是qvq^{-1}
- cout << "(1,0,0) after rotation = " << v_rotated.transpose() << endl;
-
- return 0;
- }
参考文献:《视觉SLAM十四讲》——高翔,张涛
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。