Provide 2D affine transformations.

Interface follows a functional paradigm. Runs on plain NumPy arrays and functions with suffix _cat munch Pandas DataFrames.

mascado.utility.affine.affine_lstsq(origin, target)[source]

Calculate optimal affine transformation in the least-squares sense.

Parameters: origin ((n,2)-shaped array) – x,y points in the domain of the transformation. target ((n,2)-shaped array) – x,y points in the target of the transformation. Matrix representation of affine trafo. (3,3)-shaped array

Notes

The affine transformation is expressed as matrix $$A$$ in homogeneous coordinates:

$\begin{split}\mathtt{target} &= A\cdot\mathtt{origin} \\ \mathbf x^\prime &= A\cdot \mathbf x \\ \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} &= \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\end{split}$

Rewrite as

$\begin{split}\begin{bmatrix} x_1' \\ \vdots \\ x_n' \\ y_1' \\ \vdots \\ y_n' \end{bmatrix} = \begin{bmatrix} x_1 & y_1 & 1 & {} & {} & {} \\ {} & \vdots & {} & {} & \mathbf{0} & {} \\ x_n & y_n & 1 & {} & {} & {} \\ {} & {} & {} & x_1 & y_1 & 1 \\ {} & \mathbf{0} & {} & {} & \vdots & {} \\ {} & {} & {} & x_n & y_n & 1 \\ \end{bmatrix} \begin{bmatrix} a_{11} \\ a_{12} \\ a_{13} \\ a_{21} \\ a_{22} \\ a_{23} \\ \end{bmatrix}\end{split}$

or for short

$\mathbf y = X \cdot \mathbf a\,.$

Use pseudo-inverse $$X^+$$ for least-squares solution:

$\mathbf a = X^+ \cdot \mathbf y$
mascado.utility.affine.affine_lstsq_cat(origin, target, x='x', y='y', ignore_index=False)[source]

Like affine_lstsq with pandas DataFrame.

Parameters: origin ((n,2)-shaped array) target ((n,2)-shaped array) x (string) – Column name of x components of data points. y (string) – Column name of y components of data points. ignore_index (bool) – By default, data points are referenced by their index. Set to True to associate by row position. ValueError – If the catalogs are not of the same length or the indices don’t match.
mascado.utility.affine.affine_trafo(points, trafo)[source]

Apply affine transformation.

Parameters: points ((N,2)-shaped array) – x,y points in the domain of the transformation. trafo ((3,3)-shaped array) – Affine transformation in matrix form. Transformed points. (N,2)-shaped array
mascado.utility.affine.affine_trafo_cat(cat, trafo, x='x', y='y')[source]

Like affine_trafo with pandas DataFrame.

Parameters: cat (pandas.DataFrame) – Catalog with points. trafo ((3,3)-shaped array) – Affine transformation in matrix form. x (string) – Column name of x components of data points. y (string) – Column name of y components of data points. DataFrame with same index and two columns named like input columns. pandas.DataFrame

Examples

>>> trafo = np.array([[1, 0, 3], [2, 1, 0], [0, 0, 1]])
>>> trafo
array([[1, 0, 3],
[2, 1, 0],
[0, 0, 1]])
>>> cat = pd.DataFrame(
...     [[0, 0, 'Anja'], [1, 0, 'Bert'], [2, 2, 'Chris']],
...     index=['A', 'B', 'C'], columns=['x', 'y', 'extra'])
>>> cat
x  y  extra
A  0  0   Anja
B  1  0   Bert
C  2  2  Chris
>>> cat2 = affine_trafo_cat(cat, trafo)
>>> cat2
x  y
A  3  0
B  4  1
C  5  4


To integrate back into the original catalog do

>>> cat1[cat2.columns] = cat2
>>> cat1
x  y  extra
A  3  0   Anja
B  4  1   Bert
C  5  4  Chris