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

原文:Eigen官网-Space transformations

本篇将介绍基于geometry module的2D 、3D旋转和投影或仿射变换。

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++语言中,这需要一个从AngleAxisTransform的非显式转换构造函数,但是我们确实不希望允许在这里隐式转换。

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<float,2>(tx, ty)
Translation<float,3>(tx, ty, tz)
Translation<float,N>(s)
Translation<float,N>(vecN)
N-D Affine transformation
仿射变换
Transform<float,N,Affine> t = concatenation_of_any_transformations;
Transform<float,3,Affine> t = Translation3f§ * AngleAxisf(a,axis) * Scaling(s);
放射变换是一些变换的结合,按平移×旋转×缩放的顺序连乘
N-D Linear transformations
(pure rotations, scaling, etc.)
线性变换
Matrix<float,N> t = concatenation_of_rotations_and_scalings;
Matrix<float,2> t = Rotation2Df(a) * Scaling(s);
Matrix<float,3> 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-07        0        1
   0.969   -0.249        0
   0.249    0.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是创建其他旋转对象的最主要的便利类型。

关于TranslationScaling的注释:
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库进行空间变换

© 版权声明
THE END
喜欢就支持一下吧
点赞437 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容