Eigen学习笔记(16)-空间变换

原文:Eigen官网-Space transformations
本篇将介绍基于geometry module的2D 、3D旋转和投影或仿射变换。
【Eigen学习笔记(16)-空间变换】Eigen中的Geometry module提供了两种不同的几何变换:

  • 抽象变换,如旋转(rotation 由角和轴表示或由四元数表示)、平移(translation)、缩放(scaling)。这些转换不表示为矩阵,但您仍然可以将它们与表达式中的矩阵和向量混合,并根据需要将它们转换为矩阵。
  • 投影或仿射变换矩阵:参见Transform类。这些以矩阵的形式进行表示。
可以从抽象转换构造一个Transform,就像这样:
Transform t(AngleAxis(angle,axis));

或者像这样:
Transform t; t = AngleAxis(angle,axis);

但是根据C++的机制,不可以通过如下方式定义:
Transform t = AngleAxis(angle,axis);

解释:在C++语言中,这需要一个从AngleAxis到Transform的非显式转换构造函数,但是我们确实不希望允许在这里隐式转换。
1. Transformation的类型
Transformation type
转换类型
Typical initialization code
典型初始化代码
-
2D rotation from an angle
2D 旋转只需一个旋转角度
Rotation2D rot2(angle_in_radian);
3D rotation as an angle + axis
3D旋转需要旋转角度+旋转轴
AngleAxis aa(angle_in_radian, Vector3f(ax,ay,az));
The axis vector must be normalized.
3D rotation as a quaternion
四元数形式的3D旋转
Quaternion q;
q = AngleAxis(angle_in_radian, axis);
提供了两类方便的类型定义:
Quaternionf for float
Quaterniond for double
也可以直接给定参数:
quater.x() = 0;
quater.y() = 0;
quater.z() = sin(M_PI/2.0 / 2.0);
quater.w() = cos(M_PI/2.0 / 2.0);
N-D Scaling
尺度缩放
Scaling(sx, sy)
Scaling(sx, sy, sz)
Scaling(s)
Scaling(vecN)
N-D Translation
平移
Translation(tx, ty)
Translation(tx, ty, tz)
Translation(s)
Translation(vecN)
N-D Affine transformation
仿射变换
Transform t = concatenation_of_any_transformations;
Transform t = Translation3f§ * AngleAxisf(a,axis) * Scaling(s);
放射变换是一些变换的结合,按平移×旋转×缩放的顺序连乘
N-D Linear transformations
(pure rotations, scaling, etc.)
线性变换
Matrix t = concatenation_of_rotations_and_scalings;
Matrix t = Rotation2Df(a) * Scaling(s);
Matrix t = AngleAxisf(a,axis) * Scaling(s);

(1) AngleAxis示例:
结合MatrixBase::Unit{X,Y,Z},可以用AngleAxis方便的模仿Euler-angles。
// Code: Matrix3f m; m = AngleAxisf(0.25*M_PI, Vector3f::UnitX()) * AngleAxisf(0.5*M_PI,Vector3f::UnitY()) * AngleAxisf(0.33*M_PI, Vector3f::UnitZ()); cout << m << endl << "is unitary: " << m.isUnitary() << endl; // Output: 1.19e-0701 0.969-0.2490 0.2490.969 1.19e-07 is unitary: 1

(2) 对三维点进行变换
//变换前的点 Eigen::Vector3f v3f_a(x_m, y_m, 0.0); //变换后的点:变换矩阵左乘点向量 Eigen::Vector3f v3f_b = affine3f*v3f_a;

(3) 要知道affine3f的四维矩阵Matrix4f,采用如下转换
Eigen::Matrix4f a; Eigen::Affine3f b; b.matrix() = a;

若要转换多个向量,首选的表示形式是旋转矩阵(rotation matrices),而对于其他用途,四元数(Quaternion)是可选择的表示形式,因为它们是紧凑、快速和稳定的。最后,Rotation2DAngleAxis是创建其他旋转对象的最主要的便利类型。
关于Translation和Scaling的注释:
AngleAxis一样,这些类被设计成简化linear(matrix)affine(Transform)变换的创建和初始化。然而,与使用效率低的AngleAxis不同,这些类可能可应用于编写通用和高效的算法,这些算法可以任意类型的转换作为输入。
上述任何transformation types都可以转换为任何其他性质相同的类型,或转换为更通用的类型。以下是一些示例:
Rotation2Df r; r= Matrix2f(..); // assumes a pure rotation matrix AngleAxisf aa; aa = Quaternionf(..); AngleAxisf aa; aa = Matrix3f(..); // assumes a pure rotation matrix Matrix2f m; m= Rotation2Df(..); Matrix3f m; m= Quaternionf(..); Matrix3f m; m = Scaling(..); Affine3f m; m= AngleAxis3f(..); Affine3f m; m = Scaling(..); Affine3f m; m= Translation3f(..); Affine3f m; m = Matrix3f(..);

2. Transformation 类型之间的通用API 在某种程度上,Eigen的geometry module允许您编写处理任何类型转换表示的通用算法:
- -
Concatenation of two transformations gen1 * gen2;
Apply the transformation to a vector vec2 = gen1 * vec1;
Get the inverse of the transformation gen2 = gen1.inverse();
Spherical interpolation
(Rotation2D and Quaternion only)
rot3 = rot1.slerp(alpha,rot2);
3. 仿射变换(Affine transformations) 泛型仿射变换用Transform类表示,其实质是(Dim+1)^2的矩阵。在Eigen中,我们选择不区分点和向量,这样所有点实际上都由原点的位移向量表示。考虑到这一点,在应用转换时,实数点和向量会进行区分。
- -
Apply the transformation to a point
对一个点应用变换
VectorNf p1, p2;
p2 = t * p1;
Apply the transformation to a vector
对一个向量应用变换
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();
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());
Component accessors
- -
full read-write access to the internal matrix t.matrix() = matN1xN1; // N1 means N+1
matN1xN1 = t.matrix();
coefficient accessors t(i,j) = scalar; <=> t.matrix()(i,j) = scalar;
scalar = t(i,j); <=> scalar = t.matrix()(i,j);
translation part t.translation() = vecN;
vecN = t.translation();
linear part t.linear() = matNxN;
matNxN = t.linear();
extract the rotation matrix matNxN = t.rotation();
Transformation creation
虽然可以通过连接基本转换来创建和更新转换对象,但Transform类还具有一个过程API:
- 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.preshear(sx,sy);
-

注意,在这两个API中,任何多个转换都可以在一个表达式中连接,如下两个等效示例所示:
t.pretranslate(..).rotate(..).translate(..).scale(..); t = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..);

4. Euler angles Euler角度可以方便地创建旋转对象。另一方面,由于存在24种不同的约定,它们使用起来非常混乱。此示例演示如何根据2-1-2约定创建旋转矩阵。
Matrix3f m; m = AngleAxisf(angle1, Vector3f::UnitZ()) * AngleAxisf(angle2, Vector3f::UnitY()) * AngleAxisf(angle3, Vector3f::UnitZ());

参考:
使用eigen库进行空间变换

    推荐阅读