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]]


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


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?

  • 2
    $\begingroup$ Take[tr[[2, 1]], 2, 2]? $\endgroup$
    – J. M.'s torpor
    Aug 10 '17 at 13:47
  • $\begingroup$ @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? $\endgroup$
    – mrz
    Aug 10 '17 at 13:55
  • 1
    $\begingroup$ The function already composes the transformations; you'll need to do extra linear algebra (e.g. w/ QRDecomposition[]) to separate them. $\endgroup$
    – J. M.'s torpor
    Aug 10 '17 at 14:01

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[1467827]; (* for reproducibility *)
            rot = RotationMatrix[RandomReal[2 π]];
            sca = DiagonalMatrix[{#, #} & @ RandomReal[3]];
            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]

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

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

                          AffineTransform[{rot.sca, tr}], 
                          AffineTransform[{RotationMatrix[θ].ScalingMatrix[sc], v}]]] -
  • $\begingroup$ thanks a lot for the solution $\endgroup$
    – mrz
    Mar 24 '18 at 7:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.