Skip to content

Commit 1552402

Browse files
committed
overwrite panel for existing camera path
1 parent b11efa2 commit 1552402

File tree

1 file changed

+112
-110
lines changed

1 file changed

+112
-110
lines changed

nerfview/render_panel.py

Lines changed: 112 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -935,17 +935,17 @@ def compute_and_update_preview_camera_state() -> (
935935
return
936936
time = None
937937
if len(maybe_pose_and_fov_rad) == 3: # Time is enabled.
938-
pose, fov_rad, time = maybe_pose_and_fov_rad
938+
pose, fov, time = maybe_pose_and_fov_rad
939939
render_tab_state.preview_time = time
940940
else:
941-
pose, fov_rad = maybe_pose_and_fov_rad
942-
render_tab_state.preview_fov = fov_rad
941+
pose, fov = maybe_pose_and_fov_rad
942+
render_tab_state.preview_fov = fov
943943
render_tab_state.preview_aspect = camera_path.get_aspect()
944944

945945
if time is not None:
946-
return pose, fov_rad, time
946+
return pose, fov, time
947947
else:
948-
return pose, fov_rad
948+
return pose, fov
949949

950950
def add_preview_frame_slider() -> Optional[viser.GuiInputHandle[int]]:
951951
"""Helper for creating the current frame # slider. This is removed and
@@ -974,13 +974,13 @@ def _(_) -> None:
974974
if maybe_pose_and_fov_rad is None:
975975
return
976976
if len(maybe_pose_and_fov_rad) == 3: # Time is enabled.
977-
pose, fov_rad, time = maybe_pose_and_fov_rad
977+
pose, fov, time = maybe_pose_and_fov_rad
978978
else:
979-
pose, fov_rad = maybe_pose_and_fov_rad
979+
pose, fov = maybe_pose_and_fov_rad
980980

981981
preview_camera_handle = server.scene.add_camera_frustum(
982982
"/preview_camera",
983-
fov=fov_rad,
983+
fov=fov,
984984
aspect=render_res_vec2.value[0] / render_res_vec2.value[1],
985985
scale=0.35,
986986
wxyz=pose.rotation().wxyz,
@@ -993,7 +993,7 @@ def _(_) -> None:
993993
# aspect ratio is not assignable, pass args in get_render instead
994994
client.camera.wxyz = pose.rotation().wxyz
995995
client.camera.position = pose.translation()
996-
client.camera.fov = fov_rad
996+
client.camera.fov = fov
997997

998998
return preview_frame_slider
999999

@@ -1216,108 +1216,110 @@ def _(_) -> None:
12161216
@save_camera_path_button.on_click
12171217
def _(event: viser.GuiEvent) -> None:
12181218
assert event.client is not None
1219-
num_frames = int(framerate_number.value * duration_number.value)
1220-
json_data = {}
1221-
# json data has the properties:
1222-
# keyframes: list of keyframes with
1223-
# matrix : flattened 4x4 matrix
1224-
# fov: float in degrees
1225-
# aspect: float
1226-
# render_height: int
1227-
# render_width: int
1228-
# fps: int
1229-
# seconds: float
1230-
# is_cycle: bool
1231-
# smoothness_value: float
1232-
# camera_path: list of frames with properties
1233-
# camera_to_world: flattened 4x4 matrix
1234-
# fov: float in degrees
1235-
# aspect: float
1236-
# first populate the keyframes:
1237-
keyframes = []
1238-
for keyframe, dummy in camera_path._keyframes.values():
1239-
pose = tf.SE3.from_rotation_and_translation(
1240-
tf.SO3(keyframe.wxyz) @ tf.SO3.from_x_radians(np.pi),
1241-
keyframe.position / scale_ratio,
1242-
)
1243-
keyframe_dict = {
1244-
"matrix": pose.as_matrix().flatten().tolist(),
1245-
"fov": (
1246-
np.rad2deg(keyframe.override_fov_rad)
1247-
if keyframe.override_fov_enabled
1248-
else fov_degrees_slider.value
1249-
),
1250-
"aspect": keyframe.aspect,
1251-
"override_transition_enabled": keyframe.override_transition_enabled,
1252-
"override_transition_sec": keyframe.override_transition_sec,
1253-
}
1254-
keyframes.append(keyframe_dict)
1255-
json_data["default_fov"] = fov_degrees_slider.value
1256-
json_data["default_transition_sec"] = transition_sec_number.value
1257-
json_data["keyframes"] = keyframes
1258-
json_data["render_height"] = render_res_vec2.value[1]
1259-
json_data["render_width"] = render_res_vec2.value[0]
1260-
json_data["fps"] = framerate_number.value
1261-
json_data["seconds"] = duration_number.value
1262-
json_data["is_cycle"] = loop_checkbox.value
1263-
json_data["smoothness_value"] = tension_slider.value
1264-
# now populate the camera path:
1265-
camera_path_list = []
1266-
for i in range(num_frames):
1267-
maybe_pose_and_fov = camera_path.interpolate_pose_and_fov_rad(
1268-
i / num_frames
1269-
)
1270-
if maybe_pose_and_fov is None:
1271-
return
1272-
time = None
1273-
if len(maybe_pose_and_fov) == 3: # Time is enabled.
1274-
pose, fov, time = maybe_pose_and_fov
1275-
else:
1276-
pose, fov = maybe_pose_and_fov
1277-
# rotate the axis of the camera 180 about x axis
1278-
pose = tf.SE3.from_rotation_and_translation(
1279-
pose.rotation() @ tf.SO3.from_x_radians(np.pi),
1280-
pose.translation() / scale_ratio,
1281-
)
1282-
camera_path_list_dict = {
1283-
"camera_to_world": pose.as_matrix().flatten().tolist(),
1284-
"fov": np.rad2deg(fov),
1285-
"aspect": render_res_vec2.value[0] / render_res_vec2.value[1],
1286-
}
1287-
if time is not None:
1288-
camera_path_list_dict["render_time"] = time
1289-
camera_path_list.append(camera_path_list_dict)
1290-
json_data["camera_path"] = camera_path_list
1291-
# finally add crop data if crop is enabled
1292-
# if control_panel is not None:
1293-
# if control_panel.crop_viewport:
1294-
# obb = control_panel.crop_obb
1295-
# rpy = tf.SO3.from_matrix(obb.R.numpy()).as_rpy_radians()
1296-
# color = control_panel.background_color
1297-
# json_data["crop"] = {
1298-
# "crop_center": obb.T.tolist(),
1299-
# "crop_scale": obb.S.tolist(),
1300-
# "crop_rot": [rpy.roll, rpy.pitch, rpy.yaw],
1301-
# "crop_bg_color": {"r": color[0], "g": color[1], "b": color[2]},
1302-
# }
1303-
1304-
# now write the json file
1305-
try:
1306-
json_outfile = (
1307-
output_dir / "camera_paths" / f"{trajectory_name_text.value}.json"
1308-
)
1309-
json_outfile.parent.mkdir(parents=True, exist_ok=True)
1310-
except Exception:
1311-
Console(width=120).print(
1312-
"[bold yellow]Warning: Failed to write the camera path to the data directory. Saving to the output directory instead."
1313-
)
1314-
json_outfile = (
1315-
output_dir / "camera_paths" / f"{trajectory_name_text.value}.json"
1316-
)
1219+
1220+
json_outfile = (
1221+
output_dir / "camera_paths" / f"{trajectory_name_text.value}.json"
1222+
)
1223+
1224+
def save_camera_path() -> None:
13171225
json_outfile.parent.mkdir(parents=True, exist_ok=True)
1318-
with open(json_outfile.absolute(), "w") as outfile:
1319-
json.dump(json_data, outfile)
1320-
print(f"Camera path saved to {json_outfile.absolute()}")
1226+
1227+
num_frames = int(framerate_number.value * duration_number.value)
1228+
json_data = {}
1229+
# json data has the properties:
1230+
# keyframes: list of keyframes with
1231+
# matrix : flattened 4x4 matrix
1232+
# fov: float in degrees
1233+
# aspect: float
1234+
# render_height: int
1235+
# render_width: int
1236+
# fps: int
1237+
# seconds: float
1238+
# is_cycle: bool
1239+
# smoothness_value: float
1240+
# camera_path: list of frames with properties
1241+
# camera_to_world: flattened 4x4 matrix
1242+
# fov: float in degrees
1243+
# aspect: float
1244+
# first populate the keyframes:
1245+
keyframes = []
1246+
for keyframe, dummy in camera_path._keyframes.values():
1247+
pose = tf.SE3.from_rotation_and_translation(
1248+
tf.SO3(keyframe.wxyz) @ tf.SO3.from_x_radians(np.pi),
1249+
keyframe.position / scale_ratio,
1250+
)
1251+
keyframe_dict = {
1252+
"matrix": pose.as_matrix().flatten().tolist(),
1253+
"fov": (
1254+
np.rad2deg(keyframe.override_fov_rad)
1255+
if keyframe.override_fov_enabled
1256+
else fov_degrees_slider.value
1257+
),
1258+
"aspect": keyframe.aspect,
1259+
"override_transition_enabled": keyframe.override_transition_enabled,
1260+
"override_transition_sec": keyframe.override_transition_sec,
1261+
}
1262+
keyframes.append(keyframe_dict)
1263+
json_data["default_fov"] = fov_degrees_slider.value
1264+
json_data["default_transition_sec"] = transition_sec_number.value
1265+
json_data["keyframes"] = keyframes
1266+
json_data["render_height"] = render_res_vec2.value[1]
1267+
json_data["render_width"] = render_res_vec2.value[0]
1268+
json_data["fps"] = framerate_number.value
1269+
json_data["seconds"] = duration_number.value
1270+
json_data["is_cycle"] = loop_checkbox.value
1271+
json_data["smoothness_value"] = tension_slider.value
1272+
# now populate the camera path:
1273+
camera_path_list = []
1274+
for i in range(num_frames):
1275+
maybe_pose_and_fov = camera_path.interpolate_pose_and_fov_rad(
1276+
i / num_frames
1277+
)
1278+
if maybe_pose_and_fov is None:
1279+
return
1280+
time = None
1281+
if len(maybe_pose_and_fov) == 3: # Time is enabled.
1282+
pose, fov, time = maybe_pose_and_fov
1283+
else:
1284+
pose, fov = maybe_pose_and_fov
1285+
# rotate the axis of the camera 180 about x axis
1286+
pose = tf.SE3.from_rotation_and_translation(
1287+
pose.rotation() @ tf.SO3.from_x_radians(np.pi),
1288+
pose.translation() / scale_ratio,
1289+
)
1290+
camera_path_list_dict = {
1291+
"camera_to_world": pose.as_matrix().flatten().tolist(),
1292+
"fov": np.rad2deg(fov),
1293+
"aspect": render_res_vec2.value[0] / render_res_vec2.value[1],
1294+
}
1295+
if time is not None:
1296+
camera_path_list_dict["render_time"] = time
1297+
camera_path_list.append(camera_path_list_dict)
1298+
json_data["camera_path"] = camera_path_list
1299+
1300+
with open(json_outfile.absolute(), "w") as outfile:
1301+
json.dump(json_data, outfile)
1302+
print(f"Camera path saved to {json_outfile.absolute()}")
1303+
1304+
if json_outfile.exists():
1305+
with event.client.gui.add_modal("Save Path") as modal:
1306+
event.client.gui.add_markdown(
1307+
"Path already exists. Do you want to overwrite?"
1308+
)
1309+
overwrite_button = event.client.gui.add_button("Overwrite")
1310+
cancel_button = event.client.gui.add_button("Cancel")
1311+
1312+
@overwrite_button.on_click
1313+
def _(_) -> None:
1314+
modal.close()
1315+
save_camera_path()
1316+
1317+
@cancel_button.on_click
1318+
def _(_) -> None:
1319+
modal.close()
1320+
1321+
else:
1322+
save_camera_path()
13211323

13221324
@dump_video_button.on_click
13231325
def _(event: viser.GuiEvent) -> None:

0 commit comments

Comments
 (0)