Eigen中Eigen::Affine3d和Eigen::Isometry3d详解

发布于:2025-09-07 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 背景:仿射变换 vs 等距变换

在三维空间中,一个 齐次变换矩阵(4×4)一般写作:

T=[At01],A∈R3×3,t∈R3 T = \begin{bmatrix} A & \mathbf{t} \\ 0 & 1 \end{bmatrix}, \quad A \in \mathbb{R}^{3\times 3}, \mathbf{t} \in \mathbb{R}^3 T=[A0t1],AR3×3,tR3

这里的 A 决定了旋转/缩放/剪切,t 是平移。

  • Affine Transform (仿射变换)

    T(x)=Ax+t T(\mathbf{x}) = A\mathbf{x} + \mathbf{t} T(x)=Ax+t

    A 可以是任意非奇异矩阵,允许旋转、缩放、剪切。

  • Isometry (等距变换)

    T(x)=Rx+t,R∈SO(3) T(\mathbf{x}) = R\mathbf{x} + \mathbf{t}, \quad R \in SO(3) T(x)=Rx+t,RSO(3)

    这里 R 必须是正交矩阵,且 det⁡(R)=+1\det(R)=+1det(R)=+1,即纯旋转,不允许缩放/畸变。
    这是 SE(3) 里标准的位姿表示。

所以:

  • Affine3d = 一般的仿射变换(包含旋转+平移+缩放+剪切)。
  • Isometry3d = Affine3d 的子集(只允许旋转+平移)。

2. Eigen 里的实现关系

在 Eigen 里:

  • Affine3d 继承自 Transform<double, 3, Affine>
  • Isometry3d 继承自 Transform<double, 3, Isometry>

它们本质上都是 Eigen::Transform 的模板特化,只是内部对 矩阵 A 的约束不同

类型 模板参数 允许的变换 典型用途
Eigen::Affine3d Transform<double,3,Affine> 旋转、平移、缩放、剪切 图形学/通用几何变换
Eigen::Isometry3d Transform<double,3,Isometry> 旋转 + 平移(R ∈ SO(3)) 机器人学/SLAM 位姿

3. 转换关系

3.1 Isometry3d → Affine3d

总是安全的,因为等距变换一定是仿射变换的特例:

Eigen::Isometry3d iso = Eigen::Isometry3d::Identity();
Eigen::Affine3d affine = iso;  // OK

3.2 Affine3d → Isometry3d

可能丢失信息:
如果 Affine3d 中包含缩放/剪切,转成 Isometry3d 时会 直接假设线性部分是旋转矩阵,数值不符合 SE(3) 要求的话,结果不可预测。

Eigen::Affine3d affine = Eigen::Affine3d::Identity();
affine.linear() *= 2.0; // 缩放
Eigen::Isometry3d iso = affine; //  结果不是严格的旋转+平移

3.3 构造与赋值

// 直接从旋转+平移构造
Eigen::Isometry3d iso = Eigen::Translation3d(1,2,3) * Eigen::AngleAxisd(M_PI/4, Eigen::Vector3d::UnitZ());
Eigen::Affine3d affine = iso; // 安全

4. 常见接口差异

两者常用接口大部分相同,比如:

  • .translation() → 获取/设置平移
  • .linear() → 获取/设置旋转部分(注意:Affine3d 不一定是正交矩阵!)
  • * 运算符 → 变换向量或点
  • .matrix() → 获取 4×4 齐次矩阵

唯一区别:

  • Isometry3d 在数值上 保证旋转矩阵正交,适合表示位姿。
  • Affine3d 不做约束,可能引入畸变。

5. 实际应用建议

  • 机器人学 / SLAM / 计算机视觉
    Isometry3d,保证运算结果在 SE(3),不会意外引入缩放。

    Eigen::Isometry3d Tcw;  // 相机位姿
    Eigen::Vector3d Pc = Tcw * Pw;
    
  • 计算机图形学 / CAD / 建模
    Affine3d,因为可能需要缩放、剪切等操作。


6. 小示例

#include <Eigen/Dense>
#include <iostream>

int main() {
    // 构造 Isometry3d (旋转+平移)
    Eigen::Isometry3d iso = Eigen::Isometry3d::Identity();
    iso.translate(Eigen::Vector3d(1,2,3));
    iso.rotate(Eigen::AngleAxisd(M_PI/4, Eigen::Vector3d::UnitZ()));

    // 构造 Affine3d
    Eigen::Affine3d affine = Eigen::Affine3d::Identity();
    affine.linear() *= 2.0;  // 加缩放
    affine.translation() << 1, 2, 3;

    // 转换
    Eigen::Affine3d affine_from_iso = iso; // 安全
    Eigen::Isometry3d iso_from_affine = affine; //  不一定合法

    std::cout << "Isometry3d matrix:\n" << iso.matrix() << "\n\n";
    std::cout << "Affine3d matrix:\n" << affine.matrix() << "\n";
}

