Single camera state in world coordinates.
| 25 | # --------------------------------------------------------------------------- |
| 26 | |
| 27 | class Camera: |
| 28 | """Single camera state in world coordinates.""" |
| 29 | |
| 30 | __slots__ = ('eye', 'center', 'up', 'fov_deg') |
| 31 | |
| 32 | def __init__(self, eye: np.ndarray, center: np.ndarray, |
| 33 | up: np.ndarray, fov_deg: float = 60.0): |
| 34 | self.eye = np.asarray(eye, dtype=np.float32) |
| 35 | self.center = np.asarray(center, dtype=np.float32) |
| 36 | self.up = np.asarray(up, dtype=np.float32) |
| 37 | self.fov_deg = fov_deg |
| 38 | |
| 39 | def w2c(self) -> np.ndarray: |
| 40 | """W2C (4x4) in OpenCV convention. Rows of R: [right, down, forward].""" |
| 41 | return lookat(self.eye, self.center, self.up) |
| 42 | |
| 43 | @property |
| 44 | def R_cw(self) -> np.ndarray: |
| 45 | return self.w2c()[:3, :3] |
| 46 | |
| 47 | @property |
| 48 | def t_cw(self) -> np.ndarray: |
| 49 | return self.w2c()[:3, 3] |
| 50 | |
| 51 | def fov_intrinsics(self, render_w: int, render_h: int) -> Tuple[float, float, float, float]: |
| 52 | """Derive pinhole intrinsics (fx, fy, cx, cy) from vertical FOV.""" |
| 53 | fov_rad = np.radians(self.fov_deg) |
| 54 | fy = render_h / (2.0 * np.tan(fov_rad / 2.0)) |
| 55 | fx = fy |
| 56 | return fx, fy, render_w / 2.0, render_h / 2.0 |
| 57 | |
| 58 | def to_dict(self) -> dict: |
| 59 | return { |
| 60 | 'eye': self.eye.tolist(), |
| 61 | 'center': self.center.tolist(), |
| 62 | 'up': self.up.tolist(), |
| 63 | 'fov': self.fov_deg, |
| 64 | } |
| 65 | |
| 66 | @classmethod |
| 67 | def from_dict(cls, d: dict) -> 'Camera': |
| 68 | return cls(d['eye'], d['center'], d['up'], d.get('fov', 60.0)) |
| 69 | |
| 70 | def __getstate__(self): |
| 71 | return {s: getattr(self, s) for s in self.__slots__} |
| 72 | |
| 73 | def __setstate__(self, state): |
| 74 | for s in self.__slots__: |
| 75 | setattr(self, s, state[s]) |
| 76 | |
| 77 | |
| 78 | # --------------------------------------------------------------------------- |
no outgoing calls
no test coverage detected