# Extracting scaling factor and rotation angle from TransformationFunction

I have successfully transformed two 2D data sets (data1, data2) by using FindGeometricTransform:

tr = FindGeometricTransform[data1, data2, TransformationClass -> "Similarity"]


"Similarity" considers translation, rotation and scaling.

As a result, I get the following: The translation is contained in the last column:

xTranslation = tr[[2, 1, 1, 3]]

-9.49427

yTranslation = tr[[2, 1, 2, 3]]

-13.1009


How can I find the rotation angle and scaling factor from the resulting transformation matrix {1.00748,0.00926369},{-0.00926369,1.00748}}? Is Mathematica storing the information about the rotation and scaling matrices somewhere, and not only showing the result of the matrix multiplication?

• Take[tr[[2, 1]], 2, 2]? – J. M. is away Aug 10 '17 at 13:47
• @J. M: Thank you. What do you think about my last sentence of the question: Is mathematica somewhere storing the information about the rotation and sclaing matrices and not only showing the result of the matrix multiplication? – mrz Aug 10 '17 at 13:55
• The function already composes the transformations; you'll need to do extra linear algebra (e.g. w/ QRDecomposition[]) to separate them. – J. M. is away Aug 10 '17 at 14:01

## 1 Answer

To demonstrate my suggestion in the comments, let's randomly generate the composition of a scaling, a rotation, and a translation, and apply it to a list of known points:

BlockRandom[SeedRandom; (* for reproducibility *)
rot = RotationMatrix[RandomReal[2 π]];
sca = DiagonalMatrix[{#, #} & @ RandomReal];
tr = RandomReal[{-2, 2}, 2]];

pts = {{88, 59}, {96, 11}, {66, 2}, {54, 62}};
new = AffineTransform[{rot.sca, tr}][pts];


Use FindGeometricTransform[] to determine the TransformationFunction[]:

{err, tf} = FindGeometricTransform[pts, new, TransformationClass -> "Similarity"];


The first thing to do to recover the parameters from the TransformationFunction[] is to use TransformationMatrix[] to obtain the associated homogeneous matrix:

tm = TransformationMatrix[tf]
{{0.221083, 0.272837, 0.0193194}, {-0.272837, 0.221083, 0.426155}, {0, 0, 1}}


We can easily get the translation vector from tm:

v = tm[[1 ;; -2, -1]]
{0.0193194, 0.426155}


Now, for the linear algebra. Apply the QR decomposition on the leading submatrix corresponding to the composed rotation and scaling:

{q, r} = QRDecomposition[tm[[;; -2, ;; -2]]]
{{{-0.629568, 0.776946}, {0.776946, 0.629568}}, {{-0.351166, 0.}, {0., 0.351166}}}


Note that the r factor is diagonal, which indicates a genuine scaling transformation. Had the off-diagonal entry been nonzero, this is an indication that the two sets of points are not related by a scaling transformation, and you have more work to do.

In any event, the diagonal elements are not all positive, but we can perform a normalization so that we have a genuine scaling matrix:

di = DiagonalMatrix[Sign[Diagonal[r]]];
sc = Diagonal[di.r]
{0.351166, 0.351166}


Finally, let's get the angle of the rotation matrix:

θ = ArcTan @@ First[di.q]
-0.8898


We now have all the needed parameters. Let's do a few checks:

Max[Norm /@ (AffineTransform[{RotationMatrix[θ].ScalingMatrix[sc], v}][new] - pts)]
2.92964*10^-14

Norm[TransformationMatrix[Composition[
AffineTransform[{rot.sca, tr}],
AffineTransform[{RotationMatrix[θ].ScalingMatrix[sc], v}]]] -
IdentityMatrix]
3.01074*10^-14

• thanks a lot for the solution – mrz Mar 24 '18 at 7:11