总结:

  • Affine3d = 仿射变换(更通用,允许缩放/剪切)
  • Isometry3d = 仿射变换的子集(严格 SE(3),只允许旋转+平移)
  • 实际上 Isometry3d 更适合 位姿 (pose)Affine3d 更适合 通用几何变换
  • Isometry3d 可以安全转 Affine3d,反之不保证合法

7.综合示例

下面是一个 综合示例,完整演示 Eigen::Affine3dEigen::Isometry3d 的构造、转换、使用、对比,适合 SLAM / 机器人学场景。


综合示例:位姿运算与差异对比

#include <Eigen/Dense>
#include <iostream>

int main() {
    // -------------------------------
    // 1. 构造 Isometry3d(严格的位姿:旋转+平移)
    // -------------------------------
    Eigen::Isometry3d T1 = Eigen::Isometry3d::Identity();
    T1.translate(Eigen::Vector3d(1, 0, 0));  // 平移
    T1.rotate(Eigen::AngleAxisd(M_PI/4, Eigen::Vector3d::UnitZ()));  // 绕Z轴旋转45度

    std::cout << "Isometry3d T1:\n" << T1.matrix() << "\n\n";

    // -------------------------------
    // 2. 构造 Affine3d(包含缩放的仿射变换)
    // -------------------------------
    Eigen::Affine3d T2 = Eigen::Affine3d::Identity();
    T2.translate(Eigen::Vector3d(0, 2, 0));  // 平移
    T2.linear() *= 2.0;  // ⚠️ 加缩放,破坏正交性

    std::cout << "Affine3d T2 (with scaling):\n" << T2.matrix() << "\n\n";

    // -------------------------------
    // 3. 类型转换
    // -------------------------------
    Eigen::Affine3d affine_from_iso = T1;  // ✅ 永远安全
    Eigen::Isometry3d iso_from_affine = T2;  // ⚠️ 丢失缩放信息,不一定合法

    std::cout << "Affine from Isometry (safe):\n" << affine_from_iso.matrix() << "\n\n";
    std::cout << "Isometry from Affine (unsafe if scaled):\n" << iso_from_affine.matrix() << "\n\n";

    // -------------------------------
    // 4. 应用:变换点
    // -------------------------------
    Eigen::Vector3d p(1, 1, 1);

    Eigen::Vector3d p_T1 = T1 * p;   // 严格位姿变换
    Eigen::Vector3d p_T2 = T2 * p;   // 包含缩放的仿射变换

    std::cout << "Original point: " << p.transpose() << "\n";
    std::cout << "Transformed by Isometry3d T1: " << p_T1.transpose() << "\n";
    std::cout << "Transformed by Affine3d T2 (scaled): " << p_T2.transpose() << "\n\n";

    // -------------------------------
    // 5. 提取旋转和平移
    // -------------------------------
    std::cout << "T1 translation: " << T1.translation().transpose() << "\n";
    std::cout << "T1 rotation matrix:\n" << T1.rotation() << "\n\n";

    std::cout << "T2 translation: " << T2.translation().transpose() << "\n";
    std::cout << "T2 linear part (not guaranteed orthogonal):\n" << T2.linear() << "\n\n";

    return 0;
}

输出要点(示例)

Isometry3d T1:
0.707 -0.707 0 1
0.707  0.707 0 0
0      0     1 0
0      0     0 1

Affine3d T2 (with scaling):
2 0 0 0
0 2 0 2
0 0 2 0
0 0 0 1

Affine from Isometry (safe):   // 完全一致
Isometry from Affine (unsafe): // 旋转矩阵不是严格正交

Original point: 1 1 1
Transformed by Isometry3d T1:  1 1.41421 1
Transformed by Affine3d T2 (scaled): 2 4 2

T1 translation: 1 0 0
T1 rotation matrix: 正交矩阵
T2 translation: 0 2 0
T2 linear part: 非正交矩阵(带缩放)

综合结论

  • Isometry3d 保证 SE(3) 位姿,适合 SLAM/机器人学。
  • Affine3d 更通用,可以引入缩放/剪切(但在位姿优化中通常不合理)。
  • Isometry3d → Affine3d 永远安全。
  • Affine3d → Isometry3d 可能非法。
  • 处理点云/位姿变换时,建议 优先用 Isometry3d


网站公告

今日签到

点亮在社区的每一天
去签到