Draw camera frame if extrinsic calibration is available. The extrinsic calibration stores T_head^camera (transforms points from head to camera). To visualize the camera's POSE in the head frame, we need the inverse: T_camera^head. The camera's Z-axis in ARKit convention points
(ax, head_matrix: np.ndarray, extrinsic: dict | None, scale: float = 0.08)
| 182 | |
| 183 | |
| 184 | def draw_camera_frame(ax, head_matrix: np.ndarray, extrinsic: dict | None, scale: float = 0.08): |
| 185 | """Draw camera frame if extrinsic calibration is available. |
| 186 | |
| 187 | The extrinsic calibration stores T_head^camera (transforms points from head to camera). |
| 188 | To visualize the camera's POSE in the head frame, we need the inverse: T_camera^head. |
| 189 | |
| 190 | The camera's Z-axis in ARKit convention points BACKWARD, so the camera looks in -Z direction. |
| 191 | """ |
| 192 | if extrinsic is None: |
| 193 | return |
| 194 | |
| 195 | def draw_camera(T_head_camera: np.ndarray, label: str, cam_scale: float): |
| 196 | """Draw a single camera with its coordinate frame and viewing direction.""" |
| 197 | # T_head^camera transforms points from head to camera |
| 198 | # To get camera pose in head frame, we need the inverse: T_camera^head |
| 199 | T_camera_in_head = np.linalg.inv(T_head_camera) |
| 200 | |
| 201 | # Now transform from head frame to world frame |
| 202 | T_world_camera = head_matrix @ T_camera_in_head |
| 203 | |
| 204 | # Draw coordinate frame |
| 205 | draw_coordinate_frame(ax, T_world_camera, label, cam_scale) |
| 206 | |
| 207 | # Draw viewing direction (camera looks in -Z direction in ARKit convention) |
| 208 | origin = get_position(T_world_camera) |
| 209 | # -Z direction is the viewing direction |
| 210 | look_dir = -T_world_camera[:3, 2] # Negative Z axis |
| 211 | look_end = origin + look_dir * cam_scale * 2 |
| 212 | |
| 213 | # Draw a dashed cyan line for viewing direction |
| 214 | ax.plot([origin[0], look_end[0]], [origin[1], look_end[1]], [origin[2], look_end[2]], |
| 215 | 'c--', linewidth=1.5, alpha=0.7) |
| 216 | |
| 217 | # Get head-to-camera transform |
| 218 | left_h2c = extrinsic.get("leftHeadToCamera") |
| 219 | if left_h2c: |
| 220 | T_head_camera = matrix_from_array(left_h2c) |
| 221 | draw_camera(T_head_camera, "L-Cam", scale) |
| 222 | |
| 223 | # Right camera for stereo |
| 224 | right_h2c = extrinsic.get("rightHeadToCamera") |
| 225 | if right_h2c: |
| 226 | T_head_camera_r = matrix_from_array(right_h2c) |
| 227 | draw_camera(T_head_camera_r, "R-Cam", scale * 0.8) |
| 228 | |
| 229 | |
| 230 | def print_calibration_info(extrinsic: dict): |
no test coverage detected