1use nalgebra::Vector3;
2
3use super::transform::Transform;
4
5#[derive(Clone, Debug)]
7pub struct CameraIntrinsics {
8 pub fx: f64,
10 pub fy: f64,
12 pub cx: f64,
14 pub cy: f64,
16 pub width: usize,
18 pub height: usize,
20}
21
22impl CameraIntrinsics {
23 pub fn from_simple_intrinsic(
38 fx: f64,
39 fy: f64,
40 cx: f64,
41 cy: f64,
42 width: usize,
43 height: usize,
44 ) -> Self {
45 Self {
46 fx,
47 fy,
48 cx,
49 cy,
50 width,
51 height,
52 }
53 }
54
55 pub fn project(&self, point: &Vector3<f32>) -> (f32, f32) {
65 let z = point[2];
66 (
67 point[0] * self.fx as f32 / z + self.cx as f32,
68 point[1] * self.fy as f32 / z + self.cy as f32,
69 )
70 }
71
72 pub fn project_grad(&self, point: &Vector3<f32>) -> ((f32, f32), (f32, f32)) {
83 let z = point[2];
84 let zz = z * z;
85 (
86 (self.fx as f32 / z, -point[0] * self.fx as f32 / zz),
87 (self.fy as f32 / z, -point[1] * self.fy as f32 / zz),
88 )
89 }
90
91 pub fn backproject(&self, x: f32, y: f32, z: f32) -> Vector3<f32> {
103 Vector3::new(
104 (x - self.cx as f32) * z / self.fx as f32,
105 (y - self.cy as f32) * z / self.fy as f32,
106 z,
107 )
108 }
109
110 pub fn scale(&self, scale: f64) -> Self {
120 Self {
121 fx: self.fx * scale,
122 fy: self.fy * scale,
123 cx: self.cx * scale,
124 cy: self.cy * scale,
125 width: self.width,
126 height: self.height,
127 }
128 }
129
130 pub fn size(&mut self, width: usize, height: usize) {
131 self.width = width;
132 self.height = height;
133 }
134}
135#[derive(Clone, Debug)]
137pub struct PinholeCamera {
138 pub intrinsics: CameraIntrinsics,
139 pub camera_to_world: Transform,
140 world_to_camera: Transform,
141 width_f32: f32,
142 height_f32: f32,
143}
144
145impl PinholeCamera {
146 pub fn new(intrinsics: CameraIntrinsics, camera_to_world: Transform) -> Self {
157 let width_f32 = intrinsics.width as f32;
158 let height_f32 = intrinsics.height as f32;
159 Self {
160 intrinsics,
161 world_to_camera: camera_to_world.inverse(),
162 camera_to_world,
163 width_f32,
164 height_f32,
165 }
166 }
167
168 pub fn project(&self, point: &Vector3<f32>) -> (f32, f32, f32) {
178 let point = self.world_to_camera.transform_vector(point);
179 let (u, v) = self.intrinsics.project(&point);
180 (u, v, point[2])
181 }
182
183 pub fn project_to_image(&self, point: &Vector3<f32>) -> Option<(f32, f32, f32)> {
193 let (x, y, z) = self.project(point);
194 let (x, y) = (x.round(), y.round());
195
196 if x >= 0.0 && x < self.width_f32 && y >= 0.0 && y < self.height_f32 {
197 Some((x, y, z))
199 } else {
200 None
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use crate::transform::Transform;
208
209 #[test]
210 pub fn test_project() {
211 let camera = super::PinholeCamera::new(
212 super::CameraIntrinsics::from_simple_intrinsic(50.0, 50.0, 0.0, 0.0, 100, 100),
213 Transform::eye(),
214 );
215
216 let point = nalgebra::Vector3::new(1.0, 1.0, 1.0);
217 let (x, y, _) = camera.project(&point);
218 assert_eq!(x, 50.0);
219 assert_eq!(y, 50.0);
220
221 let point = nalgebra::Vector3::new(1.0, 1.5, 1.0);
222 let (x, y, _) = camera.project(&point);
223 assert_eq!(x, 50.0);
224 assert_eq!(y, 75.0);
225 }
226
227 #[test]
228 pub fn test_project_to_image() {
229 let camera = super::PinholeCamera::new(
230 super::CameraIntrinsics::from_simple_intrinsic(50.0, 50.0, 0.0, 0.0, 100, 100),
231 Transform::eye(),
232 );
233
234 let point = nalgebra::Vector3::new(1.0, 1.0, 1.0);
235 let (x, y, _) = camera.project_to_image(&point).unwrap();
236 assert_eq!(x, 50.0);
237 assert_eq!(y, 50.0);
238
239 let point = nalgebra::Vector3::new(1.0, 1.5, 1.0);
240 let (x, y, _) = camera.project_to_image(&point).unwrap();
241 assert_eq!(x, 50.0);
242 assert_eq!(y, 75.0);
243 }
244}