scan_core/transform/
perspective.rs1use crate::Point;
2
3pub struct PerspectiveTransform {
6 coeffs: [f32; 9],
7 coeffs_inv: [f32; 9],
8}
9
10impl PerspectiveTransform {
11 pub fn new(src: &[Point], dst: &[Point]) -> Option<Self> {
12 if src.len() < 4 || dst.len() != src.len() {
13 return None;
14 }
15
16 let coeffs = get_normalization_coefficients(src, dst, false)?;
17 let coeffs_inv = get_normalization_coefficients(src, dst, true)?;
18
19 Some(Self {
20 coeffs,
21 coeffs_inv,
22 })
23 }
24
25 pub fn transform(&self, x: f32, y: f32) -> Point {
26 let c = self.coeffs;
27 let den = c[6] * x + c[7] * y + 1.0;
28 Point {
29 x: (c[0] * x + c[1] * y + c[2]) / den,
30 y: (c[3] * x + c[4] * y + c[5]) / den,
31 }
32 }
33
34 pub fn transform_inverse(&self, x: f32, y: f32) -> Point {
35 let c = self.coeffs_inv;
36 let den = c[6] * x + c[7] * y + 1.0;
37 Point {
38 x: (c[0] * x + c[1] * y + c[2]) / den,
39 y: (c[3] * x + c[4] * y + c[5]) / den,
40 }
41 }
42}
43
44fn get_normalization_coefficients(src: &[Point], dst: &[Point], is_inverse: bool) -> Option<[f32; 9]> {
45 let (src, dst) = if is_inverse { (dst, src) } else { (src, dst) };
46 let n = src.len();
47
48 let mut a = [[0.0f32; 8]; 8];
55 let mut y = [0.0f32; 8];
56
57 for i in 0..n {
58 let sx = src[i].x;
59 let sy = src[i].y;
60 let dx = dst[i].x;
61 let dy = dst[i].y;
62
63 let r0 = [sx, sy, 1.0, 0.0, 0.0, 0.0, -dx * sx, -dx * sy];
68 let r1 = [0.0, 0.0, 0.0, sx, sy, 1.0, -dy * sx, -dy * sy];
69
70 for row in 0..8 {
72 for col in 0..8 {
73 a[row][col] += r0[row] * r0[col] + r1[row] * r1[col];
74 }
75 y[row] += r0[row] * dx + r1[row] * dy;
76 }
77 }
78
79 let mut matrix = [[0.0f32; 9]; 8];
81 for i in 0..8 {
82 for j in 0..8 {
83 matrix[i][j] = a[i][j];
84 }
85 matrix[i][8] = y[i];
86 }
87
88 let size = 8;
90 for i in 0..size {
91 let mut pivot_row = i;
92 for j in i + 1..size {
93 if matrix[j][i].abs() > matrix[pivot_row][i].abs() {
94 pivot_row = j;
95 }
96 }
97 matrix.swap(i, pivot_row);
98 let pivot = matrix[i][i];
99 if pivot.abs() < 1e-9 { return None; }
100
101 for j in i..=size { matrix[i][j] /= pivot; }
102 for k in 0..size {
103 if k != i {
104 let factor = matrix[k][i];
105 for j in i..=size { matrix[k][j] -= factor * matrix[i][j]; }
106 }
107 }
108 }
109
110 let mut res = [0.0; 9];
111 for i in 0..8 {
112 res[i] = matrix[i][8];
113 }
114 res[8] = 1.0;
115
116 Some(res)
117}