SMPL 笔记
原理(已有 shape、pose 参数版)
-
根据 shape、pose 参数,得到 T-pose 下的 vertices,joints。(根据参数产生相应的形变)
-
根据 pose 参数求得每个关节相对其父节点的偏移量,产生一个关于点的 global transformation
-
将 transformation 应用到 vertices 上,根据施加动作的 vertices 产生 human mesh
参考
原理、代码:
https://khanhha.github.io/posts/SMPL-model-introduction/
模型训练(其实仅仅可视化是用不着的):
https://www.cnblogs.com/sariel-sakura/p/14321818.html
代码(numpy 版)
(放最核心的一段)
def update(self):
"""
Called automatically when parameters are updated.
"""
# how beta affect body shape
v_shaped = self.shapedirs.dot(self.beta) + self.v_template
# joints location
self.J = self.J_regressor.dot(v_shaped)
pose_cube = self.pose.reshape((-1, 1, 3)) # pose_cube: (24, 1, 3)
# rotation matrix for each joint
self.R = self.rodrigues(pose_cube) # self.R: (24, 3, 3)
I_cube = np.broadcast_to(
np.expand_dims(np.eye(3), axis=0),
(self.R.shape[0]-1, 3, 3)
)
lrotmin = (self.R[1:] - I_cube).ravel() # Irotmin: (23*3*3, 1)
# how pose affect body shape in zero pose
v_posed = v_shaped + self.posedirs.dot(lrotmin) # posedir: (6890, 3, 207), v_posed: (6890, 3)
# 注意 pose 参数是每个关节点相对其父节点的旋转,这一步没有相对旋转的操作,只是让 vertices 产生与 pose 有关的形变
# world transformation of each joint
G = np.empty((self.kintree_table.shape[1], 4, 4)) # G: (24, 4, 4)
G[0] = self.with_zeros(np.hstack((self.R[0], self.J[0, :].reshape([3, 1]))))
# R[0]是joint0的旋转矩阵,J[0,:]是joint0的坐标,这里把它转成列向量。hstack水平堆叠
# with_zeros是把3x4变成齐次的4x4,底下加(0,0,0,1)
# G[0] 表示根节点的变换(包含坐标和旋转矩阵,相对于全局坐标系)
for i in range(1, self.kintree_table.shape[1]):
G[i] = G[self.parent[i]].dot(
self.with_zeros(
np.hstack(
[self.R[i],((self.J[i, :]-self.J[self.parent[i],:]).reshape([3,1]))]
)
)
)
# G[i]=G[[parent[i]]]乘上joint_i的相对parent[i]的变换
# 减掉最开始的 T-pose 下 joint 位置的影响
G = G - self.pack(
np.matmul( # matmul 有广播机制,使得可以matmul
G,
np.hstack([self.J, np.zeros([24, 1])]).reshape([24, 4, 1])
)
)
# transformation of each vertex
T = np.tensordot(self.weights, G, axes=[[1], [0]]) # T: (6890,4,4)
# weights: the transformation weights for each joint (6890, 24)
rest_shape_h = np.hstack((v_posed, np.ones([v_posed.shape[0], 1]))) # (6890, 4)
v = np.matmul(T, rest_shape_h.reshape([-1, 4, 1])).reshape([-1, 4])[:, :3] # 形变后的顶点位置
self.verts = v + self.trans.reshape([1, 3]) # trans 平移向量
使用体验
首先要下载 SMPL 模型到本地/服务器。
通过在 /data/liumengyin/forder1/SMPL
文件夹下运行 smpl_np.py
或者 smpl_torch.py
(同时在主函数修改 shape 和 pose 参数),可以获得一个 .obj 格式的 SMPL 人体模型。
目前尚不清楚视频怎么处理。