# -----------------------------------------------------------------------------
# This file was autogenerated by symforce from template:
# cam_package/CLASS.py.jinja
# Do NOT modify by hand.
# -----------------------------------------------------------------------------
from __future__ import annotations
import typing as T
import numpy
from .ops import orthographic_camera_cal as ops
[docs]class OrthographicCameraCal(object):
"""
Autogenerated Python implementation of :py:class:`symforce.cam.orthographic_camera_cal.OrthographicCameraCal`.
Orthographic camera model with four parameters [fx, fy, cx, cy].
It would be possible to define orthographic cameras with only two parameters [fx, fy] but we
keep the [cx, cy] parameters for consistency with the CameraCal interface.
The orthographic camera model can be thought of as a special case of the LinearCameraCal model,
where (x,y,z) in the camera frame projects to pixel (x * fx + cx, y * fy + cy).
The z-coordinate of the point is ignored in the projection, except that only points with
positive z-coordinates are considered valid.
Because this is a noncentral camera model, the camera_ray_from_pixel function is not implemented.
"""
__slots__ = ["data"]
# This is because of an issue where mypy doesn't recognize attributes defined in __slots__
# See https://github.com/python/mypy/issues/5941
if T.TYPE_CHECKING:
data: list[float] = []
def __init__(
self,
focal_length: T.Union[T.Sequence[float], numpy.ndarray],
principal_point: T.Union[T.Sequence[float], numpy.ndarray],
) -> None:
self.data: list[float] = []
if isinstance(focal_length, numpy.ndarray):
if focal_length.shape in {(2, 1), (1, 2)}:
focal_length = focal_length.flatten()
elif focal_length.shape != (2,):
raise IndexError(
"Expected focal_length to be a vector of length 2; instead had shape {}".format(
focal_length.shape
)
)
elif len(focal_length) != 2:
raise IndexError(
"Expected focal_length to be a sequence of length 2, was instead length {}.".format(
len(focal_length)
)
)
if isinstance(principal_point, numpy.ndarray):
if principal_point.shape in {(2, 1), (1, 2)}:
principal_point = principal_point.flatten()
elif principal_point.shape != (2,):
raise IndexError(
"Expected principal_point to be a vector of length 2; instead had shape {}".format(
principal_point.shape
)
)
elif len(principal_point) != 2:
raise IndexError(
"Expected principal_point to be a sequence of length 2, was instead length {}.".format(
len(principal_point)
)
)
self.data.extend(focal_length)
self.data.extend(principal_point)
def __repr__(self) -> str:
return "<{} {}>".format(self.__class__.__name__, self.data)
# --------------------------------------------------------------------------
# CameraOps
# --------------------------------------------------------------------------
[docs] def focal_length(self: OrthographicCameraCal) -> numpy.ndarray:
"""
Return the focal length.
"""
return ops.CameraOps.focal_length(self)
[docs] def principal_point(self: OrthographicCameraCal) -> numpy.ndarray:
"""
Return the principal point.
"""
return ops.CameraOps.principal_point(self)
[docs] def pixel_from_camera_point(
self: OrthographicCameraCal, point: numpy.ndarray, epsilon: float
) -> tuple[numpy.ndarray, float]:
"""
Project a 3D point in the camera frame into 2D pixel coordinates.
Returns:
pixel: (x, y) coordinate in pixels if valid
is_valid: 1 if the operation is within bounds else 0
"""
return ops.CameraOps.pixel_from_camera_point(self, point, epsilon)
[docs] def pixel_from_camera_point_with_jacobians(
self: OrthographicCameraCal, point: numpy.ndarray, epsilon: float
) -> tuple[numpy.ndarray, float, numpy.ndarray, numpy.ndarray]:
"""
Project a 3D point in the camera frame into 2D pixel coordinates.
Returns:
pixel: (x, y) coordinate in pixels if valid
is_valid: 1 if the operation is within bounds else 0
pixel_D_cal: Derivative of pixel with respect to intrinsic calibration parameters
pixel_D_point: Derivative of pixel with respect to point
"""
return ops.CameraOps.pixel_from_camera_point_with_jacobians(self, point, epsilon)
# --------------------------------------------------------------------------
# StorageOps concept
# --------------------------------------------------------------------------
[docs] @staticmethod
def storage_dim() -> int:
return 4
[docs] def to_storage(self) -> list[float]:
return list(self.data)
[docs] @classmethod
def from_storage(cls, vec: T.Sequence[float]) -> OrthographicCameraCal:
instance = cls.__new__(cls)
if isinstance(vec, list):
instance.data = vec
else:
instance.data = list(vec)
if len(vec) != cls.storage_dim():
raise ValueError(
"{} has storage dim {}, got {}.".format(cls.__name__, cls.storage_dim(), len(vec))
)
return instance
# --------------------------------------------------------------------------
# LieGroupOps concept
# --------------------------------------------------------------------------
[docs] @staticmethod
def tangent_dim() -> int:
return 4
[docs] @classmethod
def from_tangent(cls, vec: numpy.ndarray, epsilon: float = 1e-8) -> OrthographicCameraCal:
if len(vec) != cls.tangent_dim():
raise ValueError(
"Vector dimension ({}) not equal to tangent space dimension ({}).".format(
len(vec), cls.tangent_dim()
)
)
return ops.LieGroupOps.from_tangent(vec, epsilon)
[docs] def to_tangent(self, epsilon: float = 1e-8) -> numpy.ndarray:
return ops.LieGroupOps.to_tangent(self, epsilon)
[docs] def retract(self, vec: numpy.ndarray, epsilon: float = 1e-8) -> OrthographicCameraCal:
if len(vec) != self.tangent_dim():
raise ValueError(
"Vector dimension ({}) not equal to tangent space dimension ({}).".format(
len(vec), self.tangent_dim()
)
)
return ops.LieGroupOps.retract(self, vec, epsilon)
[docs] def local_coordinates(self, b: OrthographicCameraCal, epsilon: float = 1e-8) -> numpy.ndarray:
return ops.LieGroupOps.local_coordinates(self, b, epsilon)
[docs] def interpolate(
self, b: OrthographicCameraCal, alpha: float, epsilon: float = 1e-8
) -> OrthographicCameraCal:
return ops.LieGroupOps.interpolate(self, b, alpha, epsilon)
# --------------------------------------------------------------------------
# General Helpers
# --------------------------------------------------------------------------
def __eq__(self, other: T.Any) -> bool:
if isinstance(other, OrthographicCameraCal):
return self.data == other.data
else:
return False