-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.py
159 lines (135 loc) · 5.38 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import torch
import torch.nn.functional as F
import numpy as np
def batch_rodrigues(theta):
"""Convert axis-angle representation to rotation matrix.
Args:
theta: size = [B, 3]
Returns:
Rotation matrix corresponding to the quaternion -- size = [B, 3, 3]
"""
l1norm = torch.norm(theta + 1e-8, p = 2, dim = 1)
angle = torch.unsqueeze(l1norm, -1)
normalized = torch.div(theta, angle)
angle = angle * 0.5
v_cos = torch.cos(angle)
v_sin = torch.sin(angle)
quat = torch.cat([v_cos, v_sin * normalized], dim = 1)
return quat_to_rotmat(quat)
def batch_global_rigid_transformation(Rs, Js, parent):
"""
Computes 3D joint locations given pose. J_child = A_parent * A_child[:, :, :3, 3]
Args:
Rs: N x 24 x 3 x 3, rotation matrix of K joints
Js: N x 24 x 3, joint locations before posing
parent: 24, holding the parent id for each joint
Returns
J_transformed : N x 24 x 3 location of absolute joints
A_relative: N x 24 4 x 4 relative transformation matrix for LBS.
"""
def make_A(R, t, N):
"""
construct transformation matrix for a joint
Args:
R: N x 3 x 3, rotation matrix
t: N x 3 x 1, bone vector (child-parent)
Returns:
A: N x 4 x 4, transformation matrix
"""
# N x 4 x 3
R_homo = F.pad(R, (0,0,0,1))
# N x 4 x 1
t_homo = torch.cat([t, torch.ones([N, 1, 1]).type(torch.float32).to(R.device)], 1)
# N x 4 x 4
return torch.cat([R_homo, t_homo], 2)
# obtain the batch size
N = Rs.size()[0]
# unsqueeze Js to N x 24 x 3 x 1
Js = Js.unsqueeze(-1)
# rot_x = torch.tensor([[1, 0, 0], [0, -1, 0], [0, 0, -1]]).type(torch.float64).to(Rs.device)
# rot_x = rot_x.repeat([N, 1]).view([N, 3, 3])
# root_rotation = torch.matmul(Rs[:, 0, :, :], rot_x)
root_rotation = Rs[:, 0, :, :]
# transformation matrix of the root
A0 = make_A(root_rotation, Js[:, 0], N)
A = [A0]
# caculate transformed matrix of each joint
for i in range(1, parent.shape[0]):
# transformation matrix
t_here = Js[:,i] - Js[:,parent[i]]
A_here = make_A(Rs[:,i], t_here, N)
# transformation given parent matrix
A_here_tran = torch.matmul(A[parent[i]], A_here)
A.append(A_here_tran)
# N x 24 x 4 x 4, transformation matrix for each joint
A = torch.stack(A, dim=1)
# recover transformed joints from the transformed transformation matrix
J_transformed = A[:, :, :3, 3]
# --- Compute relative A: Skinning is based on
# how much the bone moved (not the final location of the bone)
# but (final_bone - init_bone)
# ---
# N x 24 x 3 x 1 to N x 24 x 4 x 1, homo with zeros
Js_homo = torch.cat([Js, torch.zeros([N, 24, 1, 1]).type(torch.float32).to(Rs.device)], 2)
# N x 24 x 4 x 1
init_bone = torch.matmul(A, Js_homo)
# N x 24 x 4 x 4, For each 4 x 4, last column is the joints position, and otherwise 0.
init_bone = F.pad(init_bone, (3,0))
A_relative = A - init_bone
return J_transformed, A_relative
def perspective_projection(points, rotation, translation,
focal_length, camera_center):
"""
This function computes the perspective projection of a set of points.
Input:
points (bs, N, 3): 3D points
rotation (bs, 3, 3): Camera rotation
translation (bs, 3): Camera translation
focal_length (bs,) or scalar: Focal length
camera_center (bs, 2): Camera center
"""
batch_size = points.shape[0]
K = torch.zeros([batch_size, 3, 3], device=points.device)
K[:,0,0] = focal_length
K[:,1,1] = focal_length
K[:,2,2] = 1.
K[:,:-1, -1] = camera_center
# Transform points
points = torch.einsum('bij,bkj->bki', rotation, points)
points = points + translation.unsqueeze(1)
# Apply perspective distortion
projected_points = points / points[:,:,-1].unsqueeze(-1)
# Apply camera intrinsics
projected_points = torch.einsum('bij,bkj->bki', K, projected_points)
return projected_points[:, :, :-1]
def crop2expandsquare_zeros(img, bbox):
C = img.shape[2]
x1,y1,x2,y2 = bbox[0],bbox[1],bbox[2],bbox[3]
center = [(x1+x2)/2, (y1+y2)/2]
Len_max = np.amax([y2-y1, x2-x1])
x1_new_square = int((Len_max - x2 + x1)/2)
y1_new_square = int((Len_max - y2 + y1)/2)
x2_new_square = int((Len_max + x2 - x1)/2)
y2_new_square = int((Len_max + y2 - y1)/2)
# square image
img_cropped_square = np.ones([Len_max,Len_max,C], dtype = np.uint8) * 255
img_cropped_square[y1_new_square:y2_new_square,x1_new_square:x2_new_square,:] = img[y1:y2,x1:x2]
return img_cropped_square, center, Len_max
def rot6d_to_rotmat(x):
"""Convert 6D rotation representation to 3x3 rotation matrix.
Based on Zhou et al., "On the Continuity of Rotation Representations in Neural Networks", CVPR 2019
Input:
(B,6) Batch of 6-D rotation representations
Output:
(B,3,3) Batch of corresponding rotation matrices
"""
x = x.view(-1,3,2)
a1 = x[:, :, 0]
a2 = x[:, :, 1]
b1 = F.normalize(a1)
b2 = F.normalize(a2 - torch.einsum('bi,bi->b', b1, a2).unsqueeze(-1) * b1)
b3 = torch.cross(b1, b2)
return torch.stack((b1, b2, b3), dim=-1)