(points_start, points_end)
return transform
Fit an affine transformation from starting points to ending points through a
    least square procedure.

    :param numpy.ndarray points_start: set of starting points.
    :param numpy.ndarray points_end: set of ending points.

    :return: transform_vector: function that transforms a vector according to
        the affine map. It takes a source vector and return a vector transformed
        by the reduced row echelon form of the map.
    :rtype: function

    :Example:

    >>> import pygem.affine as at

    >>> # Example of a rotation (affine transformation)
    >>> p_start = np.array([[1,0,0], [0,1,0], [0,0,1], [0,0,0]])
    >>> p_end = np.array([[0,1,0], [-1,0,0], [0,0,1], [0,0,0]])
    >>> v_test = np.array([1., 2., 3.])
    >>> transformation = at.affine_points_fit(p_start, p_end)
    >>> v_trans = transformation(v_test)
Fit an affine transformation from starting points to ending points through a
    least square procedure.
Fit an affine transformation from starting points to ending points through a least square procedure .
def fit_affine_transformation(points_start, points_end):
    """
    Fit an affine transformation from starting points to ending points through a
    least square procedure.

    :param numpy.ndarray points_start: set of starting points.
    :param numpy.ndarray points_end: set of ending points.

    :return: transform_vector: function that transforms a vector according to
        the affine map. It takes a source vector and return a vector transformed
        by the reduced row echelon form of the map.
    :rtype: function

    :Example:

    >>> import pygem.affine as at

    >>> # Example of a rotation (affine transformation)
    >>> p_start = np.array([[1,0,0], [0,1,0], [0,0,1], [0,0,0]])
    >>> p_end = np.array([[0,1,0], [-1,0,0], [0,0,1], [0,0,0]])
    >>> v_test = np.array([1., 2., 3.])
    >>> transformation = at.affine_points_fit(p_start, p_end)
    >>> v_trans = transformation(v_test)
    """
    if len(points_start) != len(points_end):
        raise RuntimeError("points_start and points_end must be of same size.")

    dim = len(points_start[0])
    if len(points_start) < dim:
        raise RuntimeError(
            "Too few starting points => under-determined system.")

    def pad_column_ones(x):
        """ Add right column of 1.0 to the given 2D numpy array """
        return np.hstack([x, np.ones((x.shape[0], 1))])

    def unpad_column(x):
        """ Remove last column to the given 2D numpy array """
        return x[:, :-1]

    def transform(src):

        shape = src.shape

        X = pad_column_ones(points_start)
        Y = pad_column_ones(points_end)

        A, res, rank, _ = np.linalg.lstsq(X, Y, rcond=None)
        # TODO add check condition number
        #if np.linalg.cond(A) >= 1 / sys.float_info.epsilon:
        #    raise RuntimeError(
        #            "Error: singular matrix. Points are probably coplanar.")
        return unpad_column(
                np.dot(
                    pad_column_ones(np.atleast_2d(src)),
                    A)
                ).reshape(shape)

    return transform
def fit_affine_transformation ( points_start , points_end ) : if len ( points_start ) != len ( points_end ) : raise RuntimeError ( "points_start and points_end must be of same size." ) dim = len ( points_start [ 0 ] ) if len ( points_start ) < dim : raise RuntimeError ( "Too few starting points => under-determined system." ) def pad_column_ones ( x ) : """ Add right column of 1.0 to the given 2D numpy array """ return np . hstack ( [ x , np . ones ( ( x . shape [ 0 ] , 1 ) ) ] ) def unpad_column ( x ) : """ Remove last column to the given 2D numpy array """ return x [ : , : - 1 ] def transform ( src ) : shape = src . shape X = pad_column_ones ( points_start ) Y = pad_column_ones ( points_end ) A , res , rank , _ = np . linalg . lstsq ( X , Y , rcond = None ) # TODO add check condition number #if np.linalg.cond(A) >= 1 / sys.float_info.epsilon: #    raise RuntimeError( #            "Error: singular matrix. Points are probably coplanar.") return unpad_column ( np . dot ( pad_column_ones ( np . atleast_2d ( src ) ) , A ) ) . reshape ( shape ) return transform