Spaces:
Running
on
Zero
Running
on
Zero
#!/usr/bin/env python2 | |
# -*- coding: utf-8 -*- | |
import numpy as np | |
import utils.utils_poses.ATE.transformations as tfs | |
def get_best_yaw(C): | |
''' | |
maximize trace(Rz(theta) * C) | |
''' | |
assert C.shape == (3, 3) | |
A = C[0, 1] - C[1, 0] | |
B = C[0, 0] + C[1, 1] | |
theta = np.pi / 2 - np.arctan2(B, A) | |
return theta | |
def rot_z(theta): | |
R = tfs.rotation_matrix(theta, [0, 0, 1]) | |
R = R[0:3, 0:3] | |
return R | |
def align_umeyama(model, data, known_scale=False, yaw_only=False): | |
"""Implementation of the paper: S. Umeyama, Least-Squares Estimation | |
of Transformation Parameters Between Two Point Patterns, | |
IEEE Trans. Pattern Anal. Mach. Intell., vol. 13, no. 4, 1991. | |
model = s * R * data + t | |
Input: | |
model -- first trajectory (nx3), numpy array type | |
data -- second trajectory (nx3), numpy array type | |
Output: | |
s -- scale factor (scalar) | |
R -- rotation matrix (3x3) | |
t -- translation vector (3x1) | |
t_error -- translational error per point (1xn) | |
""" | |
# substract mean | |
mu_M = model.mean(0) | |
mu_D = data.mean(0) | |
model_zerocentered = model - mu_M | |
data_zerocentered = data - mu_D | |
n = np.shape(model)[0] | |
# correlation | |
C = 1.0/n*np.dot(model_zerocentered.transpose(), data_zerocentered) | |
sigma2 = 1.0/n*np.multiply(data_zerocentered, data_zerocentered).sum() | |
U_svd, D_svd, V_svd = np.linalg.linalg.svd(C) | |
D_svd = np.diag(D_svd) | |
V_svd = np.transpose(V_svd) | |
S = np.eye(3) | |
if(np.linalg.det(U_svd)*np.linalg.det(V_svd) < 0): | |
S[2, 2] = -1 | |
if yaw_only: | |
rot_C = np.dot(data_zerocentered.transpose(), model_zerocentered) | |
theta = get_best_yaw(rot_C) | |
R = rot_z(theta) | |
else: | |
R = np.dot(U_svd, np.dot(S, np.transpose(V_svd))) | |
if known_scale: | |
s = 1 | |
else: | |
s = 1.0/sigma2*np.trace(np.dot(D_svd, S)) | |
t = mu_M-s*np.dot(R, mu_D) | |
return s, R, t | |