abreza commited on
Commit
ffbf761
1 Parent(s): 5f22a23

refactor and organize files

Browse files
app.py CHANGED
@@ -1,230 +1,50 @@
1
- import json
2
- import numpy as np
3
- import rerun as rr
4
- import spaces
5
  import gradio as gr
6
  from gradio_rerun import Rerun
7
- from scipy.spatial.transform import Rotation
8
- import tempfile
9
- import os
10
- from typing import Optional, Dict, Any, List, Tuple
11
 
12
 
13
- def vector3_to_numpy(vec):
14
- """Convert Vector3 dictionary to numpy array"""
15
- return np.array([vec['x'], vec['y'], vec['z']])
16
-
17
-
18
- def euler_to_quaternion(euler):
19
- """Convert Euler angles dictionary to quaternion"""
20
- return Rotation.from_euler('xyz', [euler['x'], euler['y'], euler['z']]).as_quat()
21
-
22
-
23
- def create_subject_mesh(subject):
24
- """Create a simple cube mesh for a subject"""
25
- position = vector3_to_numpy(subject['position'])
26
- size = vector3_to_numpy(subject['size'])
27
-
28
- # Create cube vertices
29
- vertices = np.array([
30
- [-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, -0.5],
31
- [-0.5, -0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, 0.5], [-0.5, 0.5, 0.5]
32
- ]) * size.reshape(1, 3) + position.reshape(1, 3)
33
-
34
- # Create cube faces
35
- faces = np.array([
36
- [0, 1, 2], [0, 2, 3], # front
37
- [1, 5, 6], [1, 6, 2], # right
38
- [5, 4, 7], [5, 7, 6], # back
39
- [4, 0, 3], [4, 3, 7], # left
40
- [3, 2, 6], [3, 6, 7], # top
41
- [4, 5, 1], [4, 1, 0] # bottom
42
- ])
43
-
44
- return vertices, faces
45
-
46
-
47
- def log_simulation(simulation_data: Dict[str, Any]) -> None:
48
- """Log single simulation data to Rerun"""
49
- rr.init("camera_simulation")
50
-
51
- subjects = simulation_data['subjects']
52
- camera_frames = simulation_data['cameraFrames']
53
- instructions = simulation_data['instructions']
54
-
55
- # Log simulation metadata
56
- rr.log("metadata/instructions", rr.TextDocument(
57
- "\n".join([
58
- f"Instruction {i+1}:\n" +
59
- f" Movement: {inst['cameraMovement']}\n" +
60
- f" Easing: {inst['movementEasing']}\n" +
61
- f" Frames: {inst['frameCount']}\n" +
62
- f" Camera Angle: {inst.get('initialCameraAngle', 'N/A')}\n" +
63
- f" Shot Type: {inst.get('initialShotType', 'N/A')}\n" +
64
- f" Subject Index: {inst.get('subjectIndex', 'N/A')}"
65
- for i, inst in enumerate(instructions)
66
- ])
67
- ), timeless=True)
68
-
69
- # Set up world coordinate system
70
- rr.log("world", rr.ViewCoordinates.RIGHT_HAND_Y_UP, timeless=True)
71
-
72
- # Log subjects (as simple cubes)
73
- for idx, subject in enumerate(subjects):
74
- vertices, faces = create_subject_mesh(subject)
75
- subject_color = [0.8, 0.2, 0.2, 1.0] if idx == simulation_data.get(
76
- 'selectedSubject') else [0.8, 0.8, 0.8, 1.0]
77
-
78
- rr.log(
79
- f"world/subject_{idx}",
80
- rr.Mesh3D(
81
- vertex_positions=vertices,
82
- indices=faces,
83
- # Apply color to all vertices
84
- colors=np.tile(subject_color, (len(vertices), 1))
85
- ),
86
- timeless=True
87
- )
88
-
89
- # Log subject class
90
- rr.log(f"world/subject_{idx}/class",
91
- rr.TextDocument(subject['objectClass']),
92
- timeless=True)
93
-
94
- # Log camera trajectory
95
- camera_positions = np.array(
96
- [vector3_to_numpy(frame['position']) for frame in camera_frames])
97
- rr.log(
98
- "world/camera_trajectory",
99
- rr.Points3D(
100
- camera_positions,
101
- # Cyan color for trajectory
102
- colors=np.full((len(camera_positions), 4), [0.0, 0.8, 0.8, 1.0])
103
- ),
104
- timeless=True
105
- )
106
 
