Spaces:
Running
on
Zero
Running
on
Zero
File size: 7,052 Bytes
247f6df 231a433 3167cfe 247f6df a202f8d 247f6df a202f8d 247f6df a202f8d 247f6df a202f8d 247f6df 3167cfe 231a433 247f6df 231a433 247f6df 231a433 247f6df 3167cfe 247f6df 3167cfe 247f6df 3167cfe 247f6df 3167cfe 247f6df 3167cfe 247f6df 3167cfe 247f6df |
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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
import json
import numpy as np
import rerun as rr
import spaces
import gradio as gr
from gradio_rerun import Rerun
from scipy.spatial.transform import Rotation
import tempfile
import os
from typing import Optional, Dict, Any, List, Tuple
def vector3_to_numpy(vec):
"""Convert Vector3 dictionary to numpy array"""
return np.array([vec['x'], vec['y'], vec['z']])
def euler_to_quaternion(euler):
"""Convert Euler angles dictionary to quaternion"""
return Rotation.from_euler('xyz', [euler['x'], euler['y'], euler['z']]).as_quat()
def create_subject_mesh(subject):
"""Create a simple cube mesh for a subject"""
position = vector3_to_numpy(subject['position'])
size = vector3_to_numpy(subject['size'])
# Create cube vertices
vertices = np.array([
[-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, -0.5],
[-0.5, -0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, 0.5], [-0.5, 0.5, 0.5]
]) * size.reshape(1, 3) + position.reshape(1, 3)
# Create cube faces
faces = np.array([
[0, 1, 2], [0, 2, 3], # front
[1, 5, 6], [1, 6, 2], # right
[5, 4, 7], [5, 7, 6], # back
[4, 0, 3], [4, 3, 7], # left
[3, 2, 6], [3, 6, 7], # top
[4, 5, 1], [4, 1, 0] # bottom
])
return vertices, faces
def log_simulation(simulation_data: Dict[str, Any]) -> None:
"""Log single simulation data to Rerun"""
rr.init("camera_simulation")
subjects = simulation_data['subjects']
camera_frames = simulation_data['cameraFrames']
instructions = simulation_data['instructions']
# Log simulation metadata
rr.log("metadata/instructions", rr.TextDocument(
"\n".join([
f"Instruction {i+1}:\n" +
f" Movement: {inst['cameraMovement']}\n" +
f" Easing: {inst['movementEasing']}\n" +
f" Frames: {inst['frameCount']}\n" +
f" Camera Angle: {inst.get('initialCameraAngle', 'N/A')}\n" +
f" Shot Type: {inst.get('initialShotType', 'N/A')}\n" +
f" Subject Index: {inst.get('subjectIndex', 'N/A')}"
for i, inst in enumerate(instructions)
])
), timeless=True)
# Set up world coordinate system
rr.log("world", rr.ViewCoordinates.RIGHT_HAND_Y_UP, timeless=True)
# Log subjects (as simple cubes)
for idx, subject in enumerate(subjects):
vertices, faces = create_subject_mesh(subject)
subject_color = [0.8, 0.2, 0.2, 1.0] if idx == simulation_data.get(
'selectedSubject') else [0.8, 0.8, 0.8, 1.0]
rr.log(
f"world/subject_{idx}",
rr.Mesh3D(
vertex_positions=vertices,
indices=faces,
# Apply color to all vertices
colors=np.tile(subject_color, (len(vertices), 1))
),
timeless=True
)
# Log subject class
rr.log(f"world/subject_{idx}/class",
rr.TextDocument(subject['objectClass']),
timeless=True)
# Log camera trajectory
camera_positions = np.array(
[vector3_to_numpy(frame['position']) for frame in camera_frames])
rr.log(
"world/camera_trajectory",
rr.Points3D(
camera_positions,
# Cyan color for trajectory
colors=np.full((len(camera_positions), 4), [0.0, 0.8, 0.8, 1.0])
),
timeless=True
)
# Log camera movement over time
for frame_idx, camera_frame in enumerate(camera_frames):
rr.set_time_sequence("frame", frame_idx)
position = vector3_to_numpy(camera_frame['position'])
rotation_q = euler_to_quaternion(camera_frame['angle'])
# Log camera transform
rr.log(
"world/camera",
rr.Transform3D(
translation=position,
rotation=rr.Quaternion(xyzw=rotation_q)
)
)
# Log camera frustum
rr.log(
"world/camera/view",
rr.Pinhole(
focal_length=camera_frame['focalLength'],
width=1920,
height=1080
)
)
# Log frame number
rr.log(
"metadata/current_frame",
rr.TextDocument(f"Frame: {frame_idx + 1}/{len(camera_frames)}"),
)
def load_simulation_data(file) -> Tuple[Optional[List[Dict[str, Any]]], Optional[List[str]]]:
"""Load simulation data from JSON file and return simulations with their descriptions"""
if file is None:
return None, None
try:
json_data = json.load(open(file.name))
simulations = json_data['simulations']
# Create descriptions for each simulation
descriptions = [
f"Simulation {i}: {len(sim['subjects'])} subjects, {len(sim['instructions'])} instructions"
for i, sim in enumerate(simulations)
]
return simulations, descriptions
except Exception as e:
print(f"Error loading simulation data: {str(e)}")
return None, None
@spaces.GPU
def visualize_simulation(file, simulation_index: int) -> Optional[str]:
"""Process selected simulation and create Rerun visualization"""
if file is None:
return None
try:
simulations, _ = load_simulation_data(file)
if simulations is None or simulation_index >= len(simulations):
return None
# Create temporary file for RRD
temp_dir = tempfile.mkdtemp()
rrd_path = os.path.join(temp_dir, "simulation.rrd")
# Log selected simulation
simulation = simulations[simulation_index]
log_simulation(simulation)
rr.save(rrd_path)
return rrd_path
except Exception as e:
print(f"Error processing simulation: {str(e)}")
return None
def update_simulation_dropdown(file):
"""Update simulation dropdown when file is uploaded"""
_, descriptions = load_simulation_data(file)
return gr.Dropdown(choices=descriptions if descriptions else [], value=None)
# Create Gradio interface
with gr.Blocks() as demo:
gr.Markdown("""
# Camera Simulation Visualizer
Upload a JSON file containing camera simulation data and select a simulation to visualize.
""")
with gr.Row():
file_input = gr.File(
label="Upload Simulation JSON",
file_types=[".json"]
)
simulation_dropdown = gr.Dropdown(
label="Select Simulation",
choices=[],
type="index"
)
with gr.Row():
viewer = Rerun(streaming=False)
# Update dropdown when file is uploaded
file_input.change(
update_simulation_dropdown,
inputs=[file_input],
outputs=[simulation_dropdown]
)
# Visualize selected simulation
simulation_dropdown.change(
visualize_simulation,
inputs=[file_input, simulation_dropdown],
outputs=[viewer]
)
if __name__ == "__main__":
demo.queue().launch(share=False)
|