4
0
mirror of https://github.com/nerfstudio-project/nerfstudio.git synced 2026-11-11 02:24:38 +08:00
nerfstudio/scripts/render.py
Ethan Weber 2150bad0e4
Reducing flicker artifacts for nerfacto method (#750)
* pose opt default nerfacto.

* added SO3 cam pose optimization which is slightly faster (~2.2m/iter) than BARF

* added occupancy grid with placeholder until nerfacc is updated to query density from it

* added occupancy grid sampling as the level 0 in proposal hierarchy, relies on nerfacc 0.1.7 (on pypi)

* merge main

* merge main

* minor changes to sampling

* adjusted sample number

* refactor occ grid stuff, settle on decent params

* nograd proposal sampling

* param tweaks

* varying resolution proposal networks

* params

* merged main

* optimizer update

* remove occ grid

* remove double nerfacto samples

* set single jitter to true

* remove pdb

* more changes

* fix method defaults

* fix pylint

* remove occupancy fn

Co-authored-by: akristoffersen <akristoffersen@berkeley.edu>
Co-authored-by: Justin Kerr <justin.g.kerr@gmail.com>
2022-10-11 14:21:00 -07:00

162 lines
5.8 KiB
Python

#!/usr/bin/env python
"""
render.py
"""
from __future__ import annotations
import dataclasses
import json
import logging
import sys
from pathlib import Path
from typing import Literal, Optional
import mediapy as media
import torch
import tyro
from rich.console import Console
from rich.progress import (
BarColumn,
Progress,
TaskProgressColumn,
TextColumn,
TimeRemainingColumn,
)
from typing_extensions import assert_never
from nerfstudio.cameras.camera_paths import get_path_from_json, get_spiral_path
from nerfstudio.cameras.cameras import Cameras
from nerfstudio.configs.base_config import Config # pylint: disable=unused-import
from nerfstudio.pipelines.base_pipeline import Pipeline
from nerfstudio.utils import install_checks
from nerfstudio.utils.eval_utils import eval_setup
from nerfstudio.utils.rich_utils import ItersPerSecColumn
console = Console(width=120)
logging.basicConfig(format="[%(filename)s:%(lineno)d] %(message)s", level=logging.INFO)
def _render_trajectory_video(
pipeline: Pipeline,
cameras: Cameras,
output_filename: Path,
rendered_output_name: str,
rendered_resolution_scaling_factor: float = 1.0,
seconds: float = 5.0,
) -> None:
"""Helper function to create a video of the spiral trajectory.
Args:
pipeline: Pipeline to evaluate with.
cameras: Cameras to render.
output_filename: Name of the output file.
rendered_output_name: Name of the renderer output to use.
rendered_resolution_scaling_factor: Scaling factor to apply to the camera image resolution.
seconds: Number for the output video.
"""
console.print("[bold green]Creating trajectory video")
images = []
cameras.rescale_output_resolution(rendered_resolution_scaling_factor)
progress = Progress(
TextColumn(":movie_camera: Rendering :movie_camera:"),
BarColumn(),
TaskProgressColumn(show_speed=True),
ItersPerSecColumn(suffix="fps"),
TimeRemainingColumn(elapsed_when_finished=True, compact=True),
)
with progress:
for camera_idx in progress.track(range(cameras.size), description=""):
camera_ray_bundle = cameras.generate_rays(camera_indices=camera_idx).to(pipeline.device)
with torch.no_grad():
outputs = pipeline.model.get_outputs_for_camera_ray_bundle(camera_ray_bundle)
if rendered_output_name not in outputs:
console.rule("Error", style="red")
console.print(f"Could not find {rendered_output_name} in the model outputs", justify="center")
console.print(f"Please set --rendered_output_name to one of: {outputs.keys()}", justify="center")
sys.exit(1)
image = outputs[rendered_output_name].cpu().numpy()
images.append(image)
fps = len(images) / seconds
# make the folder if it doesn't exist
output_filename.parent.mkdir(parents=True, exist_ok=True)
with console.status("[yellow]Saving video", spinner="bouncingBall"):
media.write_video(output_filename, images, fps=fps)
console.rule("[green] :tada: :tada: :tada: Success :tada: :tada: :tada:")
console.print(f"[green]Saved video to {output_filename}", justify="center")
@dataclasses.dataclass
class RenderTrajectory:
"""Load a checkpoint, render a trajectory, and save to a video file."""
# Path to config YAML file.
load_config: Path
# Name of the renderer output to use. rgb, depth, etc.
rendered_output_name: str = "rgb"
# Trajectory to render.
traj: Literal["spiral", "interp", "filename"] = "spiral"
# Scaling factor to apply to the camera image resolution.
downscale_factor: int = 1
# Filename of the camera path to render.
camera_path_filename: Path = Path("camera_path.json")
# Name of the output file.
output_path: Path = Path("renders/output.mp4")
# How long the video should be.
seconds: float = 5.0
# Specifies number of rays per chunk during eval.
eval_num_rays_per_chunk: Optional[int] = None
def main(self) -> None:
"""Main function."""
_, pipeline, _ = eval_setup(
self.load_config,
eval_num_rays_per_chunk=self.eval_num_rays_per_chunk,
)
install_checks.check_ffmpeg_installed()
seconds = self.seconds
# TODO(ethan): use camera information from parsing args
if self.traj == "spiral":
camera_start = pipeline.datamanager.eval_dataloader.get_camera(image_idx=0)
# TODO(ethan): pass in the up direction of the camera
camera_path = get_spiral_path(camera_start, steps=30, radius=0.1)
elif self.traj == "interp":
# cameras_a = pipeline.datamanager.eval_dataloader.get_camera(image_idx=0)
# cameras_b = pipeline.datamanager.eval_dataloader.get_camera(image_idx=10)
# camera_path = get_interpolated_camera_path(cameras, steps=30)
raise NotImplementedError("Interpolated camera path not implemented.")
elif self.traj == "filename":
with open(self.camera_path_filename, "r", encoding="utf-8") as f:
camera_path = json.load(f)
seconds = camera_path["seconds"]
camera_path = get_path_from_json(camera_path)
else:
assert_never(self.traj)
_render_trajectory_video(
pipeline,
camera_path,
output_filename=self.output_path,
rendered_output_name=self.rendered_output_name,
rendered_resolution_scaling_factor=1.0 / self.downscale_factor,
seconds=seconds,
)
def entrypoint():
"""Entrypoint for use with pyproject scripts."""
tyro.extras.set_accent_color("bright_yellow")
tyro.cli(RenderTrajectory).main()
if __name__ == "__main__":
entrypoint()
# For sphinx docs
get_parser_fn = lambda: tyro.extras.get_parser(RenderTrajectory) # noqa