| Name | Message | Date |
|---|---|---|
| ๐ camera.rs | 5 hours ago | |
| ๐ lib.rs | 5 hours ago | |
| ๐ rig.rs | 5 hours ago | |
| ๐ source.rs | 5 hours ago | |
| ๐ splat.rs | 5 hours ago |
📄
rig/src/rig.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! The fixed 3-camera rig and the virtual camera steered between its //! cameras. use crate::camera::{Camera, CameraIntrinsics, CameraPose}; /// The physical rig: the Kinect (`center`, the depth source) flanked by /// two webcams (`left`, `right`). /// /// Extrinsics are known exactly from the offline calibration (see /// PLAN.md); for the synthetic dataset they are simply declared. #[derive(Debug, Clone, PartialEq)] pub struct Rig { pub left: Camera, pub center: Camera, pub right: Camera, } impl Rig { /// Iterate the rig cameras in order `left, center, right`. pub fn cameras(&self) -> [Camera; 3] { [self.left.clone(), self.center.clone(), self.right.clone()] } /// The virtual camera pose at position `t` between the side cameras: /// `t = 0` is the left camera, `t = 1` the right camera. /// /// `t` is clamped to `[0, 1]`. pub fn virtual_pose(&self, t: f32) -> CameraPose { let t = t.clamp(0.0, 1.0); self.left.pose.blend(&self.right.pose, t) } /// The full virtual camera at `t`, using the given intrinsics and /// resolution (normally the webcams': the virtual camera *is* a /// webcam placed where no real one sits). pub fn virtual_camera( &self, t: f32, intrinsics: CameraIntrinsics, resolution: glam::UVec2, ) -> Camera { Camera { id: "virtual".into(), pose: self.virtual_pose(t), intrinsics, resolution, } } } #[cfg(test)] mod tests { use super::*; use crate::camera::CameraIntrinsics; use glam::{uvec2, vec3}; /// A symmetric converging rig, like the real one: side cameras /// `ยฑbaseline/2` apart, all looking at a subject 2 m out. fn symmetric_rig(baseline: f32) -> Rig { let intrinsics = CameraIntrinsics { fx: 500.0, fy: 500.0, cx: 320.0, cy: 240.0, }; let make = |x: f32| Camera { id: "test".into(), pose: CameraPose::looking_at(vec3(x, 0.0, 0.0), vec3(0.0, 0.0, 2.0)), intrinsics, resolution: uvec2(640, 480), }; Rig { left: make(-baseline / 2.0), center: make(0.0), right: make(baseline / 2.0), } } #[test] fn virtual_pose_hits_the_side_cameras() { let rig = symmetric_rig(0.6); assert_eq!(rig.virtual_pose(0.0), rig.left.pose); assert_eq!(rig.virtual_pose(1.0), rig.right.pose); } #[test] fn virtual_pose_midpoint_is_center_for_symmetric_rig() { let rig = symmetric_rig(0.6); let mid = rig.virtual_pose(0.5); assert!(mid.position.distance(rig.center.pose.position) < 1e-6); // Orientation within a degree of the center camera. let dot = mid .rotation .normalize() .dot(rig.center.pose.rotation.normalize()); assert!(dot > (1.0_f32).cos().to_radians()); } #[test] fn virtual_pose_moves_monotonically_along_baseline() { let rig = symmetric_rig(1.0); let mut last_x = f32::MIN; for i in 0..=10 { let t = i as f32 / 10.0; let x = rig.virtual_pose(t).position.x; assert!(x >= last_x, "t={t} moved backwards"); last_x = x; } } #[test] fn virtual_pose_clamps_out_of_range() { let rig = symmetric_rig(0.6); assert_eq!(rig.virtual_pose(-2.0), rig.virtual_pose(0.0)); assert_eq!(rig.virtual_pose(7.0), rig.virtual_pose(1.0)); } #[test] fn virtual_camera_carries_intrinsics() { let rig = symmetric_rig(0.6); let intrinsics = CameraIntrinsics { fx: 600.0, fy: 600.0, cx: 320.0, cy: 240.0, }; let cam = rig.virtual_camera(0.25, intrinsics, uvec2(640, 480)); assert_eq!(cam.intrinsics, intrinsics); assert_eq!(cam.resolution, uvec2(640, 480)); assert_eq!(cam.pose, rig.virtual_pose(0.25)); } }