smpl.py
Go to the documentation of this file.
1 from __future__ import absolute_import
2 from __future__ import division
3 from __future__ import print_function
4 
5 import itertools, pkg_resources, sys
6 from distutils.version import LooseVersion
7 if LooseVersion(pkg_resources.get_distribution("chainer").version) >= LooseVersion('7.0.0') and \
8  sys.version_info.major == 2:
9  print('''Please install chainer < 7.0.0:
10 
11  sudo pip install chainer==6.7.0
12 
13 c.f https://github.com/jsk-ros-pkg/jsk_recognition/pull/2485
14 ''', file=sys.stderr)
15  sys.exit(1)
16 if [p for p in list(itertools.chain(*[pkg_resources.find_distributions(_) for _ in sys.path])) if "cupy-" in p.project_name ] == []:
17  print('''Please install CuPy
18 
19  sudo pip install cupy-cuda[your cuda version]
20 i.e.
21  sudo pip install cupy-cuda91
22 
23 ''', file=sys.stderr)
24  # sys.exit(1)
25 from chainer import Parameter
26 from chainer import Variable
27 import chainer
28 import chainer.functions as F
29 import numpy as np
30 
31 
32 def batch_global_rigid_transformation(Rs, Js, parent, rotate_base=False):
33  """
34  Computes absolute joint locations given pose.
35 
36  rotate_base: if True, rotates the global rotation by 90 deg in x axis.
37  if False, this is the original SMPL coordinate.
38 
39  Args:
40  Rs: N x 24 x 3 x 3 rotation vector of K joints
41  Js: N x 24 x 3, joint locations before posing
42  parent: 24 holding the parent id for each index
43 
44  Returns
45  new_J : `Tensor`: N x 24 x 3 location of absolute joints
46  A : `Tensor`: N x 24 4 x 4 relative joint transformations for LBS.
47  """
48  xp = Rs.xp
49  N = Rs.shape[0]
50  if rotate_base:
51  print('Flipping the SMPL coordinate frame!!!!')
52  rot_x = Variable(
53  [[1, 0, 0], [0, -1, 0], [0, 0, -1]], dtype=Rs.dtype)
54  rot_x = F.reshape(F.tile(rot_x, [N, 1]), [N, 3, 3])
55  root_rotation = F.matmul(Rs[:, 0, :, :], rot_x)
56  else:
57  root_rotation = Rs[:, 0, :, :]
58 
59  # Now Js is N x 24 x 3 x 1
60  Js = F.expand_dims(Js, -1)
61 
62  def make_A(R, t, name=None):
63  # Rs is N x 3 x 3, ts is N x 3 x 1
64  R_homo = F.pad(R, [[0, 0], [0, 1], [0, 0]], 'constant')
65  t_homo = F.concat([t, xp.ones([N, 1, 1], 'f')], 1)
66  return F.concat([R_homo, t_homo], 2)
67 
68  A0 = make_A(root_rotation, Js[:, 0])
69  results = [A0]
70  for i in range(1, parent.shape[0]):
71  j_here = Js[:, i] - Js[:, parent[i]]
72  A_here = make_A(Rs[:, i], j_here)
73  res_here = F.matmul(
74  results[parent[i]], A_here)
75  results.append(res_here)
76 
77  # 10 x 24 x 4 x 4
78  results = F.stack(results, axis=1)
79 
80  new_J = results[:, :, :3, 3]
81 
82  # --- Compute relative A: Skinning is based on
83  # how much the bone moved (not the final location of the bone)
84  # but (final_bone - init_bone)
85  # ---
86  Js_w0 = F.concat([Js, xp.zeros([N, 24, 1, 1], 'f')], 2)
87  init_bone = F.matmul(results, Js_w0)
88  # Append empty 4 x 3:
89  init_bone = F.pad(init_bone, [[0, 0], [0, 0], [0, 0], [3, 0]], 'constant')
90  A = results - init_bone
91 
92  return new_J, results
93 
94 
95 def batch_skew(vec, batch_size=None):
96  """
97  vec is N x 3, batch_size is int
98 
99  returns N x 3 x 3. Skew_sym version of each matrix.
100  """
101  xp = vec.xp
102  if batch_size is None:
103  batch_size = vec.shape[0]
104  col_inds = xp.array([1, 2, 3, 5, 6, 7])
105  indices = F.reshape(
106  F.repeat(col_inds.reshape(1, -1), batch_size, axis=0) +
107  F.repeat(F.reshape(xp.arange(0, batch_size) * 9, [-1, 1]), 6, axis=1),
108  [-1, 1])
109  updates = F.reshape(
110  F.stack(
111  [-vec[:, 2], vec[:, 1], vec[:, 2], -vec[:, 0], -vec[:, 1],
112  vec[:, 0]], axis=1), [-1])
113  res = Variable(xp.zeros((batch_size * 3 * 3), 'f'))
114  res.data[indices.reshape(-1).data] = updates.data
115  res = F.reshape(res, [batch_size, 3, 3])
116  return res
117 
118 
119 def batch_rodrigues(theta):
120  """
121  Theta is N x 3
122  """
123  batch_size = theta.shape[0]
124  xp = theta.xp
125 
126  angle = F.expand_dims(F.sqrt(F.batch_l2_norm_squared(theta + 1e-8)), -1)
127  r = F.expand_dims(theta / F.tile(angle, 3), -1)
128 
129  angle = F.expand_dims(angle, -1)
130  cos = F.cos(angle)
131  sin = F.sin(angle)
132  cos = F.tile(cos, (3, 3))
133  sin = F.tile(sin, (3, 3))
134 
135  outer = F.matmul(r, r, transb=True)
136 
137  eyes = F.tile(F.expand_dims(
138  Variable(xp.array(xp.eye(3), 'f')), 0), (batch_size, 1, 1))
139  R = cos * eyes + (1 - cos) * outer + sin * batch_skew(r, batch_size)
140  return R
141 
142 
143 class SMPL(chainer.Chain):
144 
145  def __init__(self):
146  super(SMPL, self).__init__()
147  self.parents = np.array([
148  4294967295, 0, 0, 0, 1,
149  2, 3, 4, 5, 6, 7, 8, 9, 9, 9,
150  12, 13, 14, 16, 17, 18, 19, 20, 21], 'i')
151 
152  with self.init_scope():
153  self.v_template = Parameter(0, (6890, 3))
154  self.size = [self.v_template.shape[0], 3]
155  self.shapedirs = Parameter(0, (10, 20670))
156  self.J_regressor = Parameter(0, (6890, 24))
157  self.posedirs = Parameter(0, (207, 20670))
158  self.weights = Parameter(0, (6890, 24))
159  self.joint_regressor = Parameter(0, (6890, 19))
160 
161  def __call__(self, beta, theta, get_skin=False, with_a=False):
162  batch_size = beta.shape[0]
163 
164  # 1. Add shape blend shapes
165  # (N x 10) x (10 x 6890*3) = N x 6890 x 3
166  self.beta_shapedirs = F.matmul(beta, self.shapedirs)
167  v_shaped = F.reshape(
168  F.matmul(beta, self.shapedirs),
169  [-1, self.size[0], self.size[1]]) + \
170  F.repeat(self.v_template[None, ], batch_size, axis=0)
171  self.v_shaped = v_shaped
172 
173  # 2. Infer shape-dependent joint locations.
174  Jx = F.matmul(v_shaped[:, :, 0], self.J_regressor)
175  Jy = F.matmul(v_shaped[:, :, 1], self.J_regressor)
176  Jz = F.matmul(v_shaped[:, :, 2], self.J_regressor)
177  J = F.stack([Jx, Jy, Jz], axis=2)
178 
179  self.J = J
180 
181  # 3. Add pose blend shapes
182  # N x 24 x 3 x 3
183  Rs = F.reshape(
184  batch_rodrigues(F.reshape(theta, [-1, 3])), [-1, 24, 3, 3])
185  self.Rs = Rs
186  # Ignore global rotation.
187  pose_feature = F.reshape(Rs[:, 1:, :, :] -
188  F.repeat(F.repeat(Variable(self.xp.array(self.xp.eye(3), 'f'))[
189  None, ], 23, axis=0)[None, ], batch_size, axis=0),
190  [-1, 207])
191  self.pose_feature = pose_feature
192 
193  # (N x 207) x (207, 20670) -> N x 6890 x 3
194  v_posed = F.reshape(
195  F.matmul(pose_feature, self.posedirs),
196  [-1, self.size[0], self.size[1]]) + v_shaped
197 
198  # 4. Get the global joint location
199  self.J_transformed, A = batch_global_rigid_transformation(
200  Rs, J, self.parents)
201 
202  # 5. Do skinning:
203  # W is N x 6890 x 24
204  W = F.reshape(
205  F.tile(self.weights, (batch_size, 1)), [batch_size, -1, 24])
206  # (N x 6890 x 24) x (N x 24 x 16)
207  T = F.reshape(
208  F.matmul(W, F.reshape(A, [batch_size, 24, 16])),
209  [batch_size, -1, 4, 4])
210  v_posed_homo = F.concat(
211  [v_posed, self.xp.ones([batch_size, v_posed.shape[1], 1], 'f')], 2)
212  v_homo = F.matmul(T, F.expand_dims(v_posed_homo, -1))
213 
214  verts = v_homo[:, :, :3, 0]
215 
216  # Get cocoplus or lsp joints:
217  joint_x = F.matmul(verts[:, :, 0], self.joint_regressor)
218  joint_y = F.matmul(verts[:, :, 1], self.joint_regressor)
219  joint_z = F.matmul(verts[:, :, 2], self.joint_regressor)
220  joints = F.stack([joint_x, joint_y, joint_z], axis=2)
221 
222  return verts, joints, Rs, A
def __call__(self, beta, theta, get_skin=False, with_a=False)
Definition: smpl.py:161
def batch_global_rigid_transformation(Rs, Js, parent, rotate_base=False)
Definition: smpl.py:32
def batch_rodrigues(theta)
Definition: smpl.py:119
def batch_skew(vec, batch_size=None)
Definition: smpl.py:95


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Mon May 3 2021 03:03:27