|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from lib.renderer.mesh import load_fit_body, compute_normal_batch |
|
from lib.dataset.body_model import TetraSMPLModel |
|
from lib.common.render import Render |
|
from lib.dataset.mesh_util import * |
|
from lib.pare.pare.utils.geometry import rotation_matrix_to_angle_axis |
|
from lib.net.nerf_util import sample_ray_h36m, get_wsampling_points |
|
from termcolor import colored |
|
import os.path as osp |
|
import numpy as np |
|
from PIL import Image |
|
import random |
|
import os, cv2 |
|
import trimesh |
|
import torch |
|
import vedo |
|
import torchvision.transforms as transforms |
|
import matplotlib.pyplot as plt |
|
import trimesh |
|
os.environ["OPENCV_IO_ENABLE_OPENEXR"]="1" |
|
|
|
cape_gender = { |
|
"male": [ |
|
'00032', '00096', '00122', '00127', '00145', '00215', '02474', '03284', |
|
'03375', '03394' |
|
], |
|
"female": ['00134', '00159', '03223', '03331', '03383'] |
|
} |
|
|
|
|
|
|
|
class PIFuDataset(): |
|
|
|
def __init__(self, cfg, split='train', vis=False): |
|
|
|
self.split = split |
|
self.root = cfg.root |
|
self.bsize = cfg.batch_size |
|
self.overfit = cfg.overfit |
|
|
|
|
|
self.vis = vis |
|
|
|
self.opt = cfg.dataset |
|
self.datasets = self.opt.types |
|
self.input_size = self.opt.input_size |
|
self.scales = self.opt.scales |
|
self.workers = cfg.num_threads |
|
self.prior_type = cfg.net.prior_type |
|
|
|
self.noise_type = self.opt.noise_type |
|
self.noise_scale = self.opt.noise_scale |
|
|
|
noise_joints = [4, 5, 7, 8, 13, 14, 16, 17, 18, 19, 20, 21] |
|
|
|
self.noise_smpl_idx = [] |
|
self.noise_smplx_idx = [] |
|
|
|
for idx in noise_joints: |
|
self.noise_smpl_idx.append(idx * 3) |
|
self.noise_smpl_idx.append(idx * 3 + 1) |
|
self.noise_smpl_idx.append(idx * 3 + 2) |
|
|
|
self.noise_smplx_idx.append((idx - 1) * 3) |
|
self.noise_smplx_idx.append((idx - 1) * 3 + 1) |
|
self.noise_smplx_idx.append((idx - 1) * 3 + 2) |
|
|
|
self.use_sdf = cfg.sdf |
|
self.sdf_clip = cfg.sdf_clip |
|
|
|
|
|
self.in_geo = [item[0] for item in cfg.net.in_geo] |
|
self.in_nml = [item[0] for item in cfg.net.in_nml] |
|
|
|
self.in_geo_dim = [item[1] for item in cfg.net.in_geo] |
|
self.in_nml_dim = [item[1] for item in cfg.net.in_nml] |
|
|
|
self.in_total = self.in_geo + self.in_nml |
|
self.in_total_dim = self.in_geo_dim + self.in_nml_dim |
|
|
|
self.base_keys = ["smpl_verts", "smpl_faces"] |
|
self.feat_names = cfg.net.smpl_feats |
|
|
|
self.feat_keys = self.base_keys + [f"smpl_{feat_name}" for feat_name in self.feat_names] |
|
|
|
if self.split == 'train': |
|
self.rotations = np.arange(0, 360, 360 / self.opt.rotation_num).astype(np.int32) |
|
else: |
|
self.rotations = range(0, 360, 120) |
|
|
|
self.datasets_dict = {} |
|
|
|
for dataset_id, dataset in enumerate(self.datasets): |
|
|
|
mesh_dir = None |
|
smplx_dir = None |
|
|
|
dataset_dir = osp.join(self.root, dataset) |
|
|
|
mesh_dir = osp.join(dataset_dir, "scans") |
|
smplx_dir = osp.join(dataset_dir, "smplx") |
|
smpl_dir = osp.join(dataset_dir, "smpl") |
|
|
|
self.datasets_dict[dataset] = { |
|
"smplx_dir": smplx_dir, |
|
"smpl_dir": smpl_dir, |
|
"mesh_dir": mesh_dir, |
|
"scale": self.scales[dataset_id] |
|
} |
|
|
|
if split == 'train': |
|
self.datasets_dict[dataset].update( |
|
{"subjects": np.loadtxt(osp.join(dataset_dir, "all.txt"), dtype=str)}) |
|
else: |
|
self.datasets_dict[dataset].update( |
|
{"subjects": np.loadtxt(osp.join(dataset_dir, "test.txt"), dtype=str)}) |
|
|
|
self.subject_list = self.get_subject_list(split) |
|
self.smplx = SMPLX() |
|
|
|
|
|
self.image_to_tensor = transforms.Compose([ |
|
transforms.Resize(self.input_size), |
|
transforms.ToTensor(), |
|
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) |
|
]) |
|
|
|
|
|
self.mask_to_tensor = transforms.Compose([ |
|
transforms.Resize(self.input_size), |
|
transforms.ToTensor(), |
|
transforms.Normalize((0.0,), (1.0,)) |
|
]) |
|
|
|
self.device = torch.device(f"cuda:{cfg.gpus[0]}") |
|
self.render = Render(size=512, device=self.device) |
|
|
|
self.UV_RENDER='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/UV_RENDER' |
|
self.UV_MASK='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/UV_MASK' |
|
self.UV_POS='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/UV_POS' |
|
self.UV_NORMAL='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/UV_NORMAL' |
|
self.IMAGE_MASK='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/MASK' |
|
self.PARAM='/sdb/zzc/zzc/paper_models/PIFu-master/PIFu-master/training_data/PARAM' |
|
self.depth='./data/thuman2_36views' |
|
|
|
def render_normal(self, verts, faces): |
|
|
|
|
|
self.render.load_meshes(verts, faces) |
|
return self.render.get_rgb_image() |
|
|
|
def get_subject_list(self, split): |
|
|
|
subject_list = [] |
|
|
|
for dataset in self.datasets: |
|
|
|
split_txt = osp.join(self.root, dataset, f'{split}.txt') |
|
|
|
if osp.exists(split_txt): |
|
print(f"load from {split_txt}") |
|
subject_list += np.loadtxt(split_txt, dtype=str).tolist() |
|
else: |
|
full_txt = osp.join(self.root, dataset, 'all.txt') |
|
print(f"split {full_txt} into train/val/test") |
|
|
|
full_lst = np.loadtxt(full_txt, dtype=str) |
|
full_lst = [dataset + "/" + item for item in full_lst] |
|
[train_lst, test_lst, val_lst] = np.split(full_lst, [ |
|
500, |
|
500 + 5, |
|
]) |
|
|
|
np.savetxt(full_txt.replace("all", "train"), train_lst, fmt="%s") |
|
np.savetxt(full_txt.replace("all", "test"), test_lst, fmt="%s") |
|
np.savetxt(full_txt.replace("all", "val"), val_lst, fmt="%s") |
|
|
|
print(f"load from {split_txt}") |
|
subject_list += np.loadtxt(split_txt, dtype=str).tolist() |
|
|
|
if self.split != 'test': |
|
subject_list += subject_list[:self.bsize - len(subject_list) % self.bsize] |
|
print(colored(f"total: {len(subject_list)}", "yellow")) |
|
random.shuffle(subject_list) |
|
|
|
|
|
return subject_list |
|
|
|
def __len__(self): |
|
return len(self.subject_list) * len(self.rotations) |
|
|
|
def __getitem__(self, index): |
|
|
|
|
|
if self.overfit: |
|
index = 0 |
|
|
|
rid = index % len(self.rotations) |
|
mid = index // len(self.rotations) |
|
|
|
rotation = self.rotations[rid] |
|
subject = self.subject_list[mid].split("/")[1] |
|
dataset = self.subject_list[mid].split("/")[0] |
|
render_folder = "/".join([dataset + f"_{self.opt.rotation_num}views", subject]) |
|
if dataset=='thuman2': |
|
old_folder="/".join([dataset + f"_{self.opt.rotation_num}views_nosideview", subject]) |
|
else: |
|
old_folder=render_folder |
|
|
|
|
|
|
|
uv_render_path=os.path.join(self.UV_RENDER,subject,'%d_%d_%02d.jpg'%(rotation,0,0)) |
|
uv_mask_path = os.path.join(self.UV_MASK, subject, '%02d.png' % (0)) |
|
uv_pos_path = os.path.join(self.UV_POS, subject, '%02d.exr' % (0)) |
|
uv_normal_path = os.path.join(self.UV_NORMAL, subject, '%02d.png' % (0)) |
|
image_mask_path=os.path.join(self.IMAGE_MASK,subject,'%d_%d_%02d.png'%(rotation,0,0)) |
|
param_path=os.path.join(self.PARAM, subject,'%d_%d_%02d.npy'%(rotation,0,0)) |
|
depth_path=os.path.join(self.depth,subject,"depth_F",'%03d.png'%(rotation)) |
|
|
|
|
|
|
|
|
|
data_dict = { |
|
'dataset': dataset, |
|
'subject': subject, |
|
'rotation': rotation, |
|
'scale': self.datasets_dict[dataset]["scale"], |
|
'calib_path': osp.join(self.root, render_folder, 'calib', f'{rotation:03d}.txt'), |
|
'image_path': osp.join(self.root, render_folder, 'render', f'{rotation:03d}.png'), |
|
'smpl_path': osp.join(self.datasets_dict[dataset]["smpl_dir"], f"{subject}.obj"), |
|
'vis_path': osp.join(self.root, old_folder, 'vis', f'{rotation:03d}.pt'), |
|
'uv_render_path': osp.join(self.root, render_folder, 'uv_color', f'{rotation:03d}.png'), |
|
'uv_mask_path': uv_mask_path, |
|
'uv_pos_path': uv_pos_path, |
|
'uv_normal_path': osp.join(self.root, render_folder, 'uv_normal', '%02d.png' % (0)), |
|
'image_mask_path':image_mask_path, |
|
'param_path':param_path, |
|
'depth_path':depth_path, |
|
} |
|
|
|
if dataset == 'thuman2': |
|
data_dict.update({ |
|
'mesh_path': |
|
osp.join(self.datasets_dict[dataset]["mesh_dir"], f"{subject}/{subject}.obj"), |
|
'smplx_path': |
|
|
|
osp.join("./data/thuman2/smplx/", f"{subject}.obj"), |
|
'smpl_param': |
|
osp.join(self.datasets_dict[dataset]["smpl_dir"], f"{subject}.pkl"), |
|
'smplx_param': |
|
osp.join(self.datasets_dict[dataset]["smplx_dir"], f"{subject}.pkl"), |
|
}) |
|
elif dataset == 'cape': |
|
data_dict.update({ |
|
'mesh_path': osp.join(self.datasets_dict[dataset]["mesh_dir"], f"{subject}.obj"), |
|
'smpl_param': osp.join(self.datasets_dict[dataset]["smpl_dir"], f"{subject}.npz"), |
|
}) |
|
|
|
|
|
data_dict.update(self.load_calib(data_dict)) |
|
|
|
|
|
for name, channel in zip(self.in_total, self.in_total_dim): |
|
|
|
if f'{name}_path' not in data_dict.keys(): |
|
data_dict.update({ |
|
f'{name}_path': osp.join(self.root, render_folder, name, f'{rotation:03d}.png') |
|
}) |
|
|
|
|
|
if os.path.exists(data_dict[f'{name}_path']): |
|
data_dict.update( |
|
{name: self.imagepath2tensor(data_dict[f'{name}_path'], channel, inv=False)}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if name=='T_normal_F' and dataset == 'thuman2': |
|
|
|
normal_right_path=osp.join(self.root, render_folder, "T_normal_R", f'{rotation:03d}.png') |
|
normal_left_path=osp.join(self.root, render_folder, "T_normal_L", f'{rotation:03d}.png') |
|
data_dict.update( |
|
{'T_normal_R': self.imagepath2tensor(normal_right_path, channel, inv=False)}) |
|
data_dict.update( |
|
{'T_normal_L': self.imagepath2tensor(normal_left_path, channel, inv=False)}) |
|
|
|
data_dict.update(self.load_mesh(data_dict)) |
|
|
|
data_dict.update( |
|
self.get_sampling_geo(data_dict, is_valid=self.split == "val", is_sdf=self.use_sdf)) |
|
data_dict.update(self.load_smpl(data_dict, self.vis)) |
|
|
|
if self.prior_type == 'pamir': |
|
data_dict.update(self.load_smpl_voxel(data_dict)) |
|
|
|
if (self.split != 'test') and (not self.vis): |
|
|
|
del data_dict['verts'] |
|
del data_dict['faces'] |
|
|
|
if not self.vis: |
|
del data_dict['mesh'] |
|
|
|
path_keys = [key for key in data_dict.keys() if '_path' in key or '_dir' in key] |
|
for key in path_keys: |
|
del data_dict[key] |
|
|
|
return data_dict |
|
|
|
def imagepath2tensor(self, path, channel=3, inv=False): |
|
|
|
rgba = Image.open(path).convert('RGBA') |
|
|
|
|
|
if "cape" in path and 'T_' not in path: |
|
mask = (cv2.imread(path.replace(path.split("/")[-2], "mask"), 0) > 1) |
|
img = np.asarray(rgba)[:, :, :3] |
|
fill_mask = ((mask & (img.sum(axis=2) == 0))).astype(np.uint8) |
|
image = Image.fromarray( |
|
cv2.inpaint(img * mask[..., None], fill_mask, 3, cv2.INPAINT_TELEA)) |
|
mask = Image.fromarray(mask) |
|
else: |
|
mask = rgba.split()[-1] |
|
image = rgba.convert('RGB') |
|
image = self.image_to_tensor(image) |
|
mask = self.mask_to_tensor(mask) |
|
image = (image * mask)[:channel] |
|
|
|
return (image * (0.5 - inv) * 2.0).float() |
|
|
|
def load_calib(self, data_dict): |
|
calib_data = np.loadtxt(data_dict['calib_path'], dtype=float) |
|
extrinsic = calib_data[:4, :4] |
|
intrinsic = calib_data[4:8, :4] |
|
calib_mat = np.matmul(intrinsic, extrinsic) |
|
calib_mat = torch.from_numpy(calib_mat).float() |
|
return {'calib': calib_mat} |
|
|
|
def load_mesh(self, data_dict): |
|
|
|
mesh_path = data_dict['mesh_path'] |
|
scale = data_dict['scale'] |
|
|
|
verts, faces = obj_loader(mesh_path) |
|
|
|
mesh = HoppeMesh(verts * scale, faces) |
|
|
|
return { |
|
'mesh': mesh, |
|
'verts': torch.as_tensor(verts * scale).float(), |
|
'faces': torch.as_tensor(faces).long() |
|
} |
|
|
|
def add_noise(self, beta_num, smpl_pose, smpl_betas, noise_type, noise_scale, type, hashcode): |
|
|
|
np.random.seed(hashcode) |
|
|
|
if type == 'smplx': |
|
noise_idx = self.noise_smplx_idx |
|
else: |
|
noise_idx = self.noise_smpl_idx |
|
|
|
if 'beta' in noise_type and noise_scale[noise_type.index("beta")] > 0.0: |
|
smpl_betas += (np.random.rand(beta_num) - |
|
0.5) * 2.0 * noise_scale[noise_type.index("beta")] |
|
smpl_betas = smpl_betas.astype(np.float32) |
|
|
|
if 'pose' in noise_type and noise_scale[noise_type.index("pose")] > 0.0: |
|
smpl_pose[noise_idx] += (np.random.rand(len(noise_idx)) - |
|
0.5) * 2.0 * np.pi * noise_scale[noise_type.index("pose")] |
|
smpl_pose = smpl_pose.astype(np.float32) |
|
if type == 'smplx': |
|
return torch.as_tensor(smpl_pose[None, ...]), torch.as_tensor(smpl_betas[None, ...]) |
|
else: |
|
return smpl_pose, smpl_betas |
|
|
|
def compute_smpl_verts(self, data_dict, noise_type=None, noise_scale=None): |
|
|
|
dataset = data_dict['dataset'] |
|
smplx_dict = {} |
|
|
|
smplx_param = np.load(data_dict['smplx_param'], allow_pickle=True) |
|
smplx_pose = smplx_param["body_pose"] |
|
smplx_betas = smplx_param["betas"] |
|
smplx_pose, smplx_betas = self.add_noise( |
|
smplx_betas.shape[1], |
|
smplx_pose[0], |
|
smplx_betas[0], |
|
noise_type, |
|
noise_scale, |
|
type='smplx', |
|
hashcode=(hash(f"{data_dict['subject']}_{data_dict['rotation']}")) % (10**8)) |
|
|
|
smplx_out, _ = load_fit_body(fitted_path=data_dict['smplx_param'], |
|
scale=self.datasets_dict[dataset]['scale'], |
|
smpl_type='smplx', |
|
smpl_gender='male', |
|
noise_dict=dict(betas=smplx_betas, body_pose=smplx_pose)) |
|
|
|
smplx_dict.update({ |
|
"type": "smplx", |
|
"gender": 'male', |
|
"body_pose": torch.as_tensor(smplx_pose), |
|
"betas": torch.as_tensor(smplx_betas) |
|
}) |
|
|
|
return smplx_out.vertices, smplx_dict |
|
|
|
def compute_voxel_verts(self, data_dict, noise_type=None, noise_scale=None): |
|
|
|
smpl_param = np.load(data_dict["smpl_param"], allow_pickle=True) |
|
|
|
if data_dict['dataset'] == 'cape': |
|
pid = data_dict['subject'].split("-")[0] |
|
gender = "male" if pid in cape_gender["male"] else "female" |
|
smpl_pose = smpl_param['pose'].flatten() |
|
smpl_betas = np.zeros((1, 10)) |
|
else: |
|
gender = 'male' |
|
smpl_pose = rotation_matrix_to_angle_axis(torch.as_tensor( |
|
smpl_param["full_pose"][0])).numpy() |
|
smpl_betas = smpl_param["betas"] |
|
|
|
smpl_path = osp.join(self.smplx.model_dir, f"smpl/SMPL_{gender.upper()}.pkl") |
|
tetra_path = osp.join(self.smplx.tedra_dir, f"tetra_{gender}_adult_smpl.npz") |
|
|
|
smpl_model = TetraSMPLModel(smpl_path, tetra_path, "adult") |
|
|
|
smpl_pose, smpl_betas = self.add_noise( |
|
smpl_model.beta_shape[0], |
|
smpl_pose.flatten(), |
|
smpl_betas[0], |
|
noise_type, |
|
noise_scale, |
|
type="smpl", |
|
hashcode=(hash(f"{data_dict['subject']}_{data_dict['rotation']}")) % (10**8), |
|
) |
|
|
|
smpl_model.set_params(pose=smpl_pose.reshape(-1, 3), |
|
beta=smpl_betas, |
|
trans=smpl_param["transl"]) |
|
if data_dict['dataset'] == 'cape': |
|
verts = np.concatenate([smpl_model.verts, smpl_model.verts_added], axis=0) * 100.0 |
|
else: |
|
verts = (np.concatenate([smpl_model.verts, smpl_model.verts_added], axis=0) * |
|
smpl_param["scale"] + |
|
smpl_param["translation"]) * self.datasets_dict[data_dict["dataset"]]["scale"] |
|
|
|
faces = (np.loadtxt( |
|
osp.join(self.smplx.tedra_dir, "tetrahedrons_male_adult.txt"), |
|
dtype=np.int32, |
|
) - 1) |
|
|
|
pad_v_num = int(8000 - verts.shape[0]) |
|
pad_f_num = int(25100 - faces.shape[0]) |
|
|
|
verts = np.pad(verts, ((0, pad_v_num), (0, 0)), mode="constant", |
|
constant_values=0.0).astype(np.float32) |
|
faces = np.pad(faces, ((0, pad_f_num), (0, 0)), mode="constant", |
|
constant_values=0.0).astype(np.int32) |
|
|
|
return verts, faces, pad_v_num, pad_f_num |
|
|
|
def densely_sample(self, verts, faces): |
|
|
|
new_vertices,new_faces,index=trimesh.remesh.subdivide(verts,faces) |
|
|
|
return new_vertices, torch.LongTensor(new_faces) |
|
... |
|
|
|
def load_smpl(self, data_dict, vis=False, densely_sample=False): |
|
|
|
smpl_type = "smplx" if ('smplx_path' in data_dict.keys() and |
|
os.path.exists(data_dict['smplx_path'])) else "smpl" |
|
|
|
return_dict = {} |
|
|
|
if 'smplx_param' in data_dict.keys() and \ |
|
os.path.exists(data_dict['smplx_param']) and \ |
|
sum(self.noise_scale) > 0.0: |
|
smplx_verts, smplx_dict = self.compute_smpl_verts(data_dict, self.noise_type, |
|
self.noise_scale) |
|
smplx_faces = torch.as_tensor(self.smplx.smplx_faces).long() |
|
smplx_cmap = torch.as_tensor(np.load(self.smplx.cmap_vert_path)).float() |
|
|
|
else: |
|
smplx_vis = torch.load(data_dict['vis_path']).float() |
|
return_dict.update({'smpl_vis': smplx_vis}) |
|
|
|
|
|
|
|
smplx_verts = rescale_smpl(data_dict[f"{smpl_type}_path"], scale=100.0) |
|
smplx_faces = torch.as_tensor(getattr(self.smplx, f"{smpl_type}_faces")).long() |
|
smplx_cmap = self.smplx.cmap_smpl_vids(smpl_type) |
|
|
|
if densely_sample: |
|
smplx_verts,smplx_faces=self.densely_sample(smplx_verts,smplx_faces) |
|
|
|
smplx_verts = projection(smplx_verts, data_dict['calib']).float() |
|
|
|
|
|
if "smpl_vis" not in return_dict.keys() and "smpl_vis" in self.feat_keys: |
|
(xy, z) = torch.as_tensor(smplx_verts).to(self.device).split([2, 1], dim=1) |
|
smplx_vis = get_visibility(xy, z, torch.as_tensor(smplx_faces).to(self.device).long()) |
|
return_dict['smpl_vis'] = smplx_vis |
|
|
|
if "smpl_norm" not in return_dict.keys() and "smpl_norm" in self.feat_keys: |
|
|
|
smplx_norms = compute_normal_batch(smplx_verts.unsqueeze(0), |
|
smplx_faces.unsqueeze(0))[0] |
|
return_dict["smpl_norm"] = smplx_norms |
|
|
|
if "smpl_cmap" not in return_dict.keys() and "smpl_cmap" in self.feat_keys: |
|
return_dict["smpl_cmap"] = smplx_cmap |
|
|
|
sample_num=smplx_verts.shape[0] |
|
verts_ids=np.arange(smplx_verts.shape[0]) |
|
|
|
sample_ids=torch.LongTensor(verts_ids) |
|
return_dict.update({ |
|
'smpl_verts': smplx_verts, |
|
'smpl_faces': smplx_faces, |
|
'smpl_cmap': smplx_cmap, |
|
'smpl_sample_id':sample_ids, |
|
}) |
|
|
|
if vis: |
|
|
|
(xy, z) = torch.as_tensor(smplx_verts).to(self.device).split([2, 1], dim=1) |
|
smplx_vis = get_visibility(xy, z, torch.as_tensor(smplx_faces).to(self.device).long()) |
|
|
|
T_normal_F, T_normal_B = self.render_normal( |
|
(smplx_verts * torch.tensor(np.array([1.0, -1.0, 1.0]))).to(self.device), |
|
smplx_faces.to(self.device)) |
|
|
|
return_dict.update({ |
|
"T_normal_F": T_normal_F.squeeze(0), |
|
"T_normal_B": T_normal_B.squeeze(0) |
|
}) |
|
query_points = projection(data_dict['samples_geo'], data_dict['calib']).float() |
|
|
|
smplx_sdf, smplx_norm, smplx_cmap, smplx_vis = cal_sdf_batch( |
|
smplx_verts.unsqueeze(0).to(self.device), |
|
smplx_faces.unsqueeze(0).to(self.device), |
|
smplx_cmap.unsqueeze(0).to(self.device), |
|
smplx_vis.unsqueeze(0).to(self.device), |
|
query_points.unsqueeze(0).contiguous().to(self.device)) |
|
|
|
return_dict.update({ |
|
'smpl_feat': |
|
torch.cat((smplx_sdf[0].detach().cpu(), smplx_cmap[0].detach().cpu(), |
|
smplx_norm[0].detach().cpu(), smplx_vis[0].detach().cpu()), |
|
dim=1) |
|
}) |
|
|
|
return return_dict |
|
|
|
def load_smpl_voxel(self, data_dict): |
|
|
|
smpl_verts, smpl_faces, pad_v_num, pad_f_num = self.compute_voxel_verts( |
|
data_dict, self.noise_type, self.noise_scale) |
|
smpl_verts = projection(smpl_verts, data_dict['calib']) |
|
|
|
smpl_verts *= 0.5 |
|
|
|
return { |
|
'voxel_verts': smpl_verts, |
|
'voxel_faces': smpl_faces, |
|
'pad_v_num': pad_v_num, |
|
'pad_f_num': pad_f_num |
|
} |
|
|
|
def get_sampling_geo(self, data_dict, is_valid=False, is_sdf=False): |
|
|
|
|
|
mesh = data_dict['mesh'] |
|
calib = data_dict['calib'] |
|
|
|
|
|
|
|
n_samples_surface = 4*self.opt.num_sample_geo |
|
vert_ids = np.arange(mesh.verts.shape[0]) |
|
|
|
samples_surface_ids = np.random.choice(vert_ids, n_samples_surface, replace=True) |
|
|
|
samples_surface = mesh.verts[samples_surface_ids, :] |
|
|
|
|
|
|
|
offset = np.random.normal(scale=self.opt.sigma_geo, size=(n_samples_surface, 1)) |
|
samples_surface += mesh.vert_normals[samples_surface_ids, :] * offset |
|
|
|
|
|
|
|
|
|
calib_inv = np.linalg.inv(calib) |
|
n_samples_space = self.opt.num_sample_geo // 4 |
|
samples_space_img = 2.0 * np.random.rand(n_samples_space, 3) - 1.0 |
|
samples_space = projection(samples_space_img, calib_inv) |
|
|
|
samples = np.concatenate([samples_surface, samples_space], 0) |
|
np.random.shuffle(samples) |
|
|
|
|
|
inside = mesh.contains(samples) |
|
inside_samples = samples[inside >= 0.5] |
|
outside_samples = samples[inside < 0.5] |
|
|
|
nin = inside_samples.shape[0] |
|
|
|
if nin > self.opt.num_sample_geo // 2: |
|
inside_samples = inside_samples[:self.opt.num_sample_geo // 2] |
|
outside_samples = outside_samples[:self.opt.num_sample_geo // 2] |
|
else: |
|
outside_samples = outside_samples[:(self.opt.num_sample_geo - nin)] |
|
|
|
samples = np.concatenate([inside_samples, outside_samples]) |
|
labels = np.concatenate( |
|
[np.ones(inside_samples.shape[0]), |
|
np.zeros(outside_samples.shape[0])]) |
|
|
|
samples = torch.from_numpy(samples).float() |
|
labels = torch.from_numpy(labels).float() |
|
|
|
|
|
|
|
|
|
if not self.datasets[0]=='cape': |
|
|
|
uv_render_path = data_dict['uv_render_path'] |
|
uv_mask_path = data_dict['uv_mask_path'] |
|
uv_pos_path = data_dict['uv_pos_path'] |
|
uv_normal_path = data_dict['uv_normal_path'] |
|
|
|
|
|
|
|
uv_mask = cv2.imread(uv_mask_path) |
|
uv_mask = uv_mask[:, :, 0] != 0 |
|
|
|
|
|
uv_render = cv2.imread(uv_render_path) |
|
uv_render = cv2.cvtColor(uv_render, cv2.COLOR_BGR2RGB) / 255.0 |
|
|
|
|
|
|
|
uv_normal = cv2.imread(uv_normal_path) |
|
uv_normal = cv2.cvtColor(uv_normal, cv2.COLOR_BGR2RGB) / 255.0 |
|
uv_normal = 2.0 * uv_normal - 1.0 |
|
|
|
|
|
uv_pos = cv2.imread(uv_pos_path, 2 | 4)[:, :, ::-1] |
|
|
|
|
|
uv_mask = uv_mask.reshape((-1)) |
|
uv_pos = uv_pos.reshape((-1, 3)) |
|
uv_render = uv_render.reshape((-1, 3)) |
|
uv_normal = uv_normal.reshape((-1, 3)) |
|
|
|
surface_points = uv_pos[uv_mask] |
|
surface_colors = uv_render[uv_mask] |
|
surface_normal = uv_normal[uv_mask] |
|
|
|
|
|
n_samples_surface = self.opt.num_sample_color |
|
|
|
if n_samples_space>surface_points.shape[0]: |
|
print(surface_points.shape[0]) |
|
print( uv_pos_path) |
|
assert 0 |
|
sample_list = random.sample(range(0, surface_points.shape[0] - 1), n_samples_surface) |
|
surface_points=surface_points[sample_list].T |
|
surface_colors=surface_colors[sample_list].T |
|
surface_normal=surface_normal[sample_list].T |
|
|
|
|
|
normal = torch.Tensor(surface_normal).float() |
|
samples_surface = torch.Tensor(surface_points).float() \ |
|
+ torch.normal(mean=torch.zeros((1, normal.size(1))), std=self.opt.sigma_color).expand_as(normal) * normal |
|
|
|
sample_color=samples_surface.T |
|
rgbs_color=(surface_colors-0.5)*2 |
|
rgbs_color=rgbs_color.T |
|
colors = torch.from_numpy(rgbs_color).float() |
|
|
|
|
|
|
|
|
|
|
|
|
|
return {'samples_geo': samples, 'labels_geo': labels,"samples_color":sample_color,"color_labels":colors} |
|
else: |
|
return {'samples_geo': samples, 'labels_geo': labels} |
|
def get_param(self,data_dict): |
|
W=512 |
|
H=512 |
|
|
|
param_path = data_dict['param_path'] |
|
|
|
param = np.load(param_path, allow_pickle=True) |
|
|
|
ortho_ratio = param.item().get('ortho_ratio') |
|
|
|
scale = param.item().get('scale') |
|
|
|
center = param.item().get('center') |
|
|
|
R = param.item().get('R') |
|
translate = -np.matmul(R, center).reshape(3, 1) |
|
extrinsic = np.concatenate([R, translate], axis=1) |
|
extrinsic = np.concatenate([extrinsic, np.array([0, 0, 0, 1]).reshape(1, 4)], 0) |
|
|
|
|
|
|
|
scale_intrinsic = np.identity(4) |
|
scale_intrinsic[0, 0] = scale / ortho_ratio |
|
scale_intrinsic[1, 1] = -scale / ortho_ratio |
|
scale_intrinsic[2, 2] = scale / ortho_ratio |
|
|
|
uv_intrinsic = np.identity(4) |
|
uv_intrinsic[0, 0] = 1.0 / float(W // 2) |
|
uv_intrinsic[1, 1] = 1.0 / float(W // 2) |
|
uv_intrinsic[2, 2] = 1.0 / float(W // 2) |
|
|
|
|
|
return scale_intrinsic[:3,:3],R,translate.numpy(),center |
|
|
|
def get_extrinsics(self,data_dict): |
|
calib_data = np.loadtxt(data_dict['calib_path'], dtype=float) |
|
extrinsic = calib_data[:4, :4] |
|
intrinsic = calib_data[4:8, :4] |
|
return intrinsic.astype(np.float32) |
|
|
|
def visualize_sampling3D(self, data_dict, mode='vis'): |
|
|
|
|
|
vp = vedo.Plotter(title="", size=(1500, 1500), axes=0, bg='white') |
|
vis_list = [] |
|
|
|
assert mode in ['vis', 'sdf', 'normal', 'cmap', 'occ'] |
|
|
|
|
|
if mode == 'vis': |
|
labels = data_dict[f'smpl_feat'][:, [-1]] |
|
colors = np.concatenate([labels, labels, labels], axis=1) |
|
elif mode == 'occ': |
|
labels = data_dict[f'labels_geo'][..., None] |
|
colors = np.concatenate([labels, labels, labels], axis=1) |
|
elif mode == 'sdf': |
|
labels = data_dict[f'smpl_feat'][:, [0]] |
|
labels -= labels.min() |
|
labels /= labels.max() |
|
colors = np.concatenate([labels, labels, labels], axis=1) |
|
elif mode == 'normal': |
|
labels = data_dict[f'smpl_feat'][:, -4:-1] |
|
colors = (labels + 1.0) * 0.5 |
|
elif mode == 'cmap': |
|
labels = data_dict[f'smpl_feat'][:, -7:-4] |
|
colors = np.array(labels) |
|
|
|
points = projection(data_dict['samples_geo'], data_dict['calib']) |
|
verts = projection(data_dict['verts'], data_dict['calib']) |
|
points[:, 1] *= -1 |
|
|
|
verts[:, 1] *= -1 |
|
|
|
|
|
mesh = trimesh.Trimesh(verts, data_dict['faces'], process=True) |
|
mesh.visual.vertex_colors = [128.0, 128.0, 128.0, 255.0] |
|
vis_list.append(mesh) |
|
|
|
if 'voxel_verts' in data_dict.keys(): |
|
print(colored("voxel verts", "green")) |
|
voxel_verts = data_dict['voxel_verts'] * 2.0 |
|
voxel_faces = data_dict['voxel_faces'] |
|
voxel_verts[:, 1] *= -1 |
|
voxel = trimesh.Trimesh(voxel_verts, |
|
voxel_faces[:, [0, 2, 1]], |
|
process=False, |
|
maintain_order=True) |
|
voxel.visual.vertex_colors = [0.0, 128.0, 0.0, 255.0] |
|
vis_list.append(voxel) |
|
|
|
if 'smpl_verts' in data_dict.keys(): |
|
print(colored("smpl verts", "green")) |
|
smplx_verts = data_dict['smpl_verts'] |
|
smplx_faces = data_dict['smpl_faces'] |
|
smplx_verts[:, 1] *= -1 |
|
smplx = trimesh.Trimesh(smplx_verts, |
|
smplx_faces[:, [0, 2, 1]], |
|
process=False, |
|
maintain_order=True) |
|
smplx.visual.vertex_colors = [128.0, 128.0, 0.0, 255.0] |
|
vis_list.append(smplx) |
|
|
|
|
|
img_pos = [1.0, 0.0, -1.0,-1.0,1.0] |
|
for img_id, img_key in enumerate(['normal_F', 'image', 'T_normal_B','T_normal_L','T_normal_R']): |
|
image_arr = (data_dict[img_key].detach().cpu().permute(1, 2, 0).numpy() + |
|
1.0) * 0.5 * 255.0 |
|
image_dim = image_arr.shape[0] |
|
|
|
if img_id==3: |
|
image=vedo.Picture(image_arr).scale(2.0 / image_dim).pos(-1.0, -1.0, -1.0).rotateY(90) |
|
elif img_id==4: |
|
image=vedo.Picture(image_arr).scale(2.0 / image_dim).pos(-1.0, -1.0, 1.0).rotateY(90) |
|
else: |
|
image = vedo.Picture(image_arr).scale(2.0 / image_dim).pos(-1.0, -1.0, img_pos[img_id]) |
|
vis_list.append(image) |
|
|
|
|
|
pc = vedo.Points(points, r=1) |
|
vis_list.append(pc) |
|
|
|
vp.show(*vis_list, bg="white", axes=1.0, interactive=True) |
|
|