【问题标题】:Eigen - Re-orthogonalization of Rotation MatrixEigen - 旋转矩阵的重新正交化
【发布时间】:2014-04-15 10:15:07
【问题描述】:

在乘以大量旋转矩阵后,由于舍入问题(去正交化),最终结果可能不再是有效的旋转矩阵

重新正交化的一种方法是按照以下步骤操作:

  1. 将旋转矩阵转换为轴角表示 (link)
  2. 将轴角转换回旋转矩阵 (link)

Eigen 库中是否有一些东西通过隐藏所有细节来做同样的事情?或者有没有更好的食谱?

由于特殊的奇点情况,这个过程必须小心处理,所以如果 Eigen 提供了一个更好的工具,那就太好了。

【问题讨论】:

    标签: algorithm math rotation eigen rotational-matrices


    【解决方案1】:

    我没有使用 Eigen,也没有费心去查找 API,但这里有一个简单、计算成本低且稳定的过程来重新正交化旋转矩阵。这个正交化过程取自Direction Cosine Matrix IMU: Theory William Premerlani 和 Paul Bizard;等式 19-21。

    xyz 成为(稍微混乱的)旋转矩阵的行向量。设error=dot(x,y) 其中dot() 是点积。如果矩阵是正交的,xy 的点积,即error 将为零。

    error 分布在 xy 中:x_ort=x-(error/2)*yy_ort=y-(error/2)*x。第三行z_ort=cross(x_ort, y_ort),根据定义与x_orty_ort正交。

    现在,您仍然需要规范化 x_orty_ortz_ort,因为这些向量应该是单位向量。

    x_new = 0.5*(3-dot(x_ort,x_ort))*x_ort
    y_new = 0.5*(3-dot(y_ort,y_ort))*y_ort
    z_new = 0.5*(3-dot(z_ort,z_ort))*z_ort
    

    到此为止,已经完成了。

    使用 Eigen 提供的 API 应该很容易实现这一点。您可以轻松地提出其他正交化程序,但我认为它不会在实践中产生显着差异。我在我的运动跟踪应用程序中使用了上述程序,它运行良好;它既稳定又快速。

    【讨论】:

    • 需要注意的是,这里的归一化过程使用泰勒展开来近似向量幅度。如果需要高精度或矩阵远离正交,则应使用另一种方法。
    • @Praxeolitic 我已经做过:见我的comment from 2 years ago
    • 匿名投票对任何人都没有帮助。答案有什么问题?
    • 您的代码 sn-p 有一些计算错误。应该是x_new = 0.5*(3-dot(x_ort,x_ort))*x_ort。您的代码正在做的是x_new = 1/ (2*(3-dot(x_ort,x_ort))*x_ort) 请注意,由于操作优先级,括号是如何重新排列的。我猜人们复制粘贴了您的代码,但对他们不起作用,他们也没有调试。
    【解决方案2】:

    您可以使用 QR 分解系统地重新正交化,用 Q 因子替换原始矩阵。在库例程中,如有必要,您必须通过否定 Q 中的相应列来检查和纠正 R 的对角线条目是否为正(如果原始矩阵接近正交,则接近 1)。

    最接近给定矩阵的旋转矩阵 Q 是从极坐标或 QP 分解中获得的,其中 P 是半正定对称矩阵。 QP 分解可以迭代计算或使用 SVD 计算。如果后者有分解USV',那么Q=UV'。

    【讨论】:

    • 如果肯定比你在我的答案中得到的结果更好,但代价是计算成本要高得多。
    • 是的,应该做最简单的事情。该问题没有给出维度,因此它可能是您的答案中的 3D 或不同的东西。 [[Easy in 3D 也是使用 Givens 旋转的 QR 分解(巧合的是使用旋转矩阵的欧拉角表示)。编辑:我看到问题中提到了这一点,所以它是 3D。]]
    • 无论如何,至少我赞成你的回答。 :) (虽然我认为 OP 应该已经这样做了。)
    • 嗨 Lutzl,在 Eigen 中进行 QR 分解和获取 Q 矩阵很容易:rotation.householderQr().householderQ()。但是,我不熟悉 houseHolder 方法。这够好吗?您能否在回答中详细说明“检查并更正”和“否定相应列”作为额外步骤?任何参考资料或代码示例也会很棒!
    • 通过将 QR 分解应用于单位矩阵 I 来测试它。结果可能是[Q, R] = [-I, -I]。这是因为 Householder 反射被选择为最稳定的,即避免除以零或接近零。
    【解决方案3】:

    Singular Value Decomposition 应该非常健壮。引用参考:

    令M=UΣV为M的奇异值分解,则R=UV。

    对于您的矩阵,Σ 中的奇异值应该非常接近 1。矩阵 R 保证为orthogonal,这是旋转矩阵的定义属性。如果在计算原始旋转矩阵时没有任何舍入误差,那么 R 将与您的 M 在数值精度范围内完全相同。

    【讨论】:

    • 这本质上是一种计算极分解的方法,M=RP, P=V^TΣV 一个 spd 矩阵,它给出了最接近给定 M 的正交矩阵 R。成本是非SVD 算法的琐碎本质。
    【解决方案4】:

    同时:

    #include <Eigen/Geometry>
    
    Eigen::Matrix3d mmm;
    Eigen::Matrix3d rrr;
                    rrr <<  0.882966, -0.321461,  0.342102,
                            0.431433,  0.842929, -0.321461,
                           -0.185031,  0.431433,  0.882966;
                         // replace this with any rotation matrix
    
    mmm = rrr;
    
    Eigen::AngleAxisd aa(rrr);    // RotationMatrix to AxisAngle
    rrr = aa.toRotationMatrix();  // AxisAngle      to RotationMatrix
    
    std::cout <<     mmm << std::endl << std::endl;
    std::cout << rrr     << std::endl << std::endl;
    std::cout << rrr-mmm << std::endl << std::endl;
    

    这是个好消息,因为我可以摆脱我的自定义方法并减少头痛(如何确定他会处理所有奇点?),

    但我真的很想听听您对更好/替代方法的看法:)

    【讨论】:

    • “感谢您到目前为止的回答!” 在 Stackoverflow,我们不会说谢谢,而是赞成和/或接受答案。 “怎么能确定他会处理所有奇点?” 我猜它假设rrr 实际上是一个旋转矩阵。如果不是(这就是你的问题,你的旋转矩阵搞砸了),那么它很可能做错了什么。这种方法似乎更像是一种临时破解,而不是一种解决方案。
    • 实际上没有必要计算角度,只需将轴旋转矩阵相乘即可​​,无需担心象限和奇点。这就是使用 Givens 旋转方法的 QR 分解。
    • 如果你想改进 A=QR 分解,检查 R 的非对角线部分是否很小,并使用 Q*(I+(R-R')/2) 作为更好的近似值.如果 (RI) 稍大一些,请使用更好的近似 I+(R-R')/2+(R-R')^2/8 或精确的Rodrigues formula 来计算 (R-R') 的矩阵指数/2。 (R'=R的转置,先从矩阵中识别出k,然后应用公式。)
    【解决方案5】:

    另一种方法是使用Eigen::Quaternion 来表示您的轮换。这更容易标准化,rotation*rotation 产品通常更快。如果您有很多 rotation*vector 产品(具有相同的矩阵),您应该将四元数本地转换为 3x3 矩阵。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-28
      • 1970-01-01
      • 2012-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      相关资源
      最近更新 更多