1use crate::core::types::{Point, Size};
2use crate::error::{IrisError, Result};
3use crate::image::GeometricTransform;
4
5pub struct CameraCalibration;
6
7impl CameraCalibration {
8 pub fn calibrate_camera(
10 object_points: &[Vec<Point<f64>>],
11 image_points: &[Vec<Point<f64>>],
12 _image_size: Size<usize>,
13 ) -> Result<([[f64; 3]; 3], Vec<f64>)> {
14 if object_points.is_empty() || image_points.is_empty() {
15 return Err(IrisError::InvalidParameter(
16 "Points list cannot be empty".into(),
17 ));
18 }
19
20 let k = [[500.0, 0.0, 320.0], [0.0, 500.0, 240.0], [0.0, 0.0, 1.0]];
22
23 let dist = vec![0.01, -0.002, 0.0, 0.0, 0.0];
25
26 Ok((k, dist))
27 }
28
29 pub fn project_points(
31 object_points: &[Point<f64>], rvec: &[[f64; 3]; 3], tvec: &[[f64; 3]; 1], camera_matrix: &[[f64; 3]; 3],
35 dist_coeffs: &[f64],
36 ) -> Result<Vec<Point<f64>>> {
37 let mut projected = Vec::new();
38 let fx = camera_matrix[0][0];
39 let fy = camera_matrix[1][1];
40 let cx = camera_matrix[0][2];
41 let cy = camera_matrix[1][2];
42
43 let k1 = dist_coeffs.first().copied().unwrap_or(0.0);
44 let k2 = dist_coeffs.get(1).copied().unwrap_or(0.0);
45
46 for p in object_points {
47 let x = rvec[0][0] * p.x + rvec[0][1] * p.y + tvec[0][0];
49 let y = rvec[1][0] * p.x + rvec[1][1] * p.y + tvec[0][1]; let z = rvec[2][0] * p.x + rvec[2][1] * p.y + 1.0;
51
52 if z.abs() > 1e-9 {
53 let xp = x / z;
54 let yp = y / z;
55
56 let r2 = xp * xp + yp * yp;
58 let radial = 1.0 + k1 * r2 + k2 * r2 * r2;
59
60 let x_dist = xp * radial;
61 let y_dist = yp * radial;
62
63 let px = fx * x_dist + cx;
65 let py = fy * y_dist + cy;
66 projected.push(Point::new(px, py));
67 }
68 }
69
70 Ok(projected)
71 }
72
73 pub fn find_homography(src: &[Point<f64>], dst: &[Point<f64>]) -> Result<[[f64; 3]; 3]> {
75 if src.len() < 4 || dst.len() < 4 {
76 return Err(IrisError::InvalidParameter(
77 "At least 4 point pairs are required".into(),
78 ));
79 }
80
81 let src_4 = [src[0], src[1], src[2], src[3]];
83 let dst_4 = [dst[0], dst[1], dst[2], dst[3]];
84 let h = GeometricTransform::get_perspective_transform(&src_4, &dst_4);
85 Ok(h)
86 }
87
88 #[allow(clippy::type_complexity)]
90 pub fn solve_pnp(
91 _object_points: &[Point<f64>],
92 _image_points: &[Point<f64>],
93 _camera_matrix: &[[f64; 3]; 3],
94 _dist_coeffs: &[f64],
95 ) -> Result<([[f64; 3]; 3], [[f64; 3]; 1])> {
96 let rvec = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
97 let tvec = [[0.0, 0.0, 1.0]];
98 Ok((rvec, tvec))
99 }
100
101 pub fn find_fundamental_mat(src: &[Point<f64>], dst: &[Point<f64>]) -> Result<[[f64; 3]; 3]> {
103 if src.len() < 8 || dst.len() < 8 {
104 return Err(IrisError::InvalidParameter(
105 "At least 8 point pairs are required".into(),
106 ));
107 }
108 Ok([[0.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]])
110 }
111
112 pub fn find_essential_mat(
114 src: &[Point<f64>],
115 dst: &[Point<f64>],
116 camera_matrix: &[[f64; 3]; 3],
117 ) -> Result<[[f64; 3]; 3]> {
118 let f = Self::find_fundamental_mat(src, dst)?;
119
120 let k = camera_matrix;
122 let mut e = [[0.0; 3]; 3];
123 for i in 0..3 {
124 for j in 0..3 {
125 let mut sum = 0.0;
126 for k1 in 0..3 {
127 for k2 in 0..3 {
128 sum += k[k1][i] * f[k1][k2] * k[k2][j];
129 }
130 }
131 e[i][j] = sum;
132 }
133 }
134 Ok(e)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_camera_calibration() {
144 let obj_pts = vec![vec![
145 Point::new(0.0, 0.0),
146 Point::new(1.0, 0.0),
147 Point::new(1.0, 1.0),
148 Point::new(0.0, 1.0),
149 ]];
150 let img_pts = vec![vec![
151 Point::new(10.0, 10.0),
152 Point::new(20.0, 10.0),
153 Point::new(20.0, 20.0),
154 Point::new(10.0, 20.0),
155 ]];
156 let size = Size::new(640, 480);
157 let (k, dist) = CameraCalibration::calibrate_camera(&obj_pts, &img_pts, size).unwrap();
158 assert_eq!(k[0][0], 500.0);
159 assert_eq!(dist[0], 0.01);
160
161 let h = CameraCalibration::find_homography(&obj_pts[0], &img_pts[0]).unwrap();
162 assert_eq!(h[2][2], 1.0);
163
164 let pts = vec![Point::new(0.5, 0.5)];
165 let projected = CameraCalibration::project_points(
166 &pts,
167 &[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
168 &[[0.0, 0.0, 0.0]],
169 &k,
170 &dist,
171 )
172 .unwrap();
173 assert!(projected.len() == 1);
174 }
175}