Spaces:
Running on Zero
Running on Zero
| """Camera angle data structures for Fibo Edit.""" | |
| from dataclasses import dataclass | |
| from enum import Enum | |
| class View(Enum): | |
| """Camera view angles""" | |
| BACK_VIEW = "back view" | |
| BACK_LEFT_QUARTER = "back-left quarter view" | |
| BACK_RIGHT_QUARTER = "back-right quarter view" | |
| FRONT_VIEW = "front view" | |
| FRONT_LEFT_QUARTER = "front-left quarter view" | |
| FRONT_RIGHT_QUARTER = "front-right quarter view" | |
| LEFT_SIDE = "left side view" | |
| RIGHT_SIDE = "right side view" | |
| class Shot(Enum): | |
| """ | |
| Camera shot angles (measured from horizontal/eye-level as 0 degrees) | |
| - ELEVATED: 45-60 degrees above subject (moderately elevated) | |
| - EYE_LEVEL: 0 degrees (horizontal with subject) | |
| - HIGH_ANGLE: 60-90 degrees above subject (steep overhead, bird's eye) | |
| - LOW_ANGLE: Below eye level (looking up at subject) | |
| """ | |
| ELEVATED = "elevated shot" | |
| EYE_LEVEL = "eye-level shot" | |
| HIGH_ANGLE = "high-angle shot" | |
| LOW_ANGLE = "low-angle shot" | |
| class Zoom(Enum): | |
| """Camera zoom levels""" | |
| CLOSE_UP = "close-up" | |
| MEDIUM = "medium shot" | |
| WIDE = "wide shot" | |
| class AngleInstruction: | |
| view: View | |
| shot: Shot | |
| zoom: Zoom | |
| def __str__(self): | |
| return f"<sks> {self.view.value} {self.shot.value} {self.zoom.value}" | |
| def from_camera_params(cls, rotation: float, tilt: float, zoom: float) -> "AngleInstruction": | |
| """ | |
| Create an AngleInstruction from camera parameters. | |
| Args: | |
| rotation: Horizontal rotation in degrees (-180 to 180) | |
| -180/180: back view, -90: left view, 0: front view, 90: right view | |
| tilt: Vertical tilt (-1 to 1) | |
| -1 to -0.33: low-angle shot | |
| -0.33 to 0.33: eye-level shot | |
| 0.33 to 0.66: elevated shot | |
| 0.66 to 1: high-angle shot | |
| zoom: Zoom level (0 to 10) | |
| 0-3.33: wide shot | |
| 3.33-6.66: medium shot | |
| 6.66-10: close-up | |
| Returns: | |
| AngleInstruction instance | |
| """ | |
| # Map rotation to View | |
| # Normalize rotation to -180 to 180 range | |
| rotation = rotation % 360 | |
| if rotation > 180: | |
| rotation -= 360 | |
| # Determine view based on rotation | |
| if -157.5 <= rotation < -112.5: | |
| view = View.BACK_LEFT_QUARTER | |
| elif -112.5 <= rotation < -67.5: | |
| view = View.LEFT_SIDE | |
| elif -67.5 <= rotation < -22.5: | |
| view = View.FRONT_LEFT_QUARTER | |
| elif -22.5 <= rotation < 22.5: | |
| view = View.FRONT_VIEW | |
| elif 22.5 <= rotation < 67.5: | |
| view = View.FRONT_RIGHT_QUARTER | |
| elif 67.5 <= rotation < 112.5: | |
| view = View.RIGHT_SIDE | |
| elif 112.5 <= rotation < 157.5: | |
| view = View.BACK_RIGHT_QUARTER | |
| else: # 157.5 to 180 or -180 to -157.5 | |
| view = View.BACK_VIEW | |
| # Map tilt to Shot | |
| if tilt < -0.33: | |
| shot = Shot.LOW_ANGLE | |
| elif tilt < 0.33: | |
| shot = Shot.EYE_LEVEL | |
| elif tilt < 0.66: | |
| shot = Shot.ELEVATED | |
| else: | |
| shot = Shot.HIGH_ANGLE | |
| # Map zoom to Zoom | |
| if zoom < 3.33: | |
| zoom_level = Zoom.WIDE | |
| elif zoom < 6.66: | |
| zoom_level = Zoom.MEDIUM | |
| else: | |
| zoom_level = Zoom.CLOSE_UP | |
| return cls(view=view, shot=shot, zoom=zoom_level) | |