Source code for cogrecon.core.similarity_transform

import numpy as np


[docs]def similarity_transform(from_points, to_points): """ References - [Umeyama's paper](http://localhost:3690/files/doc/Umeyama_least_square.pdf) - [CarloNicolini's python implementation](https://gist.github.com/CarloNicolini/7118015) Modified by Kevin Horecka Feb 11, 2017 :param from_points: a list of points (list of floats) from which to find a transform :param to_points: a list points (list of floats) to which to find a transform :return: the rotation matrix, scaling, and translation between from_points and to_points via SVD """ assert len(from_points.shape) == 2, \ "from_points must be a m x n array" assert from_points.shape == to_points.shape, \ "from_points and to_points must have the same shape" N, m = from_points.shape mean_from = from_points.mean(axis=0) mean_to = to_points.mean(axis=0) delta_from = from_points - mean_from # N x m delta_to = to_points - mean_to # N x m sigma_from = (delta_from * delta_from).sum(axis=1).mean() # sigma_to = (delta_to * delta_to).sum(axis=1).mean() cov_matrix = delta_to.T.dot(delta_from) / N U, d, V_t = np.linalg.svd(cov_matrix, full_matrices=True) cov_rank = np.linalg.matrix_rank(cov_matrix) S = np.eye(m) if cov_rank >= m - 1 and np.linalg.det(cov_matrix) < 0: S[m - 1, m - 1] = -1 elif cov_rank < m - 1: raise ValueError("colinearility detected in covariance matrix:\n{}".format(cov_matrix)) R_out = U.dot(S).dot(V_t) c_out = (d * S.diagonal()).sum() / sigma_from t_out = mean_to - c_out * R_out.dot(mean_from) return R_out, c_out, t_out
if __name__ == "__main__": # Testing case from the original paper by Umeyama. # each row represents a point f_points = np.array([[0, 0], [1, 0], [0, 2]]) t_points = np.array([[0, 0], [-1, 0], [0, 2]]) c_ans = 0.721 R_ans = np.array([[0.832, 0.555], [-0.555, 0.832]]) t_ans = np.array([-0.8, 0.4]) M_ans = c_ans * R_ans R, c, t = similarity_transform(f_points, t_points) assert np.allclose(c*R, M_ans, atol=1e-3) and np.allclose(t, t_ans, atol=1e-3), "test from Umeyama's paper fail" print("test from Umeyama's paper pass") # test in 3D space f_points = np.array([[0, 0, 1], [1, 0, 3], [2, 5, 8]]) M_ans = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) t_ans = np.array([1, 1, 1]) t_points = M_ans.dot(f_points.T).T + t_ans R, c, t = similarity_transform(f_points, t_points) assert np.allclose(c*R, M_ans) and np.allclose(t, t_ans), "test for 3D space fail" print("test for 3D space pass")