Determining a uniform six point affine transformation matrix in 3D using Python

Three points are assigned to me:

p1 = [1.0, 1.0, 1.0]
p2 = [1.0, 2.0, 1.0]
p3 = [1.0, 1.0, 2.0]

      

and their converted copies:

p1_prime = [2.414213562373094,  5.732050807568877, 0.7320508075688767]
p2_prime = [2.7677669529663684, 6.665063509461097, 0.6650635094610956]
p3_prime = [2.7677669529663675, 5.665063509461096, 1.6650635094610962]

      

The affine transformation matrix has the form

trans_mat = np.array([[…, …, …, …],
                      […, …, …, …],
                      […, …, …, …],
                      […, …, …, …]])

      

such that for

import numpy as np

def transform_pt(point, trans_mat):
    a  = np.array([point[0], point[1], point[2], 1])
    ap = np.dot(a, trans_mat)[:3]
    return [ap[0], ap[1], ap[2]]

      

You'll get:

transform_pt(p1, trans_mat) == p1_prime
transform_pt(p2, trans_mat) == p2_prime
transform_pt(p3, trans_mat) == p3_prime

      

Assuming the transformation is uniform (consists of rotations and translations only), how can I determine this transformation matrix?

From the CAD program, I know that the matrix:

trans_mat = np.array([[0.866025403784, -0.353553390593, -0.353553390593, 0],
                      [0.353553390593,  0.933012701892, -0.066987298108, 0],
                      [0.353553390593, -0.066987298108,  0.933012701892, 0],
                      [0.841081377402,  5.219578794378,  0.219578794378, 1]])

      

I would like to know how this can be found.

+3


source to share


4 answers


Six points alone are not enough to unambiguously define an affine transformation. However, based on what you asked in the question earlier (shortly before deleting it), as well as your comment , it would seem that you are not just looking for an affine transformation, but a homogeneous affine transformation.

This answer by robjohn provides a solution to the problem. While it solves a more general problem with many points, the 6-point solution can be found at the very end of the answer. I'll decode it here in a more programmer-friendly format:

import numpy as np

def recover_homogenous_affine_transformation(p, p_prime):
    '''
    Find the unique homogeneous affine transformation that
    maps a set of 3 points to another set of 3 points in 3D
    space:

        p_prime == np.dot(p, R) + t

    where `R` is an unknown rotation matrix, `t` is an unknown
    translation vector, and `p` and `p_prime` are the original
    and transformed set of points stored as row vectors:

        p       = np.array((p1,       p2,       p3))
        p_prime = np.array((p1_prime, p2_prime, p3_prime))

    The result of this function is an augmented 4-by-4
    matrix `A` that represents this affine transformation:

        np.column_stack((p_prime, (1, 1, 1))) == \
            np.dot(np.column_stack((p, (1, 1, 1))), A)

    Source: https://math.stackexchange.com/a/222170 (robjohn)
    '''

    # construct intermediate matrix
    Q       = p[1:]       - p[0]
    Q_prime = p_prime[1:] - p_prime[0]

    # calculate rotation matrix
    R = np.dot(np.linalg.inv(np.row_stack((Q, np.cross(*Q)))),
               np.row_stack((Q_prime, np.cross(*Q_prime))))

    # calculate translation vector
    t = p_prime[0] - np.dot(p[0], R)

    # calculate affine transformation matrix
    return np.column_stack((np.row_stack((R, t)),
                            (0, 0, 0, 1)))

      



For your sample inputs, this returns the same matrix as in the CAD program:

>>> recover_homogenous_affine_transformation(
        np.array(((1.0,1.0,1.0),
                  (1.0,2.0,1.0),
                  (1.0,1.0,2.0))),
        np.array(((2.4142135623730940, 5.732050807568877, 0.7320508075688767),
                  (2.7677669529663684, 6.665063509461097, 0.6650635094610956),
                  (2.7677669529663675, 5.665063509461096, 1.6650635094610962))))
array([[ 0.8660254 , -0.35355339, -0.35355339,  0.        ],
       [ 0.35355339,  0.9330127 , -0.0669873 ,  0.        ],
       [ 0.35355339, -0.0669873 ,  0.9330127 ,  0.        ],
       [ 0.84108138,  5.21957879,  0.21957879,  1.        ]])

      

+2


source


Finding a transformation is similar to solving any system of equations with an unknown. First, you need to write down an equation, which in your case means that you need to know what transformation you are looking for. For example. hard translation takes three parameters (x, y and z), so you must have at least three parameters. The total rotation takes three more parameters, which give you six unknowns. Scaling gives you three more parameters for 9 parameters. Since you are only listing three points that yield nine unknows, this is the conversion you are looking for. This means that you ignore any shifts and projections. You should always be aware of the type of conversions you are looking for.



Once you know the type of transformation, you have to write down the matrix equation and then solve for the unknowns. This can be done with a linear algebra library using matrix multiplication for example. by numpy.

+2


source


It is possible to define a transformation matrix if the original data (p1, p2, p3 i n is your case) and the transformed data (p1_prime, p2_prime, p3_prime) are given below:

>>> p   # original data
array([[ 1.,  1.,  1.],
       [ 1.,  2.,  1.],
       [ 1.,  1.,  2.]])
>>> p_prime  # transformed data
array([[ 2.41421356,  5.73205081,  0.73205081],
       [ 2.76776695,  6.66506351,  0.66506351],
       [ 2.76776695,  5.66506351,  1.66506351]])
# Get transformation matrix
>>> trans = np.dot(np.linalg.inv(p),p_prime)
>>> trans  # transformation matrix
array([[ 1.70710678,  4.86602541, -0.13397459],
       [ 0.35355339,  0.9330127 , -0.0669873 ],
       [ 0.35355339, -0.0669873 ,  0.9330127 ]])
# obtain transformed data from original data and transformation matrix
>>> np.dot(a, trans)  
array([[ 2.41421356,  5.73205081,  0.73205081],
       [ 2.76776695,  6.66506351,  0.66506351],
       [ 2.76776695,  5.66506351,  1.66506351]])

      

In your case, since there is unknown data, transformed values ap[3]

for all three points, the transformation matrix cannot be obtained. It can only be obtained if these three values ​​are known.

+1


source


This problem is called point-to-point registration or point set registration .

For hard conversion, i.e. ignoring shearing and scaling, I like this tutorial . I've been looking for centroids and applying singular decomposition.

Note that for your particular case, with exactly three dots, you can find a closed form solution.

OpenCV is good to help with this.

Oh, check Finding translation and scaling to two sets of points to get the least square error at their distance?

0


source







All Articles