use nalgebra::Affine2;
use crate::core::multires;
use crate::misc::type_aliases::{Float, Iso3, Mat3, Point2, Point3, Vec3};
#[derive(PartialEq, Debug, Clone)]
pub struct Camera {
pub intrinsics: Intrinsics,
pub extrinsics: Extrinsics,
}
impl Camera {
pub fn new(intrinsics: Intrinsics, extrinsics: Extrinsics) -> Self {
Self {
intrinsics,
extrinsics,
}
}
pub fn project(&self, point: Point3) -> Vec3 {
self.intrinsics
.project(extrinsics::project(&self.extrinsics, point))
}
pub fn back_project(&self, point: Point2, depth: Float) -> Point3 {
extrinsics::back_project(&self.extrinsics, self.intrinsics.back_project(point, depth))
}
pub fn multi_res(self, n: usize) -> Vec<Self> {
multires::limited_sequence(n, self, |cam| Some(cam.half_res()))
}
pub fn half_res(&self) -> Self {
Self::new(self.intrinsics.half_res(), self.extrinsics)
}
}
pub type Extrinsics = Iso3;
pub mod extrinsics {
use super::*;
pub fn project(pose: &Extrinsics, point: Point3) -> Point3 {
pose.rotation.inverse() * (pose.translation.inverse() * point)
}
pub fn back_project(pose: &Extrinsics, point: Point3) -> Point3 {
pose * point
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct Intrinsics {
pub principal_point: (Float, Float),
pub focal: (Float, Float),
pub skew: Float,
}
impl Intrinsics {
#[rustfmt::skip]
pub fn matrix(&self) -> Affine2<Float> {
Affine2::from_matrix_unchecked(Mat3::new(
self.focal.0, self.skew, self.principal_point.0,
0.0, self.focal.1, self.principal_point.1,
0.0, 0.0, 1.0,
))
}
pub fn multi_res(self, n: usize) -> Vec<Self> {
multires::limited_sequence(n, self, |intrinsics| Some(intrinsics.half_res()))
}
pub fn half_res(&self) -> Self {
let (cx, cy) = self.principal_point;
let (fx, fy) = self.focal;
Self {
principal_point: ((cx + 0.5) / 2.0 - 0.5, (cy + 0.5) / 2.0 - 0.5),
focal: (0.5 * fx, 0.5 * fy),
skew: self.skew,
}
}
pub fn project(&self, point: Point3) -> Vec3 {
Vec3::new(
self.focal.0 * point[0] + self.skew * point[1] + self.principal_point.0 * point[2],
self.focal.1 * point[1] + self.principal_point.1 * point[2],
point[2],
)
}
pub fn back_project(&self, point: Point2, depth: Float) -> Point3 {
let z = depth;
let y = (point[1] - self.principal_point.1) * z / self.focal.1;
let x = ((point[0] - self.principal_point.0) * z - self.skew * y) / self.focal.0;
Point3::new(x, y, z)
}
}