107
- # Log camera movement over time
108
- for frame_idx, camera_frame in enumerate(camera_frames):
109
- rr.set_time_sequence("frame", frame_idx)
110
 
111
- position = vector3_to_numpy(camera_frame['position'])
112
- rotation_q = euler_to_quaternion(camera_frame['angle'])
 
 
 
 
113
 
114
- # Log camera transform
115
- rr.log(
116
- "world/camera",
117
- rr.Transform3D(
118
- translation=position,
119
- rotation=rr.Quaternion(xyzw=rotation_q)
120
  )
121
- )
122
-
123
- # Log camera frustum
124
- rr.log(
125
- "world/camera/view",
126
- rr.Pinhole(
127
- focal_length=camera_frame['focalLength'],
128
- width=1920,
129
- height=1080
130
  )
131
- )
132
 
133
- # Log frame number
134
- rr.log(
135
- "metadata/current_frame",
136
- rr.TextDocument(f"Frame: {frame_idx + 1}/{len(camera_frames)}"),
137
- )
138
-
139
-
140
- def load_simulation_data(file) -> Tuple[Optional[List[Dict[str, Any]]], Optional[List[str]]]:
141
- """Load simulation data from JSON file and return simulations with their descriptions"""
142
- if file is None:
143
- return None, None
144
-
145
- try:
146
- json_data = json.load(open(file.name))
147
- simulations = json_data['simulations']
148
-
149
- # Create descriptions for each simulation
150
- descriptions = [
151
- f"Simulation {i}: {len(sim['subjects'])} subjects, {len(sim['instructions'])} instructions"
152
- for i, sim in enumerate(simulations)
153
- ]
154
-
155
- return simulations, descriptions
156
- except Exception as e:
157
- print(f"Error loading simulation data: {str(e)}")
158
- return None, None
159
-
160
-
161
- @spaces.GPU
162
- def visualize_simulation(file, simulation_index: int) -> Optional[str]:
163
- """Process selected simulation and create Rerun visualization"""
164
- if file is None:
165
- return None
166
-
167
- try:
168
- simulations, _ = load_simulation_data(file)
169
- if simulations is None or simulation_index >= len(simulations):
170
- return None
171
-
172
- # Create temporary file for RRD
173
- temp_dir = tempfile.mkdtemp()
174
- rrd_path = os.path.join(temp_dir, "simulation.rrd")
175
-
176
- # Log selected simulation
177
- simulation = simulations[simulation_index]
178
- log_simulation(simulation)
179
- rr.save(rrd_path)
180
 
181
- return rrd_path
182
-
183
- except Exception as e:
184
- print(f"Error processing simulation: {str(e)}")
185
- return None
186
-
187
-
188
- def update_simulation_dropdown(file):
189
- """Update simulation dropdown when file is uploaded"""
190
- _, descriptions = load_simulation_data(file)
191
- return gr.Dropdown(choices=descriptions if descriptions else [], value=None)
192
-
193
-
194
- # Create Gradio interface
195
- with gr.Blocks() as demo:
196
- gr.Markdown("""
197
- # Camera Simulation Visualizer
198
- Upload a JSON file containing camera simulation data and select a simulation to visualize.
199
- """)
200
-
201
- with gr.Row():
202
- file_input = gr.File(
203
- label="Upload Simulation JSON",
204
- file_types=[".json"]
205
- )
206
- simulation_dropdown = gr.Dropdown(
207
- label="Select Simulation",
208
- choices=[],
209
- type="index"
210
  )
211
 
212
- with gr.Row():
213
- viewer = Rerun(streaming=False)
 
 
 
214
 
215
- # Update dropdown when file is uploaded
216
- file_input.change(
217
- update_simulation_dropdown,
218
- inputs=[file_input],
219
- outputs=[simulation_dropdown]
220
- )
221
 
222
- # Visualize selected simulation
223
- simulation_dropdown.change(
224
- visualize_simulation,
225
- inputs=[file_input, simulation_dropdown],
226
- outputs=[viewer]
227
- )
228
 
229
  if __name__ == "__main__":
 
230
  demo.queue().launch(share=False)
 
 
 
 
 
1
  import gradio as gr
2
  from gradio_rerun import Rerun
3
+ from data.loader import load_simulation_data
4
+ from visualization.visualizer import visualize_simulation
 
 
5
 
6
 
