| | import math |
| | import numpy as np |
| | from plyfile import PlyData, PlyElement |
| | import math |
| | import os |
| | import warp as wp |
| |
|
| |
|
| | def load_ply(filepath): |
| | """ |
| | Load a Gaussian splat PLY file. |
| | |
| | Returns dict with: positions, scales, rotations, opacities, shs |
| | """ |
| | plydata = PlyData.read(filepath) |
| | vertex = plydata['vertex'] |
| | |
| | num_points = len(vertex) |
| | |
| | |
| | positions = np.stack([ |
| | vertex['x'], vertex['y'], vertex['z'] |
| | ], axis=-1).astype(np.float32) |
| | |
| | |
| | scales = np.stack([ |
| | np.exp(vertex['scale_0']), |
| | np.exp(vertex['scale_1']), |
| | np.exp(vertex['scale_2']) |
| | ], axis=-1).astype(np.float32) |
| | |
| | |
| | opacities = vertex['opacity'].astype(np.float32).reshape(-1, 1) |
| | |
| | |
| | rotations = np.stack([ |
| | vertex['rot_0'], vertex['rot_1'], vertex['rot_2'], vertex['rot_3'] |
| | ], axis=-1).astype(np.float32) |
| | |
| | |
| | |
| | sh_dc = np.stack([ |
| | vertex['f_dc_0'], vertex['f_dc_1'], vertex['f_dc_2'] |
| | ], axis=-1).astype(np.float32) |
| | |
| | |
| | sh_rest = [] |
| | for i in range(45): |
| | sh_rest.append(vertex[f'f_rest_{i}']) |
| | sh_rest = np.stack(sh_rest, axis=-1).astype(np.float32) |
| | sh_rest = sh_rest.reshape(num_points, 15, 3) |
| | |
| | |
| | shs = np.zeros((num_points * 16, 3), dtype=np.float32) |
| | for i in range(num_points): |
| | shs[i * 16] = sh_dc[i] |
| | for j in range(15): |
| | shs[i * 16 + j + 1] = sh_rest[i, j] |
| | |
| | return { |
| | 'positions': positions, |
| | 'scales': scales, |
| | 'rotations': rotations, |
| | 'opacities': opacities, |
| | 'shs': shs, |
| | 'num_points': num_points |
| | } |
| |
|
| |
|
| | |
| | def save_ply(params, filepath, num_points, colors=None): |
| | |
| | positions = params['positions'].numpy() |
| | scales = params['scales'].numpy() |
| | rotations = params['rotations'].numpy() |
| | opacities = params['opacities'].numpy() |
| | shs = params['shs'].numpy() |
| | |
| | |
| | if colors is not None: |
| | |
| | if hasattr(colors, 'numpy'): |
| | colors_np = colors.numpy() |
| | else: |
| | colors_np = colors |
| | else: |
| | |
| | |
| | colors_np = np.zeros((num_points, 3), dtype=np.float32) |
| | for i in range(num_points): |
| | |
| | sh_dc = shs[i * 16] |
| | |
| | colors_np[i] = np.clip(sh_dc + 0.5, 0.0, 1.0) |
| | |
| | |
| | vertex_data = [] |
| | for i in range(num_points): |
| | |
| | vertex = ( |
| | positions[i][0], positions[i][1], positions[i][2], |
| | np.log(scales[i][0]), np.log(scales[i][1]), np.log(scales[i][2]), |
| | (opacities[i]) |
| | ) |
| | |
| | |
| | quat = rotations[i] |
| | rot_elements = (quat[0], quat[1], quat[2], quat[3]) |
| | vertex += rot_elements |
| | |
| | |
| | color_255 = ( |
| | int(np.clip(colors_np[i][0] * 255, 0, 255)), |
| | int(np.clip(colors_np[i][1] * 255, 0, 255)), |
| | int(np.clip(colors_np[i][2] * 255, 0, 255)) |
| | ) |
| | vertex += color_255 |
| | |
| | |
| | sh_dc = tuple(shs[i * 16][j] for j in range(3)) |
| | vertex += sh_dc |
| | |
| | |
| | sh_rest = [] |
| | for j in range(1, 16): |
| | for c in range(3): |
| | sh_rest.append(shs[i * 16 + j][c]) |
| | vertex += tuple(sh_rest) |
| | |
| | vertex_data.append(vertex) |
| | |
| | |
| | vertex_type = [ |
| | ('x', 'f4'), ('y', 'f4'), ('z', 'f4'), |
| | ('scale_0', 'f4'), ('scale_1', 'f4'), ('scale_2', 'f4'), |
| | ('opacity', 'f4') |
| | ] |
| | |
| | |
| | vertex_type.extend([('rot_0', 'f4'), ('rot_1', 'f4'), ('rot_2', 'f4'), ('rot_3', 'f4')]) |
| | |
| | |
| | vertex_type.extend([('red', 'u1'), ('green', 'u1'), ('blue', 'u1')]) |
| | |
| | |
| | vertex_type.extend([('f_dc_0', 'f4'), ('f_dc_1', 'f4'), ('f_dc_2', 'f4')]) |
| | |
| | |
| | for i in range(45): |
| | vertex_type.append((f'f_rest_{i}', 'f4')) |
| | |
| | vertex_array = np.array(vertex_data, dtype=vertex_type) |
| | el = PlyElement.describe(vertex_array, 'vertex') |
| | |
| | |
| | os.makedirs(os.path.dirname(filepath), exist_ok=True) |
| | |
| | |
| | PlyData([el], text=False).write(filepath) |
| | print(f"Point cloud saved to {filepath}") |
| |
|