Download scripts/visualize_mesh.py from vegagoto123/Live3DPortrait: direct link, hf CLI and curl.
- Browser
- Download file 6.65 kB
-
https://huggingface.co/vegagoto123/Live3DPortrait/resolve/main/scripts/visualize_mesh.py
- Command line
-
hf download hf://vegagoto123/Live3DPortrait/scripts/visualize_mesh.py
-
curl -L -o visualize_mesh.py https://huggingface.co/vegagoto123/Live3DPortrait/resolve/main/scripts/visualize_mesh.py
6.65 kB
| import os | |
| import math | |
| import trimesh | |
| import numpy as np | |
| os.environ["PYOPENGL_PLATFORM"] = "egl" | |
| import pyrender # requires Python 3.8 | |
| from matplotlib import pyplot as plt | |
| # from load_blender import pose_spherical | |
| ''' | |
| This code is used to visualize the mesh of the 3D model. | |
| ''' | |
| # 使用pyrender进行可视化ply文件 | |
| # | |
| # import trimesh | |
| # import pyrender | |
| # import numpy as np | |
| # | |
| # mesh = trimesh.load('output/mesh_1.ply') | |
| # scene = pyrender.Scene() | |
| # scene.add(pyrender.Mesh.from_trimesh(mesh)) | |
| # pyrender.Viewer(scene, use_raymond_lighting=True) | |
| def normalize_vecs(vectors): | |
| return vectors / (np.linalg.norm(vectors, axis=-1, keepdims=True) + 1e-5) | |
| def create_cam2world_matrix(forward_vector, origin): | |
| """ | |
| Takes in the direction the camera is pointing and the camera origin and returns a cam2world matrix. | |
| Works on batches of forward_vectors, origins. Assumes y-axis is up and that there is no camera roll. | |
| """ | |
| forward_vector = normalize_vecs(forward_vector) | |
| print(forward_vector.shape) | |
| # up_vector = np.array([0.0, 1.0, 0.0]).expand_as(forward_vector) | |
| up_vector = np.array([0.0, 1.0, 0.0]) | |
| right_vector = -normalize_vecs(np.cross(up_vector, forward_vector, axis=-1)) | |
| up_vector = normalize_vecs(np.cross(forward_vector, right_vector, axis=-1)) | |
| rotation_matrix = np.eye(4) | |
| rotation_matrix[:3, :3] = np.stack((right_vector, up_vector, forward_vector), axis=-1) | |
| translation_matrix = np.eye(4) | |
| translation_matrix[:3, 3] = origin | |
| cam2world = (translation_matrix @ rotation_matrix)[:, :] | |
| assert(cam2world.shape == (4, 4)) | |
| return cam2world | |
| def sample(horizontal_mean, vertical_mean, lookat_position, horizontal_stddev=0, vertical_stddev=0, radius=1, batch_size=1, device='cpu'): | |
| h = horizontal_mean | |
| v = vertical_mean | |
| v = np.clip(v, 1e-5, math.pi - 1e-5) | |
| theta = h | |
| v = v / math.pi | |
| phi = np.arccos(1 - 2*v) | |
| camera_origins = np.zeros((batch_size, 3)) | |
| camera_origins[:, 0:1] = radius*np.sin(phi) * np.cos(math.pi-theta) | |
| camera_origins[:, 2:3] = radius*np.sin(phi) * np.sin(math.pi-theta) | |
| camera_origins[:, 1:2] = radius*np.cos(phi) | |
| # forward_vectors = math_utils.normalize_vecs(-camera_origins) | |
| forward_vectors = normalize_vecs(lookat_position - camera_origins) | |
| return create_cam2world_matrix(forward_vectors, camera_origins) | |
| trans_t = lambda t : np.array([ | |
| [1,0,0,0], | |
| [0,1,0,0], | |
| [0,0,1,t], | |
| [0,0,0,1], | |
| ], dtype=np.float32) | |
| rot_phi = lambda phi : np.array([ | |
| [1,0,0,0], | |
| [0,np.cos(phi),-np.sin(phi),0], | |
| [0,np.sin(phi), np.cos(phi),0], | |
| [0,0,0,1], | |
| ], dtype=np.float32) | |
| rot_theta = lambda th : np.array([ | |
| [np.cos(th),0,-np.sin(th),0], | |
| [0,1,0,0], | |
| [np.sin(th),0, np.cos(th),0], | |
| [0,0,0,1], | |
| ], dtype=np.float32) | |
| def pose_spherical(theta, phi, radius): | |
| c2w = trans_t(radius) | |
| c2w = rot_phi(phi/180.*np.pi) @ c2w | |
| c2w = rot_theta(theta/180.*np.pi) @ c2w | |
| # c2w = np.array([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) @ c2w | |
| c2w = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]) @ c2w | |
| return c2w | |
| # camera_params = np.concatenate([cam2world_pose.reshape(-1, 16), intrinsics], 1) | |
| def plot_3d(mesh): | |
| scene = pyrender.Scene() | |
| # set background color | |
| # scene.bg_color = [0.0, 0.0, 0.0, 0.0] | |
| # scene.add(pyrender.Mesh.from_trimesh(mesh)) | |
| scene.add(pyrender.Mesh.from_trimesh(mesh, smooth=True)) | |
| # Set up the camera -- z-axis away from the scene, x-axis right, y-axis up | |
| # camera = pyrender.PerspectiveCamera(yfov=18.834 * np.pi / 180.0, aspectRatio=1.0) | |
| camera = pyrender.PerspectiveCamera(yfov=1.5 * 18.834 * np.pi / 180.0, aspectRatio=1, znear=0.1) | |
| # camera = pyrender.OrthographicCamera(xmag=1, ymag=1) | |
| # camera = pyrender.PerspectiveCamera(yfov=np.pi / 3.0, aspectRatio=1.414) | |
| # mesh = pyrender.Mesh.from_trimesh(mesh) | |
| # light = pyrender.SpotLight(color=np.ones(3), intensity=3.0, | |
| # innerConeAngle=np.pi/4) | |
| # r = pyrender.OffscreenRenderer(512, 512) | |
| # camera = pyrender.OrthographicCamera(xmag=0.6, ymag=0.6) | |
| camera_pose = pose_spherical(90., 0., 2.7) | |
| # cam_pivot = [0, 0, 0] | |
| # cam_radius = 2.7 | |
| # cam2world_pose = sample(0, np.pi/2, cam_pivot, radius=cam_radius) | |
| # camera_pose = cam2world_pose | |
| # # camera_pose[:, 0] = -camera_pose[:, 0] | |
| # # camera_pose[0, 0] = -camera_pose[0, 0] | |
| # camera_pose[:, 2] = -camera_pose[:, 2] | |
| # camera_pose[:, 1] = -camera_pose[:, 1] | |
| # # camera_pose[2, :] = -camera_pose[2, :] | |
| # # camera_pose[1, :] = -camera_pose[1, :] | |
| # print(camera_pose) | |
| # # camera_pose[:3, 3] = 512 * camera_pose[:3, 3] | |
| nc = pyrender.Node(camera=camera, matrix=camera_pose) | |
| scene.add_node(nc) | |
| scene.add(camera, pose=camera_pose) | |
| # Set up the light -- a point light in the same spot as the camera | |
| # use double sided lighting | |
| light = pyrender.SpotLight(color=np.ones(3), intensity=3.0, innerConeAngle=np.pi/4.0) | |
| # light = pyrender.PointLight(color=np.ones(3), intensity=4.0) | |
| nl = pyrender.Node(light=light, matrix=camera_pose) | |
| scene.add_node(nl) | |
| # scene.add(light, pose=camera_pose) | |
| # Render the scene | |
| r = pyrender.OffscreenRenderer(512, 512) | |
| color, depth = r.render(scene) | |
| # save the image | |
| # print(color.min()) | |
| # print(depth.min(), depth.max()) | |
| # color = ((color - color.min())/ (color.max() - color.min()) * 255.0).astype(np.uint8) | |
| # depth = (depth - depth.min())/ (depth.max() - depth.min()) * 255.0 | |
| plt.imsave("output/mesh_1.png", color) | |
| plt.imsave("output/mesh_1_depth.png", (depth).astype(np.uint8)) | |
| if __name__ == '__main__': | |
| # mesh_path = "/raid/xjd/workspace/eg3d/eg3d/out/seed0000.ply" | |
| mesh_path = "/raid/xjd/workspace/opensource/Live3DPortrait/output/mesh_1.ply" | |
| # mesh_path = "/raid/xjd/workspace/other/Deep3DFaceRecon_pytorch/checkpoints/face_recon/results/epoch_20_000000/000028.obj" | |
| mesh = trimesh.load(mesh_path) | |
| # b_min_np = np.array([-bound, -bound, -bound]) | |
| # b_max_np = np.array([ bound, bound, bound]) | |
| # vertices = vertices / (resolution - 1.0) * (b_max_np - b_min_np)[None, :] + b_min_np[None, :] | |
| # return vertices.astype('float32'), faces | |
| # mesh.vertices = mesh.vertices.astype('float64') | |
| # mesh.vertices = 2.0 * (mesh.vertices / 512.0) - 1.0 | |
| # print(mesh.vertices.dtype) | |
| # mesh.vertices = (mesh.vertices - (256.0, 256.0, 256.0))/256.0 | |
| print(mesh.vertices.min()) | |
| print(mesh.vertices.max()) | |
| # mesh.vertices = mesh.vertices / 512.0 | |
| # print(mesh.vertices) | |
| # print(mesh.vertices.shape) | |
| # print(mesh.faces.shape) | |
| plot_3d(mesh) | |