pub mod functions;
pub mod geo;
pub mod interface;
pub mod pairs;
use crate::functions::{solve, HomographySolution};
use crate::geo::{Line, Point};
use crate::interface::{Matrix2x9, WithRestriction};
use crate::pairs::LinePair;
use nalgebra::{DMatrix, RealField, Scalar};
use num_traits::Float;
use crate::pairs::PointPair;
#[derive(Debug, Clone)]
pub struct HomographyRestrictions<T: Scalar> {
restrictions: Vec<Matrix2x9<T>>,
}
#[derive(Debug, Clone)]
pub struct HomographyComputation<T = f32> {
point_correspondences: Vec<PointPair<T>>,
line_correspondences: Vec<LinePair<T>>,
}
impl<T: Float + Scalar> HomographyComputation<T> {
pub fn new() -> Self {
HomographyComputation {
point_correspondences: Vec::new(),
line_correspondences: Vec::new(),
}
}
pub fn add_point_correspondence(&mut self, p1: Point<T>, p2: Point<T>) {
self.point_correspondences.push(PointPair { p1, p2 });
}
pub fn add_line_correspondence(&mut self, l1: Line<T>, l2: Line<T>) {
self.line_correspondences.push(LinePair { l1, l2 });
}
pub fn get_restrictions(&self) -> HomographyRestrictions<T> {
let mut restrictions = HomographyRestrictions {
restrictions: Vec::new(),
};
for pair in &self.point_correspondences {
restrictions.restrictions.push(pair.generate_restriction());
}
for pair in &self.line_correspondences {
restrictions.restrictions.push(pair.generate_restriction());
}
restrictions
}
}
impl<T: Scalar + Copy + num_traits::Zero + RealField> HomographyRestrictions<T> {
pub fn compute(&self) -> HomographySolution<T> {
let num_rows = self.restrictions.len() * 2;
let mut matrix = DMatrix::zeros(num_rows, 9);
for (i, m) in self.restrictions.iter().enumerate() {
matrix.set_row(i * 2, &m.row(0));
matrix.set_row(i * 2 + 1, &m.row(1));
}
solve(matrix)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_homography_computation() {
let hc = HomographyComputation::<f32>::new();
assert_eq!(hc.point_correspondences.len(), 0);
assert_eq!(hc.line_correspondences.len(), 0);
}
#[test]
fn test_add_point_correspondence() {
let mut hc = HomographyComputation::new();
let p1 = Point::new(1., 2.);
let p2 = Point::new(3., 4.);
hc.add_point_correspondence(p1, p2);
assert_eq!(hc.point_correspondences.len(), 1);
}
#[test]
fn test_add_line_correspondence() {
let mut hc = HomographyComputation::new();
let l1 = Line::new(1., 2., 3.);
let l2 = Line::new(4., 5., 6.);
hc.add_line_correspondence(l1, l2);
assert_eq!(hc.line_correspondences.len(), 1);
}
#[test]
fn test_get_restrictions() {
let mut hc = HomographyComputation::new();
let p1 = Point::new(1., 2.);
let p2 = Point::new(3., 4.);
let l1 = Line::new(1., 2., 3.);
let l2 = Line::new(4., 5., 6.);
hc.add_point_correspondence(p1, p2);
hc.add_line_correspondence(l1, l2);
let restrictions = hc.get_restrictions();
assert_eq!(restrictions.restrictions.len(), 2);
}
#[test]
fn test_compute_homography_solution() {
let mut hc = HomographyComputation::new();
let p1 = Point::new(148., 337.);
let p2 = Point::new(131., 516.);
let p3 = Point::new(321., 486.);
let p4 = Point::new(332., 370.);
let p1p = Point::new(0., 0.);
let p2p = Point::new(0., 60.);
let p3p = Point::new(80., 60.);
let p4p = Point::new(80., 0.);
let line1 = Line::from_points(&p1, &p2);
let line1p = Line::from_points(&p1p, &p2p);
hc.add_point_correspondence(p1, p1p);
hc.add_point_correspondence(p2, p2p);
hc.add_point_correspondence(p3, p3p);
hc.add_point_correspondence(p4, p4p);
hc.add_line_correspondence(line1, line1p);
let restrictions = hc.get_restrictions();
let solution = restrictions.compute();
assert_eq!(solution.matrix.nrows(), 3);
assert_eq!(solution.matrix.ncols(), 3);
}
}