| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| from lib.dataset.mesh_util import SMPLX |
| from lib.common.render_utils import face_vertices |
| import numpy as np |
| import lib.smplx as smplx |
| import trimesh |
| import torch |
| import torch.nn.functional as F |
|
|
| model_init_params = dict(gender='male', |
| model_type='smplx', |
| model_path=SMPLX().model_dir, |
| create_global_orient=False, |
| create_body_pose=False, |
| create_betas=False, |
| create_left_hand_pose=False, |
| create_right_hand_pose=False, |
| create_expression=False, |
| create_jaw_pose=False, |
| create_leye_pose=False, |
| create_reye_pose=False, |
| create_transl=False, |
| num_pca_comps=12) |
|
|
|
|
| def get_smpl_model(model_type, gender): |
| return smplx.create(**model_init_params) |
|
|
|
|
| def normalization(data): |
| _range = np.max(data) - np.min(data) |
| return ((data - np.min(data)) / _range) |
|
|
|
|
| def sigmoid(x): |
| z = 1 / (1 + np.exp(-x)) |
| return z |
|
|
|
|
| def load_fit_body(fitted_path, |
| scale, |
| smpl_type='smplx', |
| smpl_gender='neutral', |
| noise_dict=None): |
|
|
| param = np.load(fitted_path, allow_pickle=True) |
| for key in param.keys(): |
| param[key] = torch.as_tensor(param[key]) |
|
|
| smpl_model = get_smpl_model(smpl_type, smpl_gender) |
| model_forward_params = dict(betas=param['betas'], |
| global_orient=param['global_orient'], |
| body_pose=param['body_pose'], |
| left_hand_pose=param['left_hand_pose'], |
| right_hand_pose=param['right_hand_pose'], |
| jaw_pose=param['jaw_pose'], |
| leye_pose=param['leye_pose'], |
| reye_pose=param['reye_pose'], |
| expression=param['expression'], |
| return_verts=True) |
|
|
| if noise_dict is not None: |
| model_forward_params.update(noise_dict) |
|
|
| smpl_out = smpl_model(**model_forward_params) |
|
|
| smpl_verts = ( |
| (smpl_out.vertices[0] * param['scale'] + param['translation']) * |
| scale).detach() |
| smpl_joints = ( |
| (smpl_out.joints[0] * param['scale'] + param['translation']) * |
| scale).detach() |
| smpl_mesh = trimesh.Trimesh(smpl_verts, |
| smpl_model.faces, |
| process=False, |
| maintain_order=True) |
|
|
| return smpl_mesh, smpl_joints |
|
|
|
|
| def load_ori_fit_body(fitted_path, smpl_type='smplx', smpl_gender='neutral'): |
|
|
| param = np.load(fitted_path, allow_pickle=True) |
| for key in param.keys(): |
| param[key] = torch.as_tensor(param[key]) |
|
|
| smpl_model = get_smpl_model(smpl_type, smpl_gender) |
| model_forward_params = dict(betas=param['betas'], |
| global_orient=param['global_orient'], |
| body_pose=param['body_pose'], |
| left_hand_pose=param['left_hand_pose'], |
| right_hand_pose=param['right_hand_pose'], |
| jaw_pose=param['jaw_pose'], |
| leye_pose=param['leye_pose'], |
| reye_pose=param['reye_pose'], |
| expression=param['expression'], |
| return_verts=True) |
|
|
| smpl_out = smpl_model(**model_forward_params) |
|
|
| smpl_verts = smpl_out.vertices[0].detach() |
| smpl_mesh = trimesh.Trimesh(smpl_verts, |
| smpl_model.faces, |
| process=False, |
| maintain_order=True) |
|
|
| return smpl_mesh |
|
|
|
|
| def save_obj_mesh(mesh_path, verts, faces): |
| file = open(mesh_path, 'w') |
| for v in verts: |
| file.write('v %.4f %.4f %.4f\n' % (v[0], v[1], v[2])) |
| for f in faces: |
| f_plus = f + 1 |
| file.write('f %d %d %d\n' % (f_plus[0], f_plus[1], f_plus[2])) |
| file.close() |
|
|
|
|
| |
| def read_mtlfile(fname): |
| materials = {} |
| with open(fname) as f: |
| lines = f.read().splitlines() |
|
|
| for line in lines: |
| if line: |
| split_line = line.strip().split(' ', 1) |
| if len(split_line) < 2: |
| continue |
|
|
| prefix, data = split_line[0], split_line[1] |
| if 'newmtl' in prefix: |
| material = {} |
| materials[data] = material |
| elif materials: |
| if data: |
| split_data = data.strip().split(' ') |
|
|
| |
| |
| if 'map' in prefix: |
| material[prefix] = split_data[-1].split('\\')[-1] |
| elif len(split_data) > 1: |
| material[prefix] = tuple(float(d) for d in split_data) |
| else: |
| try: |
| material[prefix] = int(data) |
| except ValueError: |
| material[prefix] = float(data) |
|
|
| return materials |
|
|
|
|
| def load_obj_mesh_mtl(mesh_file): |
| vertex_data = [] |
| norm_data = [] |
| uv_data = [] |
|
|
| face_data = [] |
| face_norm_data = [] |
| face_uv_data = [] |
|
|
| |
| face_data_mat = {} |
| face_norm_data_mat = {} |
| face_uv_data_mat = {} |
|
|
| |
| mtl_data = None |
| cur_mat = None |
|
|
| if isinstance(mesh_file, str): |
| f = open(mesh_file, "r") |
| else: |
| f = mesh_file |
| for line in f: |
| if isinstance(line, bytes): |
| line = line.decode("utf-8") |
| if line.startswith('#'): |
| continue |
| values = line.split() |
| if not values: |
| continue |
|
|
| if values[0] == 'v': |
| v = list(map(float, values[1:4])) |
| vertex_data.append(v) |
| elif values[0] == 'vn': |
| vn = list(map(float, values[1:4])) |
| norm_data.append(vn) |
| elif values[0] == 'vt': |
| vt = list(map(float, values[1:3])) |
| uv_data.append(vt) |
| elif values[0] == 'mtllib': |
| mtl_data = read_mtlfile( |
| mesh_file.replace(mesh_file.split('/')[-1], values[1])) |
| elif values[0] == 'usemtl': |
| cur_mat = values[1] |
| elif values[0] == 'f': |
| |
| l_face_data = [] |
| l_face_uv_data = [] |
| l_face_norm_data = [] |
|
|
| |
| if len(values) > 4: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[0]) if int(x.split('/')[0]) |
| < 0 else int(x.split('/')[0]) - 1, values[1:4])) |
| l_face_data.append(f) |
| f = list( |
| map( |
| lambda x: int(x.split('/')[0]) |
| if int(x.split('/')[0]) < 0 else int(x.split('/')[0]) - |
| 1, [values[3], values[4], values[1]])) |
| l_face_data.append(f) |
| |
| else: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[0]) if int(x.split('/')[0]) |
| < 0 else int(x.split('/')[0]) - 1, values[1:4])) |
| l_face_data.append(f) |
| |
| if len(values[1].split('/')) >= 2: |
| |
| if len(values) > 4: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[1]) |
| if int(x.split('/')[1]) < 0 else int( |
| x.split('/')[1]) - 1, values[1:4])) |
| l_face_uv_data.append(f) |
| f = list( |
| map( |
| lambda x: int(x.split('/')[1]) |
| if int(x.split('/')[1]) < 0 else int( |
| x.split('/')[1]) - 1, |
| [values[3], values[4], values[1]])) |
| l_face_uv_data.append(f) |
| |
| elif len(values[1].split('/')[1]) != 0: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[1]) |
| if int(x.split('/')[1]) < 0 else int( |
| x.split('/')[1]) - 1, values[1:4])) |
| l_face_uv_data.append(f) |
| |
| if len(values[1].split('/')) == 3: |
| |
| if len(values) > 4: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[2]) |
| if int(x.split('/')[2]) < 0 else int( |
| x.split('/')[2]) - 1, values[1:4])) |
| l_face_norm_data.append(f) |
| f = list( |
| map( |
| lambda x: int(x.split('/')[2]) |
| if int(x.split('/')[2]) < 0 else int( |
| x.split('/')[2]) - 1, |
| [values[3], values[4], values[1]])) |
| l_face_norm_data.append(f) |
| |
| elif len(values[1].split('/')[2]) != 0: |
| f = list( |
| map( |
| lambda x: int(x.split('/')[2]) |
| if int(x.split('/')[2]) < 0 else int( |
| x.split('/')[2]) - 1, values[1:4])) |
| l_face_norm_data.append(f) |
|
|
| face_data += l_face_data |
| face_uv_data += l_face_uv_data |
| face_norm_data += l_face_norm_data |
|
|
| if cur_mat is not None: |
| if cur_mat not in face_data_mat.keys(): |
| face_data_mat[cur_mat] = [] |
| if cur_mat not in face_uv_data_mat.keys(): |
| face_uv_data_mat[cur_mat] = [] |
| if cur_mat not in face_norm_data_mat.keys(): |
| face_norm_data_mat[cur_mat] = [] |
| face_data_mat[cur_mat] += l_face_data |
| face_uv_data_mat[cur_mat] += l_face_uv_data |
| face_norm_data_mat[cur_mat] += l_face_norm_data |
|
|
| vertices = np.array(vertex_data) |
| faces = np.array(face_data) |
|
|
| norms = np.array(norm_data) |
| norms = normalize_v3(norms) |
| face_normals = np.array(face_norm_data) |
|
|
| uvs = np.array(uv_data) |
| face_uvs = np.array(face_uv_data) |
|
|
| out_tuple = (vertices, faces, norms, face_normals, uvs, face_uvs) |
|
|
| if cur_mat is not None and mtl_data is not None: |
| for key in face_data_mat: |
| face_data_mat[key] = np.array(face_data_mat[key]) |
| face_uv_data_mat[key] = np.array(face_uv_data_mat[key]) |
| face_norm_data_mat[key] = np.array(face_norm_data_mat[key]) |
|
|
| out_tuple += (face_data_mat, face_norm_data_mat, face_uv_data_mat, |
| mtl_data) |
|
|
| return out_tuple |
|
|
|
|
| def load_scan(mesh_file, with_normal=False, with_texture=False): |
| vertex_data = [] |
| norm_data = [] |
| uv_data = [] |
|
|
| face_data = [] |
| face_norm_data = [] |
| face_uv_data = [] |
|
|
| if isinstance(mesh_file, str): |
| f = open(mesh_file, "r") |
| else: |
| f = mesh_file |
| for line in f: |
| if isinstance(line, bytes): |
| line = line.decode("utf-8") |
| if line.startswith('#'): |
| continue |
| values = line.split() |
| if not values: |
| continue |
|
|
| if values[0] == 'v': |
| v = list(map(float, values[1:4])) |
| vertex_data.append(v) |
| elif values[0] == 'vn': |
| vn = list(map(float, values[1:4])) |
| norm_data.append(vn) |
| elif values[0] == 'vt': |
| vt = list(map(float, values[1:3])) |
| uv_data.append(vt) |
|
|
| elif values[0] == 'f': |
| |
| if len(values) > 4: |
| f = list(map(lambda x: int(x.split('/')[0]), values[1:4])) |
| face_data.append(f) |
| f = list( |
| map(lambda x: int(x.split('/')[0]), |
| [values[3], values[4], values[1]])) |
| face_data.append(f) |
| |
| else: |
| f = list(map(lambda x: int(x.split('/')[0]), values[1:4])) |
| face_data.append(f) |
|
|
| |
| if len(values[1].split('/')) >= 2: |
| |
| if len(values) > 4: |
| f = list(map(lambda x: int(x.split('/')[1]), values[1:4])) |
| face_uv_data.append(f) |
| f = list( |
| map(lambda x: int(x.split('/')[1]), |
| [values[3], values[4], values[1]])) |
| face_uv_data.append(f) |
| |
| elif len(values[1].split('/')[1]) != 0: |
| f = list(map(lambda x: int(x.split('/')[1]), values[1:4])) |
| face_uv_data.append(f) |
| |
| if len(values[1].split('/')) == 3: |
| |
| if len(values) > 4: |
| f = list(map(lambda x: int(x.split('/')[2]), values[1:4])) |
| face_norm_data.append(f) |
| f = list( |
| map(lambda x: int(x.split('/')[2]), |
| [values[3], values[4], values[1]])) |
| face_norm_data.append(f) |
| |
| elif len(values[1].split('/')[2]) != 0: |
| f = list(map(lambda x: int(x.split('/')[2]), values[1:4])) |
| face_norm_data.append(f) |
|
|
| vertices = np.array(vertex_data) |
| faces = np.array(face_data) - 1 |
|
|
| if with_texture and with_normal: |
| uvs = np.array(uv_data) |
| face_uvs = np.array(face_uv_data) - 1 |
| norms = np.array(norm_data) |
| if norms.shape[0] == 0: |
| norms = compute_normal(vertices, faces) |
| face_normals = faces |
| else: |
| norms = normalize_v3(norms) |
| face_normals = np.array(face_norm_data) - 1 |
| return vertices, faces, norms, face_normals, uvs, face_uvs |
|
|
| if with_texture: |
| uvs = np.array(uv_data) |
| face_uvs = np.array(face_uv_data) - 1 |
| return vertices, faces, uvs, face_uvs |
|
|
| if with_normal: |
| norms = np.array(norm_data) |
| norms = normalize_v3(norms) |
| face_normals = np.array(face_norm_data) - 1 |
| return vertices, faces, norms, face_normals |
|
|
| return vertices, faces |
|
|
|
|
| def normalize_v3(arr): |
| ''' Normalize a numpy array of 3 component vectors shape=(n,3) ''' |
| lens = np.sqrt(arr[:, 0]**2 + arr[:, 1]**2 + arr[:, 2]**2) |
| eps = 0.00000001 |
| lens[lens < eps] = eps |
| arr[:, 0] /= lens |
| arr[:, 1] /= lens |
| arr[:, 2] /= lens |
| return arr |
|
|
|
|
| def compute_normal(vertices, faces): |
| |
| norm = np.zeros(vertices.shape, dtype=vertices.dtype) |
| |
| tris = vertices[faces] |
| |
| n = np.cross(tris[::, 1] - tris[::, 0], tris[::, 2] - tris[::, 0]) |
| |
| |
| normalize_v3(n) |
| |
| |
| |
| |
| norm[faces[:, 0]] += n |
| norm[faces[:, 1]] += n |
| norm[faces[:, 2]] += n |
| normalize_v3(norm) |
|
|
| return norm |
|
|
|
|
| def compute_normal_batch(vertices, faces): |
|
|
| bs, nv = vertices.shape[:2] |
| bs, nf = faces.shape[:2] |
|
|
| vert_norm = torch.zeros(bs * nv, 3).type_as(vertices) |
| tris = face_vertices(vertices, faces) |
| face_norm = F.normalize(torch.cross(tris[:, :, 1] - tris[:, :, 0], |
| tris[:, :, 2] - tris[:, :, 0]), |
| dim=-1) |
|
|
| faces = (faces + |
| (torch.arange(bs).type_as(faces) * nv)[:, None, None]).view( |
| -1, 3) |
|
|
| vert_norm[faces[:, 0]] += face_norm.view(-1, 3) |
| vert_norm[faces[:, 1]] += face_norm.view(-1, 3) |
| vert_norm[faces[:, 2]] += face_norm.view(-1, 3) |
|
|
| vert_norm = F.normalize(vert_norm, dim=-1).view(bs, nv, 3) |
|
|
| return vert_norm |
|
|
|
|
| |
| def compute_tangent(vertices, faces, normals, uvs, faceuvs): |
| |
| |
| c1 = np.cross(normals, np.array([0, 1, 0.0])) |
| tan = c1 |
| normalize_v3(tan) |
| btan = np.cross(normals, tan) |
|
|
| |
|
|
| |
| |
|
|
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
|
|
| |
| |
|
|
| |
|
|
| return tan, btan |
|
|