Spaces:
Configuration error
Configuration error
""" | |
Prepare blend weights of grid points | |
""" | |
import os | |
import json | |
import numpy as np | |
import cv2 | |
import sys | |
sys.path.append('/mnt/data/home/pengsida/Codes/SMPL_CPP/build/python') | |
import pysmplceres | |
import open3d as o3d | |
import pyskeleton | |
from psbody.mesh import Mesh | |
import pickle | |
# initialize a smpl model | |
pysmplceres.loadSMPL('/mnt/data/home/pengsida/Codes/SMPL_CPP/model/smpl/', | |
'smpl') | |
def read_pickle(pkl_path): | |
with open(pkl_path, 'rb') as f: | |
u = pickle._Unpickler(f) | |
u.encoding = 'latin1' | |
return u.load() | |
def get_o3d_mesh(vertices, faces): | |
mesh = o3d.geometry.TriangleMesh() | |
mesh.vertices = o3d.utility.Vector3dVector(vertices) | |
mesh.triangles = o3d.utility.Vector3iVector(faces) | |
mesh.compute_vertex_normals() | |
return mesh | |
def barycentric_interpolation(val, coords): | |
""" | |
:param val: verts x 3 x d input matrix | |
:param coords: verts x 3 barycentric weights array | |
:return: verts x d weighted matrix | |
""" | |
t = val * coords[..., np.newaxis] | |
ret = t.sum(axis=1) | |
return ret | |
def process_shapedirs(shapedirs, vert_ids, bary_coords): | |
arr = [] | |
for i in range(3): | |
t = barycentric_interpolation(shapedirs[:, i, :][vert_ids], | |
bary_coords) | |
arr.append(t[:, np.newaxis, :]) | |
arr = np.concatenate(arr, axis=1) | |
return arr | |
def batch_rodrigues(poses): | |
""" poses: N x 3 | |
""" | |
batch_size = poses.shape[0] | |
angle = np.linalg.norm(poses + 1e-8, axis=1, keepdims=True) | |
rot_dir = poses / angle | |
cos = np.cos(angle)[:, None] | |
sin = np.sin(angle)[:, None] | |
rx, ry, rz = np.split(rot_dir, 3, axis=1) | |
zeros = np.zeros([batch_size, 1]) | |
K = np.concatenate([zeros, -rz, ry, rz, zeros, -rx, -ry, rx, zeros], | |
axis=1) | |
K = K.reshape([batch_size, 3, 3]) | |
ident = np.eye(3)[None] | |
rot_mat = ident + sin * K + (1 - cos) * np.matmul(K, K) | |
return rot_mat | |
def get_rigid_transformation(rot_mats, joints, parents): | |
""" | |
rot_mats: 24 x 3 x 3 | |
joints: 24 x 3 | |
parents: 24 | |
""" | |
# obtain the relative joints | |
rel_joints = joints.copy() | |
rel_joints[1:] -= joints[parents[1:]] | |
# create the transformation matrix | |
transforms_mat = np.concatenate([rot_mats, rel_joints[..., None]], axis=2) | |
padding = np.zeros([24, 1, 4]) | |
padding[..., 3] = 1 | |
transforms_mat = np.concatenate([transforms_mat, padding], axis=1) | |
# rotate each part | |
transform_chain = [transforms_mat[0]] | |
for i in range(1, parents.shape[0]): | |
curr_res = np.dot(transform_chain[parents[i]], transforms_mat[i]) | |
transform_chain.append(curr_res) | |
transforms = np.stack(transform_chain, axis=0) | |
# obtain the rigid transformation | |
padding = np.zeros([24, 1]) | |
joints_homogen = np.concatenate([joints, padding], axis=1) | |
transformed_joints = np.sum(transforms * joints_homogen[:, None], axis=2) | |
transforms[..., 3] = transforms[..., 3] - transformed_joints | |
return transforms | |
def get_transform_params(smpl, params): | |
""" obtain the transformation parameters for linear blend skinning | |
""" | |
v_template = np.array(smpl['v_template']) | |
# add shape blend shapes | |
shapedirs = np.array(smpl['shapedirs']) | |
betas = params['shapes'] | |
v_shaped = v_template + np.sum(shapedirs * betas[None], axis=2) | |
# add pose blend shapes | |
poses = params['poses'].reshape(-1, 3) | |
# 24 x 3 x 3 | |
rot_mats = batch_rodrigues(poses) | |
# 23 x 3 x 3 | |
pose_feature = rot_mats[1:].reshape(23, 3, 3) - np.eye(3)[None] | |
pose_feature = pose_feature.reshape(1, 1, 207) | |
posedirs = np.array(smpl['posedirs']) | |
# v_posed = v_shaped + np.sum(posedirs * pose_feature, axis=2) | |
v_posed = v_shaped | |
# obtain the joints | |
joints = smpl['J_regressor'].dot(v_shaped) | |
# obtain the rigid transformation | |
parents = smpl['kintree_table'][0] | |
A = get_rigid_transformation(rot_mats, joints, parents) | |
# apply global transformation | |
R = cv2.Rodrigues(params['Rh'][0])[0] | |
Th = params['Th'] | |
return A, R, Th | |
def get_colored_pc(pts, rgb): | |
pc = o3d.geometry.PointCloud() | |
pc.points = o3d.utility.Vector3dVector(pts) | |
colors = np.zeros_like(pts) | |
colors += rgb | |
pc.colors = o3d.utility.Vector3dVector(colors) | |
return pc | |
def get_grid_points(xyz): | |
min_xyz = np.min(xyz, axis=0) | |
max_xyz = np.max(xyz, axis=0) | |
min_xyz -= 0.05 | |
max_xyz += 0.05 | |
bounds = np.stack([min_xyz, max_xyz], axis=0) | |
vsize = 0.025 | |
voxel_size = [vsize, vsize, vsize] | |
x = np.arange(bounds[0, 0], bounds[1, 0] + voxel_size[0], voxel_size[0]) | |
y = np.arange(bounds[0, 1], bounds[1, 1] + voxel_size[1], voxel_size[1]) | |
z = np.arange(bounds[0, 2], bounds[1, 2] + voxel_size[2], voxel_size[2]) | |
pts = np.stack(np.meshgrid(x, y, z, indexing='ij'), axis=-1) | |
return pts | |
def get_canpts(param_path): | |
params = np.load(param_path, allow_pickle=True).item() | |
vertices = pysmplceres.getVertices(params)[0] | |
faces = pysmplceres.getFaces() | |
mesh = get_o3d_mesh(vertices, faces) | |
smpl = read_pickle( | |
'/mnt/data/home/pengsida/Codes/EasyMocap/data/smplx/smpl/SMPL_NEUTRAL.pkl' | |
) | |
# obtain the transformation parameters for linear blend skinning | |
A, R, Th = get_transform_params(smpl, params) | |
# transform points from the world space to the pose space | |
pxyz = np.dot(vertices - Th, R) | |
smpl_mesh = Mesh(pxyz, faces) | |
# create grid points in the pose space | |
pts = get_grid_points(pxyz) | |
sh = pts.shape | |
pts = pts.reshape(-1, 3) | |
# obtain the blending weights for grid points | |
closest_face, closest_points = smpl_mesh.closest_faces_and_points(pts) | |
vert_ids, bary_coords = smpl_mesh.barycentric_coordinates_for_points( | |
closest_points, closest_face.astype('int32')) | |
bweights = barycentric_interpolation(smpl['weights'][vert_ids], | |
bary_coords) | |
A = np.dot(bweights, A.reshape(24, -1)).reshape(-1, 4, 4) | |
can_pts = pts - A[:, :3, 3] | |
R_inv = np.linalg.inv(A[:, :3, :3]) | |
can_pts = np.sum(R_inv * can_pts[:, None], axis=2) | |
can_pts = can_pts.reshape(*sh).astype(np.float32) | |
return can_pts | |
def prepare_tpose(): | |
data_root = '/home/pengsida/Datasets/light_stage' | |
human = 'CoreView_315' | |
param_dir = os.path.join(data_root, human, 'params') | |
canpts_dir = os.path.join(data_root, human, 'canpts') | |
os.system('mkdir -p {}'.format(canpts_dir)) | |
for i in range(len(os.listdir(param_dir))): | |
i = i + 1 | |
param_path = os.path.join(param_dir, '{}.npy'.format(i)) | |
canpts = get_canpts(param_path) | |
canpts_path = os.path.join(canpts_dir, '{}.npy'.format(i)) | |
np.save(canpts_path, canpts) | |
prepare_tpose() | |