Geometry(几何学)主要就是指的空间变换。学习这一章,可以减少代码编写量。本小节将会介绍一些处理2D、3D旋转、投影和仿射的变换的一些内容,这些内容将会由几何模块(geometry module)提供。
官方文档地址
Geometry模块可以提供以下功能支持:
这里主要对Tranform进行支持,这个类是几何变换的基础,代表N维齐次矩阵。
Transform模板定义如下:
template<typename _Scalar, int _Dim, int _Mode, int _Options>
class Eigen::Transform< _Scalar, _Dim, _Mode, _Options >
它代表了N维的齐次矩阵(Homogeneous transformation),单应性(homography)在内部由矩阵表示,可以使用matrix()方法返回。
对于机器人的变换算子(齐次矩阵)_Mode应该为Isometry,_Dim=3,对应的完整声明为:Transform
,和Matrix3f等一样,为了方便声明,有以下别名:
完整声明 | 别名 |
---|---|
typedef Transform |
Isometry2f; |
typedef Transform |
Isometry3f; |
typedef Transform |
Isometry2d; |
typedef Transform |
Isometry3d; |
typedef Transform |
Affine2f; |
typedef Transform |
Affine3f; |
typedef Transform |
Affine2d; |
typedef Transform |
Affine3d; |
typedef Transform |
AffineCompact2f; |
typedef Transform |
AffineCompact3f; |
typedef Transform |
AffineCompact2d; |
typedef Transform |
AffineCompact3d; |
typedef Transform |
Projective2f; |
typedef Transform |
Projective3f; |
typedef Transform |
Projective2d; |
typedef Transform |
Projective3d; |
这样一来,我们就能够直接使用Isometry3d来表示机器人的变换算子了。
默认构造函数 | 解释 |
---|---|
Transform() | 默认不进行初始化 |
Transform(const EigenBase< OtherDerived > & other) | 用满足一定规则的Matrix构造 |
Transform(const QTransform< _Scalar, _Dim, _Mode, _Options > & other) | QT中的QTransform构造 |
Transform(const QMatrix & other) | QT中的QMatrix构造 |
Transform(const Transform< OtherScalarType, Dim, Mode, Options > & other) | 拷贝构造(Tranform)类型 |
注:第二个构造函数是EigenBase,可用于构造和赋值MatrixBase,MatrixBase是所有dense matrices, vectors, and expressions的基类。像是一开始学到的Matrix类就是MatrixBase的子类,因此,你可以直接使用Matrix构造Transform。
MatrixBase有一个反解欧拉角的方法:Matrix< Scalar, 3, 1 > eulerAngles (Index a0, Index a1, Index a2) const)
Index是一个std::ptrdiff_t long型整数,0代表绕x,1代表绕y,2代表z。
Transform之间的变换可以通过运算符*来进行,值得注意的是,运算支持了DiagonalBase、EigenBase和Transform ,这也就是说,我们可以直接与Vector、Matrix进行混合运算。
Tranform类会提供两种不同的几何变换:
请注意,Transform虽非一个Matrix类型,但是仍然可以与Matrix、Vector进行混合使用。与一般的Matrix不同的地方在于,Tranform提供了许多性质用于简化组合和使用。具体的,它能够由其他变换(Transfrom,Translation,RotationBase,DiaonalMatrix)隐式转换成齐次向量后组合而成,这个操作就是运算符*
,运算一般就是纯乘法,eigen不可以充分利用这些变换的性质,对其进行优化以提升效率。
坐标变换是将一个坐标变换到另一个坐标,可以分为平移、旋转、缩放等。
变换类型 | 典型的初始化方法 |
---|---|
二维定角度旋转 | Rotation2D |
三维定轴、定角旋转 | AngleAxis 注:轴向量必须标准化,怕出错用,Vector3d::UnitX |
三维四元数旋转 | Quaternion q = AngleAxis |
N维缩放 | Scaling(sx, sy) Scaling(sx, sy, sz) Scaling(s) Scaling(vecN) |
N维平移 | Translation Translation Translation Translation |
N维维仿射变换 | Transform Transform ; |
N维线性变换(纯旋转、缩放等) | Matrix Matrix Matrix |
以AngleAxis为例,构造函数有:
赋值构造函数有:
这就是不同四元数、矩阵之间构造时相互转换的基础。
Matrix3d m=Matrix3d::Identity(3,3);
Quaterniond q(m); //Rotation Matrix to Quaternion
AngleAxisd d; //Default construction for AngleAxisd
d.fromRotationMatrix(m); //Rotation Matrix to AngleAxis
auto dq=d*q; //Quaternion=AngleAxis*Quaternion
auto qd=q*d; //Quaternion=Quaternion*AngleAxis
d=q; //AngleAxis=Quaternion
q=d; //Quaternion=AngleAxis
std::cout<<d.matrix()<<std::endl; //AngleAxis to Rotation Matrix 3x3
std::cout<<q.matrix()<<std::endl; //Quaternion to Rotation Matrix 3x3
Quaternion也有对应的构造函数:点击此查看
在特定范围内,Eigen的几何模块允许您编写处理任何类型变换表示的通用算法:
算法 | 形式 |
---|---|
变换串联 | gen1 * gen2; |
对一个向量应用变换 | vec2 = gen1 * vec1; |
变换的逆 | gen2 = gen1.inverse(); |
球面插补 | (Rotation2D and Quaternion only) |
算法是针对所有抽象类型的而不是特定类型的。
通用的仿射变换由Transform类表示,其内部内部为 ( D i m + 1 ) 2 (Dim+1)^2 (Dim+1)2矩阵。在Eigen中,我们选择不区分点和向量,这样所有点实际上都由原点的位移向量表示( p ≡ P − 0 p≡P−0 p≡P−0 ). 考虑到这一点,应用变换时,实际点和向量会有所区别。
变换 | 代码 |
---|---|
点的变换 | VectorNf p1, p2; p2 = t * p1; |
向量的变换 | VectorNf vec1, vec2; vec2 = t.linear() * vec1; |
Apply a general transformation to a normal vector | VectorNf n1, n2; MatrixNf normalMatrix = t.linear().inverse().transpose(); n2 = (normalMatrix *n1).normalized(); (See subject 5.27 of this faq for the explanations) |
Apply a transformation with pure rotation to a normal vector (no scaling, no shear) | n2 = t.linear() * n1; |
OpenGL compatibility 3D | glLoadMatrixf(t.data()); |
OpenGL compatibility 2D | Affine3f aux(Affine3f::Identity()); aux.linear().topLeftCorner<2,2>() = t.linear(); aux.translation().start<2>() = t.translation(); glLoadMatrixf(aux.data()); |
部件获取:
解释 | 代码 |
---|---|
读写内部矩阵 | t.matrix() = matN1xN1; // N1 means N+1 mat N1xN1 = t.matrix(); |
读写系数(元素) | t(i,j) = scalar; <=> t.matrix()(i,j) = scalar; scalar = t(i,j); <=> scalar = t.matrix()(i,j); |
移动部分 | t.translation() = vecN; vecN = t.translation(); |
线性部分 | t.linear() = matNxN; matNxN = t.linear(); |
取出旋转矩阵 | matNxN = t.rotation(); |
变换上应用另一个变换:
名称 | procedural API | equivalent natural API |
---|---|---|
Translation | t.translate(Vector_(tx,ty,…)); t.pretranslate(Vector_(tx,ty,…)); |
t *= Translation_(tx,ty,…); t = Translation_(tx,ty,…) * t; |
Rotation In 2D and for the procedural API, any_rotation can also be an angle in radian |
t.rotate(any_rotation); t.prerotate(any_rotation); |
t *= any_rotation; t = any_rotation * t; |
Scaling | t.scale(Vector_(sx,sy,…)); t.scale(s); t.prescale(Vector_(sx,sy,…)); t.prescale(s); |
t *= Scaling(sx,sy,…); t *= Scaling(s); t = Scaling(sx,sy,…) * t; t = Scaling(s) * t; |
Shear transformation ( 2D only ! ) |
t.shear(sx,sy); t.shear(sx,sy); |
注:pre代表在作用对象的前面,即左乘;不带pre的则为右乘,*=为右乘。
等价形式代码,注意顺序:
t.pretranslate(..).rotate(..).translate(..).scale(..);
t = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..);
补充阅读
【1】什么是仿射变换。https://blog.csdn.net/u011681952/article/details/98942207
_Option
:
_Options A combination of either RowMajor or ColMajor, and of either AutoAlign or DontAlign. The former controls storage order, and defaults to column-major. The latter controls alignment, which is required for vectorization. It defaults to aligning matrices except for fixed sizes that aren’t a multiple of the packet size.
关于仿射变换、射影变换和等距变换的区别。在Slam中几种变换的理解一文中可以知道这些变换的具体的含义。机器人运动学中选iosmetry表示同一个向量再各个坐标系下的长度和角度都没有发生变化,仅仅只是发生了旋转和平移的运动。
【3】http://eigen.tuxfamily.org/dox-devel/group__TutorialGeometry.html