I have a 4x4 matrix with translation, rotation, and scaling components, but no shear or other transformations. How do I find its inverse? I'm using the Eigen library in c++.
1
votes
1 Answers
3
votes
This is tricky to get right, since the operations need to be performed in the correct order:
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();
}
As this answer states, the inverse of the top left 3x3 block can be calculated separately:
inv ([ A b ]) = [inv(A) -inv(A)*b]
([ 0 1 ]) [ 0 1 ]
The key insight for the top left block is that the scaling and rotation is equal to a orthogonal (rotation) matrix Q
times a diagonal (scaling) matrix D
: Q*D
. To invert it, do some linear algebra:
inv(Q*D)
= transp(transp(inv(Q*D)))
= transp(inv(transp(Q*D)))
= transp(inv(transp(D)*transp(Q)))
(see this proof), and since D
is diagonal and Q
is orthogonal,
= transp(inv(D*inv(Q)))
= transp(Q*inv(D))).
Q*inv(D)
is easy to find: Since in Q*D
each column is a column of Q
(which is a unit vector) times an entry of D
(which is a scalar), it is enough to divide each column by the square of its norm. This is what the first three lines of the function do.
Written out fully in linear algebra form:
inv ([ Q*D b ]) = [transp(Q*inv(D)) -transp(Q*inv(D))*b]
([ 0 1 ]) [ 0 1 ]