align3d/io/dataset/
slamtb.rs1use std::path::{Path, PathBuf};
2
3use super::core::{DatasetError, RgbdDataset};
4use crate::{
5 camera::CameraIntrinsics,
6 image::{IntoArray3, RgbdFrame, RgbdImage},
7 trajectory::Trajectory,
8 transform::Transform,
9};
10
11use nshare::ToNdarray2;
12
13pub struct SlamTbDataset {
14 cameras: Vec<CameraIntrinsics>,
15 extrinsic_cameras: Vec<Transform>,
16 rgb_images: Vec<String>,
17 depth_images: Vec<String>,
18 depth_scales: Vec<f64>,
19 base_dir: PathBuf,
20}
21
22mod json {
23 use serde_derive::Deserialize;
24 #[derive(Deserialize, Debug)]
25 pub struct KCam {
26 pub matrix: Vec<Vec<f64>>,
27 #[serde(rename = "undist_coeff")]
28 pub _undist_coeff: Vec<f32>,
29 pub image_size: (i32, i32),
30 }
31
32 #[derive(Deserialize, Debug)]
33 pub struct RTCam {
34 pub matrix: Vec<Vec<f32>>,
35 }
36
37 #[derive(Deserialize, Debug)]
38 pub struct Info {
39 pub kcam: KCam,
40 pub depth_scale: f64,
41 pub depth_bias: f64,
42 pub depth_max: f64,
43 pub rt_cam: RTCam,
44 pub timestamp: f64,
45 }
46
47 #[derive(Deserialize, Debug)]
48 pub struct Frame {
49 pub info: Info,
50 pub depth_image: String,
51 pub rgb_image: String,
52 }
53
54 #[derive(Deserialize, Debug)]
55 pub struct Document {
56 pub root: Vec<Frame>,
57 }
58}
59
60impl SlamTbDataset {
61 pub fn load(base_dir: &str) -> Result<Self, DatasetError> {
62 let buffer = std::io::BufReader::new(std::fs::File::open(
63 Path::new(base_dir).join("frames.json"),
64 )?);
65 serde_json::from_reader(buffer)
66 .map(|doc: json::Document| {
67 let mut cameras = Vec::new();
68 let mut extrinsic_cameras = Vec::new();
69 let mut rgb_images = Vec::new();
70 let mut depth_images = Vec::new();
71 let mut depth_scales = Vec::new();
72
73 for frame in doc.root.iter() {
74 let info = &frame.info;
75
76 let fx = info.kcam.matrix[0][0];
77 let fy = info.kcam.matrix[1][1];
78 let cx = info.kcam.matrix[0][2];
79 let cy = info.kcam.matrix[1][2];
80
81 let extrinsics = if info.rt_cam.matrix.len() == 4 {
82 Transform::from_matrix4(&nalgebra::Matrix4::<f32>::from_fn(|r, c| {
83 info.rt_cam.matrix[r][c]
84 }))
85 } else {
86 Transform::eye()
87 };
88
89 cameras.push(CameraIntrinsics::from_simple_intrinsic(
90 fx,
91 fy,
92 cx,
93 cy,
94 info.kcam.image_size.0 as usize,
95 info.kcam.image_size.1 as usize,
96 ));
97 extrinsic_cameras.push(extrinsics);
98 rgb_images.push(frame.rgb_image.clone());
99 depth_images.push(frame.depth_image.clone());
100 depth_scales.push(info.depth_scale);
101 }
102 Self {
103 cameras,
104 extrinsic_cameras,
105 rgb_images,
106 depth_images,
107 depth_scales,
108 base_dir: PathBuf::from(base_dir),
109 }
110 })
111 .map_err(|err| DatasetError::Parser(err.to_string()))
112 }
113}
114
115impl RgbdDataset for SlamTbDataset {
116 fn len(&self) -> usize {
117 self.rgb_images.len().min(self.depth_images.len())
118 }
119
120 fn is_empty(&self) -> bool {
121 self.len() == 0
122 }
123
124 fn get(&self, index: usize) -> Result<RgbdFrame, DatasetError> {
125 let rgb_image = image::open(self.base_dir.join(&self.rgb_images[index]))?
126 .into_rgb8()
127 .into_array3();
128
129 let rgb_image = rgb_image.as_standard_layout().into_owned();
130 let depth_image = image::open(self.base_dir.join(&self.depth_images[index]))?
131 .into_luma16()
132 .into_ndarray2();
133 Ok(RgbdFrame::new(
134 self.cameras[index].clone(),
135 RgbdImage::with_depth_scale(rgb_image, depth_image, self.depth_scales[index]),
136 Some(self.extrinsic_cameras[index].clone()),
137 ))
138 }
139
140 fn trajectory(&self) -> Option<Trajectory> {
141 let mut trajectory = Trajectory::default();
142 for (i, cam) in self.extrinsic_cameras.iter().enumerate() {
143 trajectory.push(cam.clone(), i as f32);
144 }
145 Some(trajectory)
146 }
147
148 fn camera(&self, index: usize) -> (CameraIntrinsics, Option<Transform>) {
149 (
150 self.cameras[index].clone(),
151 Some(self.extrinsic_cameras[index].clone()),
152 )
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn test_load() {
162 let rgbd_dataset = SlamTbDataset::load("tests/data/rgbd/sample1").unwrap();
163
164 let (camera, image, _) = rgbd_dataset.get(0).unwrap().into_parts();
165
166 assert_eq!(camera.fx, 544.4732666015625);
167 assert_eq!(camera.fy, 544.4732666015625);
168 assert_eq!(camera.cx, 320.0);
169 assert_eq!(camera.cy, 240.0);
170
171 assert_eq!(image.height(), 480);
172 assert_eq!(image.width(), 640);
173 }
174}