-
Notifications
You must be signed in to change notification settings - Fork 11
/
batch_lbs.py
144 lines (114 loc) · 4.59 KB
/
batch_lbs.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
""" Util functions for SMPL
@@batch_skew
@@batch_rodrigues
@@batch_lrotmin
@@batch_global_rigid_transformation
"""
import tensorflow as tf
def batch_skew(vec, batch_size=None):
"""
vec is N x 3, batch_size is int
returns N x 3 x 3. Skew_sym version of each matrix.
"""
with tf.variable_scope("batch_skew", [vec]):
if batch_size is None:
batch_size = vec.shape.as_list()[0]
col_inds = tf.constant([1, 2, 3, 5, 6, 7])
indices = tf.reshape(
tf.reshape(tf.range(0, batch_size) * 9, [-1, 1]) + col_inds,
[-1, 1])
updates = tf.reshape(
tf.stack(
[
-vec[:, 2], vec[:, 1], vec[:, 2], -vec[:, 0], -vec[:, 1],
vec[:, 0]
],
axis=1), [-1])
out_shape = [batch_size * 9]
res = tf.scatter_nd(indices, updates, out_shape)
res = tf.reshape(res, [batch_size, 3, 3])
return res
def batch_rodrigues(theta, name=None):
"""
Theta is N x 3
"""
with tf.variable_scope(name, "batch_rodrigues", [theta]):
batch_size = tf.shape(theta)[0]
angle = tf.expand_dims(tf.norm(theta + 1e-8, axis=1), -1)
r = tf.expand_dims(tf.div(theta, angle), -1)
angle = tf.expand_dims(angle, -1)
cos = tf.cos(angle)
sin = tf.sin(angle)
outer = tf.matmul(r, r, transpose_b=True, name="outer")
eyes = tf.tile(tf.expand_dims(tf.eye(3), 0), [batch_size, 1, 1])
R = cos * eyes + (1 - cos) * outer + sin * batch_skew(
r, batch_size=batch_size)
return R
def batch_lrotmin(theta, name=None):
""" NOTE: not used bc I want to reuse R and this is simple.
Output of this is used to compute joint-to-pose blend shape mapping.
Equation 9 in SMPL paper.
Args:
pose: `Tensor`, N x 72 vector holding the axis-angle rep of K joints.
This includes the global rotation so K=24
Returns
diff_vec : `Tensor`: N x 207 rotation matrix of 23=(K-1) joints with identity subtracted.,
"""
with tf.variable_scope(name, "batch_lrotmin", [theta]):
with tf.variable_scope("ignore_global"):
theta = theta[:, 3:]
# N*23 x 3 x 3
Rs = batch_rodrigues(tf.reshape(theta, [-1, 3]))
lrotmin = tf.reshape(Rs - tf.eye(3), [-1, 207])
return lrotmin
def batch_global_rigid_transformation(Rs, Js, parent, rotate_base=False):
"""
Computes absolute joint locations given pose.
rotate_base: if True, rotates the global rotation by 90 deg in x axis.
if False, this is the original SMPL coordinate.
Args:
Rs: N x 24 x 3 x 3 rotation vector of K joints
Js: N x 24 x 3, joint locations before posing
parent: 24 holding the parent id for each index
Returns
new_J : `Tensor`: N x 24 x 3 location of absolute joints
A : `Tensor`: N x 24 4 x 4 relative joint transformations for LBS.
"""
with tf.variable_scope("batch_forward_kinematics", [Rs, Js]):
N = tf.shape(Rs)[0]
if rotate_base:
rot_x = tf.constant(
[[1, 0, 0], [0, -1, 0], [0, 0, -1]], dtype=Rs.dtype)
rot_x = tf.reshape(tf.tile(rot_x, [N, 1]), [N, 3, 3])
root_rotation = tf.matmul(Rs[:, 0, :, :], rot_x)
else:
root_rotation = Rs[:, 0, :, :]
# Now Js is N x 24 x 3 x 1
Js = tf.expand_dims(Js, -1)
def make_A(R, t, name=None):
# Rs is N x 3 x 3, ts is N x 3 x 1
with tf.variable_scope(name, "Make_A", [R, t]):
R_homo = tf.pad(R, [[0, 0], [0, 1], [0, 0]])
t_homo = tf.concat([t, tf.ones([N, 1, 1])], 1)
return tf.concat([R_homo, t_homo], 2)
A0 = make_A(root_rotation, Js[:, 0])
results = [A0]
for i in range(1, parent.shape[0]):
j_here = Js[:, i] - Js[:, parent[i]]
A_here = make_A(Rs[:, i], j_here)
res_here = tf.matmul(
results[parent[i]], A_here, name="propA%d" % i)
results.append(res_here)
# 10 x 24 x 4 x 4
results = tf.stack(results, axis=1)
new_J = results[:, :, :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)
# ---
Js_w0 = tf.concat([Js, tf.zeros([N, 24, 1, 1])], 2)
init_bone = tf.matmul(results, Js_w0)
# Append empty 4 x 3:
init_bone = tf.pad(init_bone, [[0, 0], [0, 0], [0, 0], [3, 0]])
A = results - init_bone
return new_J, A