-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender_dynamic.py
More file actions
152 lines (122 loc) · 5.98 KB
/
Copy pathrender_dynamic.py
File metadata and controls
152 lines (122 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
"""
Dynamic Scaffold-GS Rendering Script
[DESIGN] Canonical Scaffold-GS + Deformable Gaussian Architecture:
- Anchors are STATIC canonical scaffolding (time-invariant)
- View-MLPs are purely view-dependent (no time conditioning)
- Deformation field predicts Gaussian-level temporal offsets: Δx(x_canonical, t)
"""
import os
import torch
import numpy as np
import subprocess
import json
import time
from tqdm import tqdm
import torchvision
# Select GPU with least memory usage
cmd = 'nvidia-smi -q -d Memory |grep -A4 GPU|grep Used'
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE).stdout.decode().split('\n')
os.environ['CUDA_VISIBLE_DEVICES'] = str(np.argmin([int(x.split()[2]) for x in result[:-1]]))
os.system('echo $CUDA_VISIBLE_DEVICES')
from scene import Scene, GaussianModel, DeformModel
from gaussian_renderer import render, prefilter_voxel
from utils.general_utils import safe_state
from argparse import ArgumentParser
from arguments import ModelParams, PipelineParams, get_combined_args
def render_set(model_path, name, iteration, views, gaussians, deform, pipeline, background, is_6dof=False):
"""Render a set of views for dynamic scene"""
render_path = os.path.join(model_path, name, "ours_{}".format(iteration), "renders")
gts_path = os.path.join(model_path, name, "ours_{}".format(iteration), "gt")
os.makedirs(render_path, exist_ok=True)
os.makedirs(gts_path, exist_ok=True)
t_list = []
for idx, view in enumerate(tqdm(views, desc="Rendering progress")):
torch.cuda.synchronize()
t0 = time.time()
# Get frame ID for temporal deformation
fid = view.fid if hasattr(view, 'fid') else torch.tensor([0.0]).cuda()
# Get time index for temporal appearance residual
if hasattr(view, 'frame_idx'):
time_index = view.frame_idx
else:
total_frames = len(views)
time_index = int(fid.item() * (total_frames - 1)) if total_frames > 1 else 0
# Prefilter visible voxels
voxel_visible_mask = prefilter_voxel(view, gaussians, pipeline, background)
# [DESIGN v4] Render with pipeline matching architecture diagram
# Static MLP → Canonical Center, Canonical View-MLP → c_can/α_can
# DeformNet → Δx/Δr/Δs, Appearance Residual MLP → Δc/Δα
render_pkg = render(view, gaussians, pipeline, background,
visible_mask=voxel_visible_mask,
deform_network=deform, time_input=fid,
is_6dof=is_6dof,
time_index=time_index if gaussians.time_appearance_dim > 0 else None)
torch.cuda.synchronize()
t1 = time.time()
t_list.append(t1 - t0)
rendering = render_pkg["render"]
gt = view.original_image[0:3, :, :]
# Save images
img_name = view.image_name if hasattr(view, 'image_name') else '{0:05d}'.format(idx)
torchvision.utils.save_image(rendering, os.path.join(render_path, f'{img_name}.png'))
torchvision.utils.save_image(gt, os.path.join(gts_path, f'{img_name}.png'))
# Report FPS (skip first 5 for warmup)
if len(t_list) > 5:
t = np.array(t_list[5:])
fps = 1.0 / t.mean()
print(f'Test FPS: \033[1;35m{fps:.5f}\033[0m')
def render_sets(dataset: ModelParams, iteration: int, pipeline: PipelineParams,
skip_train: bool, skip_test: bool):
"""Render train and test sets for dynamic scene"""
with torch.no_grad():
# Create Gaussian model (no time embedding - view-MLPs are time-independent)
gaussians = GaussianModel(
dataset.feat_dim,
dataset.n_offsets,
dataset.voxel_size,
dataset.update_depth,
dataset.update_init_factor,
dataset.update_hierachy_factor,
dataset.use_feat_bank,
dataset.appearance_dim,
dataset.ratio,
dataset.add_opacity_dist,
dataset.add_cov_dist,
dataset.add_color_dist,
time_emb_dim=0 # [DESIGN] No time embedding in view-MLPs
)
# Load scene
scene = Scene(dataset, gaussians, load_iteration=iteration, shuffle=False)
gaussians.eval()
# Create and load deformation model
deform = DeformModel(is_blender=dataset.is_blender, is_6dof=dataset.is_6dof)
deform.load_weights(dataset.model_path, iteration)
deform.deform.eval()
# Background color
bg_color = [1, 1, 1] if dataset.white_background else [0, 0, 0]
background = torch.tensor(bg_color, dtype=torch.float32, device="cuda")
os.makedirs(dataset.model_path, exist_ok=True)
if not skip_train:
render_set(dataset.model_path, "train", scene.loaded_iter,
scene.getTrainCameras(), gaussians, deform, pipeline, background,
is_6dof=dataset.is_6dof)
if not skip_test:
render_set(dataset.model_path, "test", scene.loaded_iter,
scene.getTestCameras(), gaussians, deform, pipeline, background,
is_6dof=dataset.is_6dof)
if __name__ == "__main__":
# Set up command line argument parser
parser = ArgumentParser(description="Dynamic scene rendering script")
model = ModelParams(parser, sentinel=True)
pipeline = PipelineParams(parser)
parser.add_argument("--iteration", default=-1, type=int)
parser.add_argument("--skip_train", action="store_true")
parser.add_argument("--skip_test", action="store_true")
parser.add_argument("--quiet", action="store_true")
args = get_combined_args(parser)
print("Rendering dynamic scene: " + args.model_path)
# Initialize system state (RNG)
safe_state(args.quiet)
render_sets(model.extract(args), args.iteration, pipeline.extract(args),
args.skip_train, args.skip_test)