7
+ def update_simulation_dropdown(file):
8
+ _, descriptions = load_simulation_data(file)
9
+ return gr.Dropdown(choices=descriptions if descriptions else [], value=None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
 
 
 
11
 
12
+ def create_app():
13
+ with gr.Blocks() as demo:
14
+ gr.Markdown("""
15
+ # Camera Simulation Visualizer
16
+ Upload a JSON file containing camera simulation data and select a simulation to visualize.
17
+ """)
18
 
19
+ with gr.Row():
20
+ file_input = gr.File(
21
+ label="Upload Simulation JSON",
22
+ file_types=[".json"]
 
 
23
  )
24
+ simulation_dropdown = gr.Dropdown(
25
+ label="Select Simulation",
26
+ choices=[],
27
+ type="index"
 
 
 
 
 
28
  )
 
29
 
30
+ with gr.Row():
31
+ viewer = Rerun(streaming=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ file_input.change(
34
+ update_simulation_dropdown,
35
+ inputs=[file_input],
36
+ outputs=[simulation_dropdown]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  )
38
 
39
+ simulation_dropdown.change(
40
+ visualize_simulation,
41
+ inputs=[file_input, simulation_dropdown],
42
+ outputs=[viewer]
43
+ )
44
 
45
+ return demo
 
 
 
 
 
46
 
 
 
 
 
 
 
47
 
48
  if __name__ == "__main__":
49
+ demo = create_app()
50
  demo.queue().launch(share=False)
data/loader.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from typing import Optional, Dict, Any, List, Tuple
3
+
4
+
5
+ def load_simulation_data(file) -> Tuple[Optional[List[Dict[str, Any]]], Optional[List[str]]]:
6
+ if file is None:
7
+ return None, None
8
+
9
+ try:
10
+ json_data = json.load(open(file.name))
11
+ simulations = json_data['simulations']
12
+
13
+ descriptions = [
14
+ f"Simulation {i}: {len(sim['subjects'])} subjects, {len(sim['instructions'])} instructions"
15
+ for i, sim in enumerate(simulations)
16
+ ]
17
+
18
+ return simulations, descriptions
19
+ except Exception as e:
20
+ print(f"Error loading simulation data: {str(e)}")
21
+ return None, None
utils/geometry.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from scipy.spatial.transform import Rotation
3
+ from typing import Dict
4
+
5
+
6
+ def vector3_to_numpy(vec: Dict[str, float]) -> np.ndarray:
7
+ return np.array([vec['x'], vec['y'], vec['z']])
8
+
9
+
10
+ def euler_to_quaternion(euler: Dict[str, float]) -> np.ndarray:
11
+ return Rotation.from_euler('xyz', [euler['x'], euler['y'], euler['z']]).as_quat()
visualization/logger.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import rerun as rr
2
+ import numpy as np
3
+ from typing import Dict, Any, List
4
+ from ..utils.geometry import vector3_to_numpy, euler_to_quaternion
5
+ from .mesh import create_subject_mesh
6
+
7
+
8
+ class SimulationLogger:
9
+ def __init__(self):
10
+ rr.init("camera_simulation")
11
+ rr.log("world", rr.ViewCoordinates.RIGHT_HAND_Y_UP, timeless=True)
12
+
13
+ def log_metadata(self, instructions: List[Dict[str, Any]]) -> None:
14
+ rr.log("metadata/instructions", rr.TextDocument(
15
+ "\n".join([
16
+ f"Instruction {i+1}:\n" +
17
+ f" Movement: {inst['cameraMovement']}\n" +
18
+ f" Easing: {inst['movementEasing']}\n" +
19
+ f" Frames: {inst['frameCount']}\n" +
20
+ f" Camera Angle: {inst.get('initialCameraAngle', 'N/A')}\n" +
21
+ f" Shot Type: {inst.get('initialShotType', 'N/A')}\n" +
22
+ f" Subject Index: {inst.get('subjectIndex', 'N/A')}"
23
+ for i, inst in enumerate(instructions)
24
+ ])
25
+ ), timeless=True)
26
+
27
+ def log_subjects(self, subjects: List[Dict[str, Any]], selected_subject: int = None) -> None:
28
+ for idx, subject in enumerate(subjects):
29
+ vertices, faces = create_subject_mesh(subject)
30
+ subject_color = [0.8, 0.2, 0.2, 1.0] if idx == selected_subject else [
31
+ 0.8, 0.8, 0.8, 1.0]
32
+
33
+ rr.log(
34
+ f"world/subject_{idx}",
35
+ rr.Mesh3D(
36
+ vertex_positions=vertices,
37
+ indices=faces,
38
+ colors=np.tile(subject_color, (len(vertices), 1))
39
+ ),
40
+ timeless=True
41
+ )
42
+
43
+ rr.log(f"world/subject_{idx}/class",
44
+ rr.TextDocument(subject['objectClass']),
45
+ timeless=True)
46
+
47
+ def log_camera_trajectory(self, camera_frames: List[Dict[str, Any]]) -> None:
48
+ camera_positions = np.array(
49
+ [vector3_to_numpy(frame['position']) for frame in camera_frames])
50
+ rr.log(
51
+ "world/camera_trajectory",
52
+ rr.Points3D(
53
+ camera_positions,
54
+ colors=np.full((len(camera_positions), 4),
55
+ [0.0, 0.8, 0.8, 1.0])
56
+ ),
57
+ timeless=True
58
+ )
59
+
60
+ def log_camera_frames(self, camera_frames: List[Dict[str, Any]]) -> None:
61
+ for frame_idx, camera_frame in enumerate(camera_frames):
62
+ rr.set_time_sequence("frame", frame_idx)
63
+
64
+ position = vector3_to_numpy(camera_frame['position'])
65
+ rotation_q = euler_to_quaternion(camera_frame['angle'])
66
+
67
+ rr.log(
68
+ "world/camera",
69
+ rr.Transform3D(
70
+ translation=position,
71
+ rotation=rr.Quaternion(xyzw=rotation_q)
72
+ )
73
+ )
74
+
75
+ rr.log(
76
+ "world/camera/view",
77
+ rr.Pinhole(
78
+ focal_length=camera_frame['focalLength'],
79
+ width=1920,
80
+ height=1080
81
+ )
82
+ )
83
+
84
+ rr.log(
85
+ "metadata/current_frame",
86
+ rr.TextDocument(
87
+ f"Frame: {frame_idx + 1}/{len(camera_frames)}"),
88
+ )
visualization/mesh.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from typing import Dict, Tuple
3
+ from ..utils.geometry import vector3_to_numpy
4
+
5
+
6
+ def create_subject_mesh(subject: Dict) -> Tuple[np.ndarray, np.ndarray]:
7
+ position = vector3_to_numpy(subject['position'])
8
+ size = vector3_to_numpy(subject['size'])
9
+
10
+ # Create cube vertices
11
+ vertices = np.array([
12
+ [-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, -0.5],
13
+ [-0.5, -0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, 0.5], [-0.5, 0.5, 0.5]
14
+ ]) * size.reshape(1, 3) + position.reshape(1, 3)
15
+
16
+ # Create cube faces
17
+ faces = np.array([
18
+ [0, 1, 2], [0, 2, 3], # front
19
+ [1, 5, 6], [1, 6, 2], # right
20
+ [5, 4, 7], [5, 7, 6], # back
21
+ [4, 0, 3], [4, 3, 7], # left
22
+ [3, 2, 6], [3, 6, 7], # top
23
+ [4, 5, 1], [4, 1, 0] # bottom
24
+ ])
25
+
26
+ return vertices, faces
visualization/visualizer.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tempfile
2
+ import os
3
+ import spaces
4
+ from typing import Optional
5
+ from ..data.loader import load_simulation_data
6
+ from .logger import SimulationLogger
7
+ import rerun as rr
8
+
9
+
10
+ @spaces.GPU
11
+ def visualize_simulation(file, simulation_index: int) -> Optional[str]:
12
+ if file is None:
13
+ return None
14
+
15
+ try:
16
+ simulations, _ = load_simulation_data(file)
17
+ if simulations is None or simulation_index >= len(simulations):
18
+ return None
19
+
20
+ # Create temporary file for RRD
21
+ temp_dir = tempfile.mkdtemp()
22
+ rrd_path = os.path.join(temp_dir, "simulation.rrd")
23
+
24
+ # Log selected simulation
25
+ simulation = simulations[simulation_index]
26
+
27
+ logger = SimulationLogger()
28
+ logger.log_metadata(simulation['instructions'])
29
+ logger.log_subjects(
30
+ simulation['subjects'], simulation.get('selectedSubject'))
31
+ logger.log_camera_trajectory(simulation['cameraFrames'])
32
+ logger.log_camera_frames(simulation['cameraFrames'])
33
+
34
+ rr.save(rrd_path)
35
+
36
+ return rrd_path
37
+
38
+ except Exception as e:
39
+ print(f"Error processing simulation: {str(e)}")
40
+ return None