Spaces:
Runtime error
Runtime error
| import smplx | |
| import torch | |
| import pickle | |
| import numpy as np | |
| import os | |
| import trimesh | |
| import cv2 | |
| os.environ['PYOPENGL_PLATFORM'] = 'egl' | |
| import pyrender | |
| root_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../..')) | |
| def get_smplx_model(bs, deivce): | |
| smpl_model = smplx.create(os.path.join(root_dir, 'deps/smplx/models'), | |
| model_type='smplx', | |
| gender='male', | |
| ext='npz', | |
| batch_size=bs, | |
| ).to(device) | |
| return smpl_model.eval() | |
| def render_motion_to_video(motion, device, output_path, title, step=2): | |
| length = motion['transl'].shape[0] | |
| model = get_smplx_model(length, device) | |
| vertices = model( | |
| body_pose = torch.tensor(motion['body_pose'], dtype=torch.float32).to(device), | |
| transl = torch.tensor(motion['transl'], dtype=torch.float32).to(device), | |
| global_orient = torch.tensor(motion['global_orient'], dtype=torch.float32).to(device) | |
| ).vertices.detach().cpu().numpy() | |
| faces = model.faces | |
| temp_dir = "temp_render_images" | |
| os.makedirs(temp_dir, exist_ok=True) | |
| width, height = 480, 320 | |
| images = [] | |
| for i in range(0, length, step): | |
| trimesh_mesh = trimesh.Trimesh(vertices=vertices[i], faces=faces) | |
| mesh = pyrender.Mesh.from_trimesh(trimesh_mesh) | |
| scene = pyrender.Scene(ambient_light=[0.5, 0.5, 0.5]) | |
| scene.add(mesh) | |
| camera = pyrender.PerspectiveCamera(yfov=np.pi / 3.0) | |
| angle = -np.pi / 8 | |
| camera_pose = np.array([ | |
| [1, 0, 0, 0], | |
| [0, np.cos(angle), -np.sin(angle), 2.0], | |
| [0, np.sin(angle), np.cos(angle), 4.0], | |
| [0, 0, 0, 1] | |
| ]) | |
| scene.add(camera, pose=camera_pose) | |
| light = pyrender.DirectionalLight(color=[1.0, 1.0, 1.0], intensity=2.0) | |
| scene.add(light, pose=camera_pose) | |
| r = pyrender.OffscreenRenderer(width, height) | |
| color, _ = r.render(scene) | |
| r.delete() | |
| image = cv2.cvtColor(color, cv2.COLOR_RGB2BGR) | |
| img_path = os.path.join(temp_dir, f"frame_{i:04d}.png") | |
| cv2.imwrite(img_path, image) | |
| images.append(image) | |
| if images: | |
| height, width, _ = images[0].shape | |
| sampled_fps = int(20 / step) | |
| temp_video_path = output_path.replace('.mp4', '_temp.mp4') | |
| fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
| video = cv2.VideoWriter(temp_video_path, fourcc, sampled_fps, (width, height)) | |
| for image in images: | |
| video.write(image) | |
| video.release() | |
| try: | |
| import subprocess | |
| cmd = [ | |
| 'ffmpeg', | |
| '-y', | |
| '-i', temp_video_path, | |
| '-filter:v', f'minterpolate=fps={24}:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1', | |
| '-c:v', 'libx264', | |
| '-preset', 'medium', | |
| '-crf', '18', | |
| output_path | |
| ] | |
| subprocess.run(cmd, check=True) | |
| print(f"帧插值完成,最终视频保存至: {output_path}") | |
| os.remove(temp_video_path) | |
| except Exception as e: | |
| print(f"帧插值失败: {e}") | |
| os.rename(temp_video_path, output_path) | |
| print(f"使用原始视频: {output_path}") | |
| else: | |
| print("没有图像可用于创建视频") | |
| for file in os.listdir(temp_dir): | |
| os.remove(os.path.join(temp_dir, file)) | |
| os.rmdir(temp_dir) | |
| from argparse import ArgumentParser | |
| import time | |
| if __name__ == "__main__": | |
| parser = ArgumentParser() | |
| print('******Start rendering...******') | |
| start_time = time.time() | |
| parser.add_argument("--motion_path", type=str, required=True) | |
| parser.add_argument("--title", type=str, default="rendered_motion.mp4") | |
| args = parser.parse_args() | |
| with open(args.motion_path, 'rb') as f: | |
| motion = pickle.load(f) | |
| output_path = args.motion_path.replace(".pkl", ".mp4") | |
| device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
| print(args.title) | |
| render_motion_to_video(motion, device, output_path, args.title) | |
| print(f"******Rendering finished in {time.time() - start_time:.2f} seconds.******") | |