Spaces:
Runtime error
Runtime error
| import rerun as rr | |
| import numpy as np | |
| from typing import Dict, Any, List | |
| from utils.geometry import vector3_to_numpy, euler_to_quaternion | |
| def create_subject_box(frame: Dict[str, Any], dimensions: Dict[str, float]) -> Dict[str, np.ndarray]: | |
| """ | |
| Given a single frame (position, rotation) and subject's dimensions, | |
| return the center and half_size for a box representation. | |
| """ | |
| position = vector3_to_numpy(frame['position']) | |
| half_size = np.array([ | |
| dimensions['width'] / 2.0, | |
| dimensions['height'] / 2.0, | |
| dimensions['depth'] / 2.0 | |
| ], dtype=np.float32) | |
| return { | |
| 'center': position, | |
| 'half_size': half_size | |
| } | |
| class SimulationLogger: | |
| def __init__(self): | |
| rr.init("camera_simulation") | |
| rr.log("world", rr.ViewCoordinates.RIGHT_HAND_Y_UP, timeless=True) | |
| self.K = np.array([ | |
| [500, 0, 960], | |
| [0, 500, 540], | |
| [0, 0, 1] | |
| ]) | |
| def log_metadata(self, instructions: List[Dict[str, Any]]) -> None: | |
| if not instructions: | |
| return | |
| rr.log( | |
| "metadata/instructions", | |
| rr.TextDocument( | |
| "\n".join([ | |
| f"Instruction {i+1}:\n" | |
| f" Movement: {inst.get('cameraMovement', 'N/A')}\n" | |
| f" Easing: {inst.get('movementEasing', 'N/A')}\n" | |
| f" Frames: {inst.get('frameCount', 'N/A')}\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 | |
| ) | |
| def log_subjects(self, subjects: List[Dict[str, Any]]) -> None: | |
| """ | |
| Handles dynamic subjects: | |
| - Each subject has multiple frames (position, rotation). | |
| - Subject dimensions (width, height, depth) remain constant across frames. | |
| """ | |
| if not subjects: | |
| return | |
| for subject_idx, subject in enumerate(subjects): | |
| dimensions = subject.get("dimensions", {}) | |
| frames = subject.get("frames", []) | |
| label = subject.get('objectClass', f"Subject_{subject_idx}") | |
| for frame_idx, frame in enumerate(frames): | |
| rr.set_time_sequence("frame_idx", frame_idx) | |
| try: | |
| box_params = create_subject_box(frame, dimensions) | |
| center = box_params['center'] | |
| half_size = box_params['half_size'] | |
| # Convert Euler angles to quaternion for rotation | |
| rotation_q = euler_to_quaternion(frame['rotation']) | |
| # 1) Log a transform for this subject so the box is placed at 'center' with correct rotation | |
| rr.log( | |
| f"world/subjects/subject_{subject_idx}", | |
| rr.Transform3D( | |
| translation=center, | |
| rotation=rr.Quaternion(xyzw=rotation_q) | |
| ) | |
| ) | |
| # 2) Log a box at the origin of the subject's local transform | |
| rr.log( | |
| f"world/subjects/subject_{subject_idx}/box", | |
| rr.Boxes3D( | |
| centers=np.array([[0.0, 0.0, 0.0]], dtype=np.float32), | |
| half_sizes=np.array([half_size], dtype=np.float32), | |
| colors=np.array([[0.8, 0.2, 0.2, 1.0]], dtype=np.float32), | |
| labels=[label], | |
| show_labels=False, | |
| fill_mode="solid" | |
| ) | |
| ) | |
| except Exception as e: | |
| print(f"Error creating box parameters for subject {subject_idx}, frame {frame_idx}: {str(e)}") | |
| def log_subject_trajectories(self, subjects: List[Dict[str, Any]]) -> None: | |
| """ | |
| For each subject, collect all frame centers and log them as: | |
| - A set of 3D points (subject center positions). | |
| - A line strip connecting them (showing the subject's center path). | |
| This is done timelessly so the full trajectory is always visible. | |
| """ | |
| if not subjects: | |
| return | |
| for subject_idx, subject in enumerate(subjects): | |
| dimensions = subject.get("dimensions", {}) | |
| frames = subject.get("frames", []) | |
| label = subject.get('objectClass', f"Subject_{subject_idx}") | |
| if not frames: | |
| continue | |
| # Gather center positions | |
| center_positions = [] | |
| for frame in frames: | |
| pos = vector3_to_numpy(frame['position']) | |
| center_positions.append(pos) | |
| center_positions = np.array(center_positions, dtype=np.float32) | |
| # Log the points | |
| rr.log( | |
| f"world/subjects/subject_{subject_idx}/center_trajectory_points", | |
| rr.Points3D( | |
| center_positions, | |
| colors=np.full((len(center_positions), 4), [0.8, 0.6, 0.2, 1.0]) | |
| ), | |
| timeless=True | |
| ) | |
| # Log a line strip | |
| if len(center_positions) > 1: | |
| lines = np.stack([center_positions[:-1], center_positions[1:]], axis=1) | |
| rr.log( | |
| f"world/subjects/subject_{subject_idx}/center_trajectory_line", | |
| rr.LineStrips3D( | |
| lines, | |
| colors=[(0.8, 0.6, 0.2, 1.0)], | |
| ), | |
| timeless=True | |
| ) | |
| def log_camera_trajectory(self, camera_frames: List[Dict[str, Any]]) -> None: | |
| """ | |
| Logs the entire camera trajectory as a set of 3D points and a connecting line strip. | |
| This is typically done timelessly to show the full path at once. | |
| """ | |
| if not camera_frames: | |
| return | |
| try: | |
| camera_positions = np.array([ | |
| vector3_to_numpy(frame['position']) for frame in camera_frames | |
| ], dtype=np.float32) | |
| rr.log( | |
| "world/camera_trajectory_points", | |
| rr.Points3D( | |
| camera_positions, | |
| colors=np.full((len(camera_positions), 4), [0.0, 0.8, 0.8, 1.0]) | |
| ), | |
| timeless=True | |
| ) | |
| if len(camera_positions) > 1: | |
| lines = np.stack([camera_positions[:-1], camera_positions[1:]], axis=1) | |
| rr.log( | |
| "world/camera_trajectory_line", | |
| rr.LineStrips3D( | |
| lines, | |
| colors=[(0.0, 0.8, 0.8, 1.0)] | |
| ), | |
| timeless=True | |
| ) | |
| except Exception as e: | |
| print(f"Error logging camera trajectory: {str(e)}") | |
| def log_camera_frames(self, camera_frames: List[Dict[str, Any]]) -> None: | |
| """ | |
| Logs each camera frame at a given time sequence, so you can watch it update over time. | |
| """ | |
| if not camera_frames: | |
| return | |
| for frame_idx, camera_frame in enumerate(camera_frames): | |
| try: | |
| rr.set_time_sequence("frame_idx", frame_idx) | |
| position = vector3_to_numpy(camera_frame['position']) | |
| rotation_q = euler_to_quaternion(camera_frame['angle']) | |
| rr.log( | |
| "world/camera", | |
| rr.Transform3D( | |
| translation=position, | |
| rotation=rr.Quaternion(xyzw=rotation_q) | |
| ) | |
| ) | |
| rr.log( | |
| "world/camera/image", | |
| rr.Pinhole( | |
| image_from_camera=self.K, | |
| width=1920, | |
| height=1080 | |
| ) | |
| ) | |
| except Exception as e: | |
| print(f"Error logging camera frame {frame_idx}: {str(e)}") | |
| def log_helper_keyframes(self, helper_keyframes: List[Dict[str, Any]]) -> None: | |
| if not helper_keyframes: | |
| return | |
| helper_positions = np.array([ | |
| vector3_to_numpy(frame['position']) for frame in helper_keyframes | |
| ]) | |
| rr.log( | |
| "world/helper_keyframes", | |
| rr.Points3D( | |
| helper_positions, | |
| radii=np.full(len(helper_positions), 0.03), | |
| colors=np.full((len(helper_positions), 4), [1.0, 1.0, 0.0, 1.0]), | |
| ), | |
| timeless=True | |
| ) | |
| for keyframe_idx, helper_keyframe in enumerate(helper_keyframes): | |
| try: | |
| position = vector3_to_numpy(helper_keyframe['position']) | |
| rotation_q = euler_to_quaternion(helper_keyframe['angle']) | |
| rr.log( | |
| f"world/helper_camera_{keyframe_idx}", | |
| rr.Transform3D( | |
| translation=position, | |
| rotation=rr.Quaternion(xyzw=rotation_q), | |
| scale=(.5, .5, .5) | |
| ), | |
| timeless=True | |
| ) | |
| rr.log( | |
| f"world/helper_camera_{keyframe_idx}/image", | |
| rr.Pinhole( | |
| image_from_camera=self.K, | |
| width=1920, | |
| height=1080, | |
| ) | |
| ) | |
| except Exception as e: | |
| print(f"Error logging helper keyframe {keyframe_idx}: {str(e)}") | |