I have a set of points that are effectively 3 vertices of a 45-45-90 right triangle and some other points, a, that should map to them.
import numpy as np
points = np.array([
( 90, 416),
(398, 390),
(374, 84)
])
a = np.array([
(0, 1), # maps to (90, 416)
(1, 1), # maps to (398, 390)
(1, 0) # maps to (374, 84)
])
I want to find the similarity transformation that properly maps a to points.
from skimage import transform
# transformation that makes sense to me
T1 = transform.estimate_transform(
ttype="similarity",
src=a,
dst=points
)
# invert the rotation for no reason
# other than to show that it works
T2 = transform.SimilarityTransform(
scale=T1.scale,
rotation=-T1.rotation,
translation=T1.translation
)
# apply transformations via matrix multiplication
a_T1 = a @ T1.params[:2, :2] + T1.params[:2, 2]
a_T2 = a @ T2.params[:2, :2] + T2.params[:2, 2]
Why is it that T2 (where I just inverted the rotation for no real reason other than I eventually found out that it works) yields the better mapping? Or am I making a dumb mistake in my implementation?

It's not you. There's lots of different conventions around transformation matrices and it just so happens that
(M @ x.T).Tas the conventionT2.params[:2, :2]is equal toT1.params[:2, :2].T(This is not generally true, if you have skew.)But, I personally am always confused by the conventions here myself. To figure it out I had to know that skimage transforms have a
__call__method, so you can just apply them withT1(a), which gives the correct results. So now it was just a matter of looking at the source code and seeing that it calls_apply_mat, which looks like this:For your transform (which is affine), this is essentially equivalent to
(T1.params[:2, :2] @ a.T).T + T1.params[:2, 2], which is equal toa @ T1.params[:2, :2].T + T1.params[:2, 2], again, the transpose of what you were computing and equal toa @ T2.params[:2, :2] + T2.params[:2, 2].Even though it's confusing to have multiple conventions out there, I hope this clarifies why things were looking wonky!