【问题标题】:Eigen combine rotation and translation into one matrixEigen 将旋转和平移组合成一个矩阵
【发布时间】:2014-08-26 11:09:48
【问题描述】:

我有一个旋转矩阵rot (Eigen::Matrix3d) 和一个平移向量transl (Eigen::Vector3d),我希望它们都在一个 4x4 变换矩阵中。我只是为了我的生活无法弄清楚如何在 Eigen 中做到这一点。我认为 Affine 可以以某种方式使用,但我不明白它是如何工作的。

基本上我想要How translation a matrix(4x4) in Eigen?Multiplying Transform and Matrix types in Eigen 的组合

我的代码(由于我不了解 Affine 的工作原理而无法编译)如下所示:

Eigen::Affine3d r(rot);
Eigen::Affine3d t(transl);
Eigen::Matrix4d m = t.matrix();
m *= r.matrix();

【问题讨论】:

  • 作为你链接的答案都使用m = m * t.matrix(),也许问题是缺少运营商*=。是这样的吗?
  • 我不知道Eigen,但旋转矩阵通常是一个 3x3 矩阵,您可以直接将其放入 4x4 矩阵中(假设您没有进行任何缩放)。在 4x4 变换矩阵中,元素 _00、_01、_02、_10、_11、_12、_20、_21 和 _22 形成旋转(如果有缩放,则为时间尺度)。元素_30、_31和_32是平移向量元素。
  • @pqnet 不,这也不起作用,我认为问题在于我需要以某种方式指出我希望将不同部分“插入”到主矩阵中的位置。但我根本不知道。
  • @rashmatash,有两种类型的 4x4 矩阵:列顺序的,如 OpenGL 中使用的矩阵,以及行顺序的,如数学或物理中常用的矩阵。因此,平移向量的系数可以是 (3,0)(3,1)(3,2) 或 (0,3)(1,3)(2,3),具体取决于定义。例如:bitbucket.org/Coin3D/coin/src/…

标签: c++ matrix eigen


【解决方案1】:

另一种方法是执行以下操作:

Eigen::Matrix3d R;
// Find your Rotation Matrix
Eigen::Vector3d T;
// Find your translation Vector
Eigen::Matrix4d Trans; // Your Transformation Matrix
Trans.setIdentity();   // Set to Identity to make bottom row of Matrix 0,0,0,1
Trans.block<3,3>(0,0) = R;
Trans.block<3,1>(0,3) = T;

此方法将旋转矩阵复制到前 3 行和前 3 列,将平移向量复制到第 4 列。然后将右下角的矩阵条目设置为 1。 您的最终矩阵将如下所示:

R R R T
R R R T
R R R T
0 0 0 1

其中 R 是旋转矩阵中的对应值,T 是平移向量中的值。

【讨论】:

  • 很好的简单解决方案。我认为甚至可以使用Trans.setIdentity(); 而不是Trans.setZero(4,4); 并且能够跳过最后的Trans(3,3) = 1; 行。
  • 正是我需要的,但是我使用Trans.block&lt;3,1&gt;(0,3) = T; 而不是Trans.rightCols&lt;1&gt;() = T; 以避免YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES 错误
  • 谢谢,我想自从我最初发布这个答案以来,他们已经添加了更严格的类型检查。
  • 您也可以更直观地编写 IMO Trans.linear() = R; Trans.translation() = T;。此外,如果您使用Eigen::Transform&lt;..., Eigen::AffineCompact&gt; 作为转换类型,则不需要使用setIdentity() 进行初始化,因为没有最低行。不过,您可能希望保留它,因为 a) 编译器很聪明(即没有运行时成本)并且 b) 您可能想在某个时候更改类型,在忘记这种“优化”很久之后。
【解决方案2】:

您没有发布编译错误,也没有发布 rottransl。下面是一个工作 示例展示了如何创建 4x4 变换矩阵。

#include <Eigen/Geometry>

Eigen::Affine3d create_rotation_matrix(double ax, double ay, double az) {
  Eigen::Affine3d rx =
      Eigen::Affine3d(Eigen::AngleAxisd(ax, Eigen::Vector3d(1, 0, 0)));
  Eigen::Affine3d ry =
      Eigen::Affine3d(Eigen::AngleAxisd(ay, Eigen::Vector3d(0, 1, 0)));
  Eigen::Affine3d rz =
      Eigen::Affine3d(Eigen::AngleAxisd(az, Eigen::Vector3d(0, 0, 1)));
  return rz * ry * rx;
}

int main() {
  Eigen::Affine3d r = create_rotation_matrix(1.0, 1.0, 1.0);
  Eigen::Affine3d t(Eigen::Translation3d(Eigen::Vector3d(1,1,2)));

  Eigen::Matrix4d m = (t * r).matrix(); // Option 1

  Eigen::Matrix4d m = t.matrix(); // Option 2
  m *= r.matrix();
  return 0;
}

【讨论】:

  • 谢谢,正是我想要的!我遇到的唯一问题是,如果我将翻译向量直接输入Eigen::Translation3d(),它就不起作用(t.matrix() 无法编译),所以我必须编写更复杂的Eigen::Translation3d(Eigen::Vector3d(transl(0), transl(1), transl(2)))。我想这是由于 Eigen 模板的黑暗巫术。
  • @BlazBratanic 那么Eigen::Transform 类是什么?
【解决方案3】:

另一种方法是使用Eigen::Transform

让我们举个例子来实现这个仿射变换,

#include <Eigen/Dense>
#include <Eigen/Geometry>
using namespace Eigen;

Matrix4f create_affine_matrix(float a, float b, float c, Vector3f trans)
{
    Transform<float, 3, Eigen::Affine> t;
    t = Translation<float, 3>(trans);
    t.rotate(AngleAxis<float>(a, Vector3f::UnitX()));
    t.rotate(AngleAxis<float>(b, Vector3f::UnitY()));
    t.rotate(AngleAxis<float>(c, Vector3f::UnitZ()));
    return t.matrix();
}

也可以如下实现

Matrix4f create_affine_matrix(float a, float b, float c, Vector3f trans)
{
    Transform<float, 3, Eigen::Affine> t;
    t = AngleAxis<float>(c, Vector3f::UnitZ());
    t.prerotate(AngleAxis<float>(b, Vector3f::UnitY()));
    t.prerotate(AngleAxis<float>(a, Vector3f::UnitX()));
    t.pretranslate(trans);
    return t.matrix();
}

第一种实现和第二种实现的区别就像Fix AngleEuler Angle的区别,可以参考this video

【讨论】:

    猜你喜欢
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多