如何通过平移,旋转和缩放反转仿射变换?

时间:2015-05-29 18:46:45

标签: c++ linear-algebra eigen

我有一个带有平移,旋转和缩放组件的4x4矩阵,但没有剪切或其他变换。我如何找到它的逆?我在c ++中使用了Eigen库。

1 个答案:

答案 0 :(得分:2)

要做到这一点很棘手,因为需要按正确的顺序执行操作:

template<class Derived>
Matrix4f AffineInverse(const Eigen::MatrixBase<Derived>& mat)
{
    Matrix3f RotSclInv = (
        mat.block<3, 3>(0, 0).array().rowwise()
        / mat.block<3, 3>(0, 0).colwise().squaredNorm().array() //scaling
        ).transpose(); //rotation
    return (Matrix4f(4,4) << RotSclInv
        , -RotSclInv * mat.block<3, 1>(0, 3) //translation
        , 0, 0, 0, 1).finished();
}

作为this answer状态,左上角3x3块的倒数可以单独计算:

inv ([ A b ]) = [inv(A)  -inv(A)*b]
    ([ 0 1 ])   [  0          1   ]

左上方块的关键见解是缩放和旋转等于正交(旋转)矩阵Q乘以对角线(缩放)矩阵DQ*D。要反转它,做一些线性代数:

  inv(Q*D)
= transp(transp(inv(Q*D)))
= transp(inv(transp(Q*D)))
= transp(inv(transp(D)*transp(Q)))

(请参阅this proof),由于D是对角线且Q是正交的,

= transp(inv(D*inv(Q)))
= transp(Q*inv(D))).

Q*inv(D)很容易找到:因为在Q*D中,每列都是Q的列(单位向量)乘以D的条目(即标量),将每列按其标准的平方划分就足够了。这就是函数的前三行。

完全以线性代数形式写出:

inv ([ Q*D b ]) = [transp(Q*inv(D))  -transp(Q*inv(D))*b]
    ([ 0   1 ])   [       0                 1           ]