vendored model
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""Contains `sharp render` CLI implementation.
|
||||
|
||||
For licensing see accompanying LICENSE file.
|
||||
Copyright (C) 2025 Apple Inc. All Rights Reserved.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
import torch
|
||||
import torch.utils.data
|
||||
|
||||
from sharp.utils import camera, gsplat, io
|
||||
from sharp.utils import logging as logging_utils
|
||||
from sharp.utils.gaussians import Gaussians3D, SceneMetaData, load_ply
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"-i",
|
||||
"--input-path",
|
||||
type=click.Path(exists=True, path_type=Path),
|
||||
help="Path to the ply or a list of plys.",
|
||||
required=True,
|
||||
)
|
||||
@click.option(
|
||||
"-o",
|
||||
"--output-path",
|
||||
type=click.Path(path_type=Path, file_okay=False),
|
||||
help="Path to save the rendered videos.",
|
||||
required=True,
|
||||
)
|
||||
@click.option("-v", "--verbose", is_flag=True, help="Activate debug logs.")
|
||||
def render_cli(input_path: Path, output_path: Path, verbose: bool):
|
||||
"""Predict Gaussians from input images."""
|
||||
logging_utils.configure(logging.DEBUG if verbose else logging.INFO)
|
||||
|
||||
if not torch.cuda.is_available():
|
||||
LOGGER.error("Rendering a checkpoint requires CUDA.")
|
||||
exit(1)
|
||||
|
||||
output_path.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
params = camera.TrajectoryParams()
|
||||
|
||||
if input_path.suffix == ".ply":
|
||||
scene_paths = [input_path]
|
||||
elif input_path.is_dir():
|
||||
scene_paths = list(input_path.glob("*.ply"))
|
||||
else:
|
||||
LOGGER.error("Input path must be either directory or single PLY file.")
|
||||
exit(1)
|
||||
|
||||
for scene_path in scene_paths:
|
||||
LOGGER.info("Rendering %s", scene_path)
|
||||
gaussians, metadata = load_ply(scene_path)
|
||||
render_gaussians(
|
||||
gaussians=gaussians,
|
||||
metadata=metadata,
|
||||
params=params,
|
||||
output_path=(output_path / scene_path.stem).with_suffix(".mp4"),
|
||||
)
|
||||
|
||||
|
||||
def render_gaussians(
|
||||
gaussians: Gaussians3D,
|
||||
metadata: SceneMetaData,
|
||||
output_path: Path,
|
||||
params: camera.TrajectoryParams | None = None,
|
||||
) -> None:
|
||||
"""Render a single gaussian checkpoint file."""
|
||||
(width, height) = metadata.resolution_px
|
||||
f_px = metadata.focal_length_px
|
||||
|
||||
if params is None:
|
||||
params = camera.TrajectoryParams()
|
||||
|
||||
if not torch.cuda.is_available():
|
||||
raise RuntimeError("Rendering a checkpoint requires CUDA.")
|
||||
|
||||
device = torch.device("cuda")
|
||||
|
||||
intrinsics = torch.tensor(
|
||||
[
|
||||
[f_px, 0, (width - 1) / 2.0, 0],
|
||||
[0, f_px, (height - 1) / 2.0, 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1],
|
||||
],
|
||||
device=device,
|
||||
dtype=torch.float32,
|
||||
)
|
||||
camera_model = camera.create_camera_model(
|
||||
gaussians, intrinsics, resolution_px=metadata.resolution_px
|
||||
)
|
||||
|
||||
trajectory = camera.create_eye_trajectory(
|
||||
gaussians, params, resolution_px=metadata.resolution_px, f_px=f_px
|
||||
)
|
||||
renderer = gsplat.GSplatRenderer(color_space=metadata.color_space)
|
||||
video_writer = io.VideoWriter(output_path)
|
||||
|
||||
for _, eye_position in enumerate(trajectory):
|
||||
camera_info = camera_model.compute(eye_position)
|
||||
rendering_output = renderer(
|
||||
gaussians.to(device),
|
||||
extrinsics=camera_info.extrinsics[None].to(device),
|
||||
intrinsics=camera_info.intrinsics[None].to(device),
|
||||
image_width=camera_info.width,
|
||||
image_height=camera_info.height,
|
||||
)
|
||||
color = (rendering_output.color[0].permute(1, 2, 0) * 255.0).to(dtype=torch.uint8)
|
||||
depth = rendering_output.depth[0]
|
||||
video_writer.add_frame(color, depth)
|
||||
video_writer.close()
|
||||
Reference in New Issue
Block a user