StructDiffusionDemo / src /StructDiffusion /utils /rotation_continuity.py
Weiyu Liu
compute rot 6d does not depend on cuda
3827c6d
Raw
History Blame Contribute Delete
13.2 kB
import torch
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
# Code adapted from the rotation continuity repo (https://github.com/papagina/RotationContinuity)
#T_poses num*3
#r_matrix batch*3*3
def compute_pose_from_rotation_matrix(T_pose, r_matrix):
batch=r_matrix.shape[0]
joint_num = T_pose.shape[0]
r_matrices = r_matrix.view(batch,1, 3,3).expand(batch,joint_num, 3,3).contiguous().view(batch*joint_num,3,3)
src_poses = T_pose.view(1,joint_num,3,1).expand(batch,joint_num,3,1).contiguous().view(batch*joint_num,3,1)
out_poses = torch.matmul(r_matrices, src_poses) #(batch*joint_num)*3*1
return out_poses.view(batch, joint_num, 3)
# batch*n
def normalize_vector( v, return_mag =False):
batch=v.shape[0]
v_mag = torch.sqrt(v.pow(2).sum(1))# batch
v_mag = torch.max(v_mag, torch.autograd.Variable(torch.FloatTensor([1e-8]).to(v.device)))
v_mag = v_mag.view(batch,1).expand(batch,v.shape[1])
v = v/v_mag
if(return_mag==True):
return v, v_mag[:,0]
else:
return v
# u, v batch*n
def cross_product( u, v):
batch = u.shape[0]
#print (u.shape)
#print (v.shape)
i = u[:,1]*v[:,2] - u[:,2]*v[:,1]
j = u[:,2]*v[:,0] - u[:,0]*v[:,2]
k = u[:,0]*v[:,1] - u[:,1]*v[:,0]
out = torch.cat((i.view(batch,1), j.view(batch,1), k.view(batch,1)),1)#batch*3
return out
#poses batch*6
#poses
def compute_rotation_matrix_from_ortho6d(ortho6d):
x_raw = ortho6d[:,0:3]#batch*3
y_raw = ortho6d[:,3:6]#batch*3
x = normalize_vector(x_raw) #batch*3
z = cross_product(x,y_raw) #batch*3
z = normalize_vector(z)#batch*3
y = cross_product(z,x)#batch*3
x = x.view(-1,3,1)
y = y.view(-1,3,1)
z = z.view(-1,3,1)
matrix = torch.cat((x,y,z), 2) #batch*3*3
return matrix
#in batch*6
#out batch*5
def stereographic_project(a):
dim = a.shape[1]
a = normalize_vector(a)
out = a[:,0:dim-1]/(1-a[:,dim-1])
return out
#in a batch*5, axis int
def stereographic_unproject(a, axis=None):
"""
Inverse of stereographic projection: increases dimension by one.
"""
batch=a.shape[0]
if axis is None:
axis = a.shape[1]
s2 = torch.pow(a,2).sum(1) #batch
ans = torch.autograd.Variable(torch.zeros(batch, a.shape[1]+1).cuda()) #batch*6
unproj = 2*a/(s2+1).view(batch,1).repeat(1,a.shape[1]) #batch*5
if(axis>0):
ans[:,:axis] = unproj[:,:axis] #batch*(axis-0)
ans[:,axis] = (s2-1)/(s2+1) #batch
ans[:,axis+1:] = unproj[:,axis:] #batch*(5-axis) # Note that this is a no-op if the default option (last axis) is used
return ans
#a batch*5
#out batch*3*3
def compute_rotation_matrix_from_ortho5d(a):
batch = a.shape[0]
proj_scale_np = np.array([np.sqrt(2)+1, np.sqrt(2)+1, np.sqrt(2)]) #3
proj_scale = torch.autograd.Variable(torch.FloatTensor(proj_scale_np).cuda()).view(1,3).repeat(batch,1) #batch,3
u = stereographic_unproject(a[:, 2:5] * proj_scale, axis=0)#batch*4
norm = torch.sqrt(torch.pow(u[:,1:],2).sum(1)) #batch
u = u/ norm.view(batch,1).repeat(1,u.shape[1]) #batch*4
b = torch.cat((a[:,0:2], u),1)#batch*6
matrix = compute_rotation_matrix_from_ortho6d(b)
return matrix
#quaternion batch*4
def compute_rotation_matrix_from_quaternion( quaternion):
batch=quaternion.shape[0]
quat = normalize_vector(quaternion).contiguous()
qw = quat[...,0].contiguous().view(batch, 1)
qx = quat[...,1].contiguous().view(batch, 1)
qy = quat[...,2].contiguous().view(batch, 1)
qz = quat[...,3].contiguous().view(batch, 1)
# Unit quaternion rotation matrices computatation
xx = qx*qx
yy = qy*qy
zz = qz*qz
xy = qx*qy
xz = qx*qz
yz = qy*qz
xw = qx*qw
yw = qy*qw
zw = qz*qw
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
return matrix
#axisAngle batch*4 angle, x,y,z
def compute_rotation_matrix_from_axisAngle( axisAngle):
batch = axisAngle.shape[0]
theta = torch.tanh(axisAngle[:,0])*np.pi #[-180, 180]
sin = torch.sin(theta*0.5)
axis = normalize_vector(axisAngle[:,1:4]) #batch*3
qw = torch.cos(theta*0.5)
qx = axis[:,0]*sin
qy = axis[:,1]*sin
qz = axis[:,2]*sin
# Unit quaternion rotation matrices computatation
xx = (qx*qx).view(batch,1)
yy = (qy*qy).view(batch,1)
zz = (qz*qz).view(batch,1)
xy = (qx*qy).view(batch,1)
xz = (qx*qz).view(batch,1)
yz = (qy*qz).view(batch,1)
xw = (qx*qw).view(batch,1)
yw = (qy*qw).view(batch,1)
zw = (qz*qw).view(batch,1)
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
return matrix
#axisAngle batch*3 (x,y,z)*theta
def compute_rotation_matrix_from_Rodriguez( rod):
batch = rod.shape[0]
axis, theta = normalize_vector(rod, return_mag=True)
sin = torch.sin(theta)
qw = torch.cos(theta)
qx = axis[:,0]*sin
qy = axis[:,1]*sin
qz = axis[:,2]*sin
# Unit quaternion rotation matrices computatation
xx = (qx*qx).view(batch,1)
yy = (qy*qy).view(batch,1)
zz = (qz*qz).view(batch,1)
xy = (qx*qy).view(batch,1)
xz = (qx*qz).view(batch,1)
yz = (qy*qz).view(batch,1)
xw = (qx*qw).view(batch,1)
yw = (qy*qw).view(batch,1)
zw = (qz*qw).view(batch,1)
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
return matrix
#axisAngle batch*3 a,b,c
def compute_rotation_matrix_from_hopf( hopf):
batch = hopf.shape[0]
theta = (torch.tanh(hopf[:,0])+1.0)*np.pi/2.0 #[0, pi]
phi = (torch.tanh(hopf[:,1])+1.0)*np.pi #[0,2pi)
tao = (torch.tanh(hopf[:,2])+1.0)*np.pi #[0,2pi)
qw = torch.cos(theta/2)*torch.cos(tao/2)
qx = torch.cos(theta/2)*torch.sin(tao/2)
qy = torch.sin(theta/2)*torch.cos(phi+tao/2)
qz = torch.sin(theta/2)*torch.sin(phi+tao/2)
# Unit quaternion rotation matrices computatation
xx = (qx*qx).view(batch,1)
yy = (qy*qy).view(batch,1)
zz = (qz*qz).view(batch,1)
xy = (qx*qy).view(batch,1)
xz = (qx*qz).view(batch,1)
yz = (qy*qz).view(batch,1)
xw = (qx*qw).view(batch,1)
yw = (qy*qw).view(batch,1)
zw = (qz*qw).view(batch,1)
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
return matrix
#euler batch*4
#output cuda batch*3*3 matrices in the rotation order of XZ'Y'' (intrinsic) or YZX (extrinsic)
def compute_rotation_matrix_from_euler(euler):
batch=euler.shape[0]
c1=torch.cos(euler[:,0]).view(batch,1)#batch*1
s1=torch.sin(euler[:,0]).view(batch,1)#batch*1
c2=torch.cos(euler[:,2]).view(batch,1)#batch*1
s2=torch.sin(euler[:,2]).view(batch,1)#batch*1
c3=torch.cos(euler[:,1]).view(batch,1)#batch*1
s3=torch.sin(euler[:,1]).view(batch,1)#batch*1
row1=torch.cat((c2*c3, -s2, c2*s3 ), 1).view(-1,1,3) #batch*1*3
row2=torch.cat((c1*s2*c3+s1*s3, c1*c2, c1*s2*s3-s1*c3), 1).view(-1,1,3) #batch*1*3
row3=torch.cat((s1*s2*c3-c1*s3, s1*c2, s1*s2*s3+c1*c3), 1).view(-1,1,3) #batch*1*3
matrix = torch.cat((row1, row2, row3), 1) #batch*3*3
return matrix
#euler_sin_cos batch*6
#output cuda batch*3*3 matrices in the rotation order of XZ'Y'' (intrinsic) or YZX (extrinsic)
def compute_rotation_matrix_from_euler_sin_cos(euler_sin_cos):
batch=euler_sin_cos.shape[0]
s1 = euler_sin_cos[:,0].view(batch,1)
c1 = euler_sin_cos[:,1].view(batch,1)
s2 = euler_sin_cos[:,2].view(batch,1)
c2 = euler_sin_cos[:,3].view(batch,1)
s3 = euler_sin_cos[:,4].view(batch,1)
c3 = euler_sin_cos[:,5].view(batch,1)
row1=torch.cat((c2*c3, -s2, c2*s3 ), 1).view(-1,1,3) #batch*1*3
row2=torch.cat((c1*s2*c3+s1*s3, c1*c2, c1*s2*s3-s1*c3), 1).view(-1,1,3) #batch*1*3
row3=torch.cat((s1*s2*c3-c1*s3, s1*c2, s1*s2*s3+c1*c3), 1).view(-1,1,3) #batch*1*3
matrix = torch.cat((row1, row2, row3), 1) #batch*3*3
return matrix
#matrices batch*3*3
#both matrix are orthogonal rotation matrices
#out theta between 0 to 180 degree batch
def compute_geodesic_distance_from_two_matrices(m1, m2):
batch=m1.shape[0]
m = torch.bmm(m1, m2.transpose(1,2)) #batch*3*3
cos = ( m[:,0,0] + m[:,1,1] + m[:,2,2] - 1 )/2
cos = torch.min(cos, torch.autograd.Variable(torch.ones(batch).cuda()) )
cos = torch.max(cos, torch.autograd.Variable(torch.ones(batch).cuda())*-1 )
theta = torch.acos(cos)
#theta = torch.min(theta, 2*np.pi - theta)
return theta
#matrices batch*3*3
#both matrix are orthogonal rotation matrices
#out theta between 0 to 180 degree batch
def compute_angle_from_r_matrices(m):
batch=m.shape[0]
cos = ( m[:,0,0] + m[:,1,1] + m[:,2,2] - 1 )/2
cos = torch.min(cos, torch.autograd.Variable(torch.ones(batch).cuda()) )
cos = torch.max(cos, torch.autograd.Variable(torch.ones(batch).cuda())*-1 )
theta = torch.acos(cos)
return theta
def get_sampled_rotation_matrices_by_quat(batch):
#quat = torch.autograd.Variable(torch.rand(batch,4).cuda())
quat = torch.autograd.Variable(torch.randn(batch, 4).cuda())
matrix = compute_rotation_matrix_from_quaternion(quat)
return matrix
def get_sampled_rotation_matrices_by_hpof(batch):
theta = torch.autograd.Variable(torch.FloatTensor(np.random.uniform(0,1, batch)*np.pi).cuda()) #[0, pi]
phi = torch.autograd.Variable(torch.FloatTensor(np.random.uniform(0,2,batch)*np.pi).cuda()) #[0,2pi)
tao = torch.autograd.Variable(torch.FloatTensor(np.random.uniform(0,2,batch)*np.pi).cuda()) #[0,2pi)
qw = torch.cos(theta/2)*torch.cos(tao/2)
qx = torch.cos(theta/2)*torch.sin(tao/2)
qy = torch.sin(theta/2)*torch.cos(phi+tao/2)
qz = torch.sin(theta/2)*torch.sin(phi+tao/2)
# Unit quaternion rotation matrices computatation
xx = (qx*qx).view(batch,1)
yy = (qy*qy).view(batch,1)
zz = (qz*qz).view(batch,1)
xy = (qx*qy).view(batch,1)
xz = (qx*qz).view(batch,1)
yz = (qy*qz).view(batch,1)
xw = (qx*qw).view(batch,1)
yw = (qy*qw).view(batch,1)
zw = (qz*qw).view(batch,1)
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
return matrix
#axisAngle batch*4 angle, x,y,z
def get_sampled_rotation_matrices_by_axisAngle( batch, return_quaternion=False):
theta = torch.autograd.Variable(torch.FloatTensor(np.random.uniform(-1,1, batch)*np.pi).cuda()) #[0, pi] #[-180, 180]
sin = torch.sin(theta)
axis = torch.autograd.Variable(torch.randn(batch, 3).cuda())
axis = normalize_vector(axis) #batch*3
qw = torch.cos(theta)
qx = axis[:,0]*sin
qy = axis[:,1]*sin
qz = axis[:,2]*sin
quaternion = torch.cat((qw.view(batch,1), qx.view(batch,1), qy.view(batch,1), qz.view(batch,1)), 1 )
# Unit quaternion rotation matrices computatation
xx = (qx*qx).view(batch,1)
yy = (qy*qy).view(batch,1)
zz = (qz*qz).view(batch,1)
xy = (qx*qy).view(batch,1)
xz = (qx*qz).view(batch,1)
yz = (qy*qz).view(batch,1)
xw = (qx*qw).view(batch,1)
yw = (qy*qw).view(batch,1)
zw = (qz*qw).view(batch,1)
row0 = torch.cat((1-2*yy-2*zz, 2*xy - 2*zw, 2*xz + 2*yw), 1) #batch*3
row1 = torch.cat((2*xy+ 2*zw, 1-2*xx-2*zz, 2*yz-2*xw ), 1) #batch*3
row2 = torch.cat((2*xz-2*yw, 2*yz+2*xw, 1-2*xx-2*yy), 1) #batch*3
matrix = torch.cat((row0.view(batch, 1, 3), row1.view(batch,1,3), row2.view(batch,1,3)),1) #batch*3*3
if(return_quaternion==True):
return matrix, quaternion
else:
return matrix