| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import logging |
| import warnings |
|
|
| warnings.filterwarnings("ignore") |
| logging.getLogger("lightning").setLevel(logging.ERROR) |
| logging.getLogger("trimesh").setLevel(logging.ERROR) |
|
|
| import argparse |
| import os |
|
|
| import torch |
| from termcolor import colored |
| from tqdm.auto import tqdm |
|
|
| from apps.IFGeo import IFGeo |
| from apps.Normal import Normal |
| from lib.common.BNI import BNI |
| from lib.common.BNI_utils import save_normal_tensor |
| from lib.common.config import cfg |
| from lib.common.voxelize import VoxelGrid |
| from lib.dataset.EvalDataset import EvalDataset |
| from lib.dataset.Evaluator import Evaluator |
| from lib.dataset.mesh_util import * |
|
|
| torch.backends.cudnn.benchmark = True |
| speed_analysis = False |
|
|
| if __name__ == "__main__": |
|
|
| if speed_analysis: |
| import cProfile |
| import pstats |
| profiler = cProfile.Profile() |
| profiler.enable() |
|
|
| |
| parser = argparse.ArgumentParser() |
|
|
| parser.add_argument("-gpu", "--gpu_device", type=int, default=0) |
| parser.add_argument("-ifnet", action="store_true") |
| parser.add_argument("-cfg", "--config", type=str, default="./configs/econ.yaml") |
|
|
| args = parser.parse_args() |
|
|
| |
| cfg.merge_from_file(args.config) |
| device = torch.device("cuda:0") |
|
|
| cfg_test_list = [ |
| "dataset.rotation_num", |
| 3, |
| "bni.use_smpl", |
| ["hand"], |
| "bni.use_ifnet", |
| args.ifnet, |
| "bni.cut_intersection", |
| True, |
| ] |
|
|
| |
| |
|
|
| |
| cfg_test_list += ["dataset.types", ["cape"], "dataset.scales", [100.0]] |
|
|
| cfg.merge_from_list(cfg_test_list) |
| cfg.freeze() |
|
|
| |
| normal_net = Normal.load_from_checkpoint( |
| cfg=cfg, checkpoint_path=cfg.normal_path, map_location=device, strict=False |
| ) |
| normal_net = normal_net.to(device) |
| normal_net.netG.eval() |
| print( |
| colored( |
| f"Resume Normal Estimator from: {cfg.normal_path}", "green" |
| ) |
| ) |
|
|
| |
| SMPLX_object = SMPLX() |
|
|
| dataset = EvalDataset(cfg=cfg, device=device) |
| evaluator = Evaluator(device=device) |
| export_dir = osp.join(cfg.results_path, cfg.name, "IF-Net+" if cfg.bni.use_ifnet else "SMPL-X") |
| print(colored(f"Dataset Size: {len(dataset)}", "green")) |
|
|
| if cfg.bni.use_ifnet: |
| |
| ifnet = IFGeo.load_from_checkpoint( |
| cfg=cfg, checkpoint_path=cfg.ifnet_path, map_location=device, strict=False |
| ) |
| ifnet = ifnet.to(device) |
| ifnet.netG.eval() |
|
|
| print(colored(f"Resume IF-Net+ from {Format.start} {cfg.ifnet_path} {Format.end}", "green")) |
| print(colored(f"Complete with {Format.start} IF-Nets+ (Implicit) {Format.end}", "green")) |
| else: |
| print(colored(f"Complete with {Format.start} SMPL-X (Explicit) {Format.end}", "green")) |
|
|
| pbar = tqdm(dataset) |
| benchmark = {} |
|
|
| for data in pbar: |
|
|
| for key in data.keys(): |
| if torch.is_tensor(data[key]): |
| data[key] = data[key].unsqueeze(0).to(device) |
|
|
| is_smplx = True if 'smplx_path' in data.keys() else False |
|
|
| |
| current_name = f"{data['dataset']}-{data['subject']}-{data['rotation']:03d}" |
| current_dir = osp.join(export_dir, data['dataset'], data['subject']) |
| os.makedirs(current_dir, exist_ok=True) |
| final_path = osp.join(current_dir, f"{current_name}_final.obj") |
|
|
| if not osp.exists(final_path): |
|
|
| in_tensor = data.copy() |
|
|
| batch_smpl_verts = in_tensor["smpl_verts"].detach() |
| batch_smpl_verts *= torch.tensor([1.0, -1.0, 1.0]).to(device) |
| batch_smpl_faces = in_tensor["smpl_faces"].detach() |
|
|
| in_tensor["depth_F"], in_tensor["depth_B"] = dataset.render_depth( |
| batch_smpl_verts, batch_smpl_faces |
| ) |
|
|
| with torch.no_grad(): |
| in_tensor["normal_F"], in_tensor["normal_B"] = normal_net.netG(in_tensor) |
|
|
| smpl_mesh = trimesh.Trimesh( |
| batch_smpl_verts.cpu().numpy()[0], |
| batch_smpl_faces.cpu().numpy()[0] |
| ) |
|
|
| side_mesh = smpl_mesh.copy() |
| face_mesh = smpl_mesh.copy() |
| hand_mesh = smpl_mesh.copy() |
| smplx_mesh = smpl_mesh.copy() |
|
|
| |
| BNI_dict = save_normal_tensor( |
| in_tensor, |
| 0, |
| osp.join(current_dir, "BNI/param_dict"), |
| cfg.bni.thickness if data['dataset'] == 'renderpeople' else 0.0, |
| ) |
|
|
| |
| BNI_object = BNI( |
| dir_path=osp.join(current_dir, "BNI"), |
| name=current_name, |
| BNI_dict=BNI_dict, |
| cfg=cfg.bni, |
| device=device |
| ) |
|
|
| BNI_object.extract_surface(False) |
|
|
| if is_smplx: |
| side_mesh = apply_face_mask(side_mesh, ~SMPLX_object.smplx_eyeball_fid_mask) |
|
|
| if cfg.bni.use_ifnet: |
|
|
| |
| in_tensor.update( |
| dataset.depth_to_voxel({ |
| "depth_F": BNI_object.F_depth.unsqueeze(0).to(device), "depth_B": |
| BNI_object.B_depth.unsqueeze(0).to(device) |
| }) |
| ) |
|
|
| occupancies = VoxelGrid.from_mesh(side_mesh, cfg.vol_res, loc=[ |
| 0, |
| ] * 3, scale=2.0).data.transpose(2, 1, 0) |
| occupancies = np.flip(occupancies, axis=1) |
|
|
| in_tensor["body_voxels"] = torch.tensor(occupancies.copy() |
| ).float().unsqueeze(0).to(device) |
|
|
| with torch.no_grad(): |
| sdf = ifnet.reconEngine(netG=ifnet.netG, batch=in_tensor) |
| verts_IF, faces_IF = ifnet.reconEngine.export_mesh(sdf) |
|
|
| if ifnet.clean_mesh_flag: |
| verts_IF, faces_IF = clean_mesh(verts_IF, faces_IF) |
|
|
| side_mesh_path = osp.join(current_dir, f"{current_name}_IF.obj") |
| side_mesh = remesh_laplacian(trimesh.Trimesh(verts_IF, faces_IF), side_mesh_path) |
|
|
| full_lst = [] |
|
|
| if "hand" in cfg.bni.use_smpl: |
|
|
| |
| if is_smplx: |
| hand_mesh = apply_vertex_mask(hand_mesh, SMPLX_object.smplx_mano_vertex_mask) |
| else: |
| hand_mesh = apply_vertex_mask(hand_mesh, SMPLX_object.smpl_mano_vertex_mask) |
|
|
| |
| BNI_object.F_B_trimesh = part_removal( |
| BNI_object.F_B_trimesh, |
| hand_mesh, |
| cfg.bni.hand_thres, |
| device, |
| smplx_mesh, |
| region="hand" |
| ) |
| side_mesh = part_removal( |
| side_mesh, hand_mesh, cfg.bni.hand_thres, device, smplx_mesh, region="hand" |
| ) |
| |
| full_lst += [hand_mesh] |
|
|
| full_lst += [BNI_object.F_B_trimesh] |
|
|
| |
| side_mesh = part_removal( |
| side_mesh, sum(full_lst), 2e-2, device, smplx_mesh, region="", clean=False |
| ) |
|
|
| full_lst += [side_mesh] |
|
|
| if cfg.bni.use_poisson: |
| final_mesh = poisson( |
| sum(full_lst), |
| final_path, |
| cfg.bni.poisson_depth, |
| ) |
| else: |
| final_mesh = sum(full_lst) |
| final_mesh.export(final_path) |
| else: |
| final_mesh = trimesh.load(final_path) |
|
|
| |
| metric_path = osp.join(export_dir, "metric.npy") |
|
|
| if osp.exists(metric_path): |
| benchmark = np.load(metric_path, allow_pickle=True).item() |
|
|
| if benchmark == {} or data["dataset"] not in benchmark.keys( |
| ) or f"{data['subject']}-{data['rotation']}" not in benchmark[data["dataset"]]["subject"]: |
|
|
| result_eval = { |
| "verts_gt": data["verts"][0], |
| "faces_gt": data["faces"][0], |
| "verts_pr": final_mesh.vertices, |
| "faces_pr": final_mesh.faces, |
| "calib": data["calib"][0], |
| } |
|
|
| evaluator.set_mesh(result_eval, scale=False) |
| chamfer, p2s = evaluator.calculate_chamfer_p2s(num_samples=1000) |
| nc = evaluator.calculate_normal_consist(osp.join(current_dir, f"{current_name}_nc.png")) |
|
|
| if data["dataset"] not in benchmark.keys(): |
| benchmark[data["dataset"]] = { |
| "chamfer": [chamfer.item()], |
| "p2s": [p2s.item()], |
| "nc": [nc.item()], |
| "subject": [f"{data['subject']}-{data['rotation']}"], |
| "total": 1, |
| } |
| else: |
| benchmark[data["dataset"]]["chamfer"] += [chamfer.item()] |
| benchmark[data["dataset"]]["p2s"] += [p2s.item()] |
| benchmark[data["dataset"]]["nc"] += [nc.item()] |
| benchmark[data["dataset"]]["subject"] += [f"{data['subject']}-{data['rotation']}"] |
| benchmark[data["dataset"]]["total"] += 1 |
|
|
| np.save(metric_path, benchmark, allow_pickle=True) |
|
|
| else: |
|
|
| subject_idx = benchmark[data["dataset"] |
| ]["subject"].index(f"{data['subject']}-{data['rotation']}") |
| chamfer = torch.tensor(benchmark[data["dataset"]]["chamfer"][subject_idx]) |
| p2s = torch.tensor(benchmark[data["dataset"]]["p2s"][subject_idx]) |
| nc = torch.tensor(benchmark[data["dataset"]]["nc"][subject_idx]) |
|
|
| pbar.set_description( |
| f"{current_name} | {chamfer.item():.3f} | {p2s.item():.3f} | {nc.item():.4f}" |
| ) |
|
|
| for dataset in benchmark.keys(): |
| for metric in ["chamfer", "p2s", "nc"]: |
| print( |
| f"{dataset}-{metric}: {sum(benchmark[dataset][metric])/benchmark[dataset]['total']:.4f}" |
| ) |
|
|
| if cfg.bni.use_ifnet: |
| print(colored("Finish evaluating on ECON_IF", "green")) |
| else: |
| print(colored("Finish evaluating of ECON_EX", "green")) |
|
|
| if speed_analysis: |
| profiler.disable() |
| profiler.dump_stats(osp.join(export_dir, "econ.stats")) |
| stats = pstats.Stats(osp.join(export_dir, "econ.stats")) |
| stats.sort_stats("cumtime").print_stats(10) |
|
|