kairunwen's picture
add code
35e2073
raw
history blame
3.06 kB
import numpy as np
import torch
from utils.utils_poses.ATE.align_utils import alignTrajectory
from utils.utils_poses.lie_group_helper import SO3_to_quat, convert3x4_4x4
def pts_dist_max(pts):
"""
:param pts: (N, 3) torch or np
:return: scalar
"""
if torch.is_tensor(pts):
dist = pts.unsqueeze(0) - pts.unsqueeze(1) # (1, N, 3) - (N, 1, 3) -> (N, N, 3)
dist = dist[0] # (N, 3)
dist = dist.norm(dim=1) # (N, )
max_dist = dist.max()
else:
dist = pts[None, :, :] - pts[:, None, :] # (1, N, 3) - (N, 1, 3) -> (N, N, 3)
dist = dist[0] # (N, 3)
dist = np.linalg.norm(dist, axis=1) # (N, )
max_dist = dist.max()
return max_dist
def align_ate_c2b_use_a2b(traj_a, traj_b, traj_c=None, method='sim3'):
"""Align c to b using the sim3 from a to b.
:param traj_a: (N0, 3/4, 4) torch tensor
:param traj_b: (N0, 3/4, 4) torch tensor
:param traj_c: None or (N1, 3/4, 4) torch tensor
:return: (N1, 4, 4) torch tensor
"""
device = traj_a.device
if traj_c is None:
traj_c = traj_a.clone()
traj_a = traj_a.float().cpu().numpy()
traj_b = traj_b.float().cpu().numpy()
traj_c = traj_c.float().cpu().numpy()
R_a = traj_a[:, :3, :3] # (N0, 3, 3)
t_a = traj_a[:, :3, 3] # (N0, 3)
quat_a = SO3_to_quat(R_a) # (N0, 4)
R_b = traj_b[:, :3, :3] # (N0, 3, 3)
t_b = traj_b[:, :3, 3] # (N0, 3)
quat_b = SO3_to_quat(R_b) # (N0, 4)
# This function works in quaternion.
# scalar, (3, 3), (3, ) gt = R * s * est + t.
s, R, t = alignTrajectory(t_a, t_b, quat_a, quat_b, method=method)
# reshape tensors
R = R[None, :, :].astype(np.float32) # (1, 3, 3)
t = t[None, :, None].astype(np.float32) # (1, 3, 1)
s = float(s)
R_c = traj_c[:, :3, :3] # (N1, 3, 3)
t_c = traj_c[:, :3, 3:4] # (N1, 3, 1)
R_c_aligned = R @ R_c # (N1, 3, 3)
t_c_aligned = s * (R @ t_c) + t # (N1, 3, 1)
traj_c_aligned = np.concatenate([R_c_aligned, t_c_aligned], axis=2) # (N1, 3, 4)
# append the last row
traj_c_aligned = convert3x4_4x4(traj_c_aligned) # (N1, 4, 4)
traj_c_aligned = torch.from_numpy(traj_c_aligned).to(device)
return traj_c_aligned # (N1, 4, 4)
def align_scale_c2b_use_a2b(traj_a, traj_b, traj_c=None):
'''Scale c to b using the scale from a to b.
:param traj_a: (N0, 3/4, 4) torch tensor
:param traj_b: (N0, 3/4, 4) torch tensor
:param traj_c: None or (N1, 3/4, 4) torch tensor
:return:
scaled_traj_c (N1, 4, 4) torch tensor
scale scalar
'''
if traj_c is None:
traj_c = traj_a.clone()
t_a = traj_a[:, :3, 3] # (N, 3)
t_b = traj_b[:, :3, 3] # (N, 3)
# scale estimated poses to colmap scale
# s_a2b: a*s ~ b
scale_a2b = pts_dist_max(t_b) / pts_dist_max(t_a)
traj_c[:, :3, 3] *= scale_a2b
if traj_c.shape[1] == 3:
traj_c = convert3x4_4x4(traj_c) # (N, 4, 4)
return traj_c, scale_a2b # (N, 4, 4)