braidz_types/
lib.rs

1//! core type definitions for braidz files
2use std::collections::BTreeMap;
3
4use serde::{Deserialize, Serialize};
5
6use braid_types::{CamNum, TrackingParams};
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct BraidMetadata {
10    // changes to this struct should update BraidMetadataSchemaTag
11    pub schema: u16, // BraidMetadataSchemaTag
12    pub git_revision: String,
13    pub original_recording_time: Option<chrono::DateTime<chrono::Local>>,
14    pub save_empty_data2d: bool,
15    /// The name of the saving program.
16    ///
17    /// This is new in schema 3 and the default value
18    /// when loading old files is "".
19    #[serde(default = "default_saving_program_name")]
20    pub saving_program_name: String,
21}
22
23fn default_saving_program_name() -> String {
24    "".to_string()
25}
26
27/// A summary of a braidz file (or braid directory).
28///
29/// Even for a many-gigabyte braidz file, this is expected to allocate
30/// megabytes, but not gigabytes, of memory and will contain a summary of the
31/// data such as filename, calibration, images, reconstruction quality metrics,
32/// and so on. It will not load the entire braidz file to memory.
33#[derive(Debug, Serialize, Deserialize, Clone)]
34pub struct BraidzSummary {
35    /// The filename of the braidz file or braid directory.
36    pub filename: String,
37    /// Number of bytes in a braidz file. (This is meaningless for braid directories.)
38    pub filesize: u64,
39    pub metadata: BraidMetadata,
40    pub cam_info: CamInfo,
41    pub expected_fps: f64,
42    pub calibration_info: Option<CalibrationSummary>,
43    pub data2d_summary: Option<Data2dSummary>,
44    pub kalman_estimates_summary: Option<KalmanEstimatesSummary>,
45    pub reconstruct_latency_usec_summary: Option<HistogramSummary>,
46    pub reprojection_distance_100x_pixels_summary: Option<HistogramSummary>,
47}
48
49/// A summary of a multi-camera calibration
50#[derive(Debug, Serialize, Deserialize, Clone)]
51pub struct CalibrationSummary {
52    /// If `Some(n)`, material with refractive index `n` at z<0.
53    pub water: Option<f64>,
54    /// All the cameras in this system.
55    pub cameras: Vec<CameraSummary>,
56}
57
58impl From<CalibrationInfo> for CalibrationSummary {
59    fn from(orig: CalibrationInfo) -> Self {
60        Self {
61            water: orig.water,
62            cameras: orig
63                .cameras
64                .cams_by_name()
65                .iter()
66                .map(|(name, cam)| CameraSummary::new(name, cam))
67                .collect(),
68        }
69    }
70}
71
72/// A summary of a camera calibration
73#[derive(Debug, Serialize, Deserialize, Clone)]
74pub struct CameraSummary {
75    pub name: String,
76    pub camera_center: (f64, f64, f64),
77    pub fx: f64,
78    pub fy: f64,
79    pub distortion: Option<Vec<f64>>,
80}
81
82impl CameraSummary {
83    pub fn new(name: &str, cam: &braid_mvg::Camera<f64>) -> Self {
84        let cc = cam.extrinsics().camcenter();
85        let fx = cam.intrinsics().fx();
86        let fy = cam.intrinsics().fy();
87        let d = &cam.intrinsics().distortion;
88        let distortion = if d.is_linear() {
89            None
90        } else {
91            Some(d.opencv_vec().iter().map(Clone::clone).collect())
92        };
93        Self {
94            name: name.into(),
95            camera_center: (cc[0], cc[1], cc[2]),
96            distortion,
97            fx,
98            fy,
99        }
100    }
101}
102
103#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
104pub struct CamInfo {
105    pub camn2camid: BTreeMap<CamNum, String>,
106    pub camid2camn: BTreeMap<String, CamNum>,
107}
108
109#[derive(Debug, Serialize, Deserialize, Clone)]
110pub struct HistogramSummary {
111    /// the number of points in the histogram
112    pub len: u64,
113    pub mean: f64,
114    pub min: u64,
115    pub max: u64,
116}
117
118#[derive(Debug, Serialize, Deserialize, Clone)]
119pub struct CalibrationInfo {
120    /// If `Some(n)`, material with refractive index `n` at z<0.
121    pub water: Option<f64>,
122    /// All the cameras in this system.
123    pub cameras: braid_mvg::MultiCameraSystem<f64>,
124}
125
126#[derive(Debug, Serialize, Deserialize, Clone)]
127pub struct Data2dSummary {
128    pub num_cameras_with_data: u16,
129    pub num_rows: u64,
130    pub frame_limits: [u64; 2],
131    pub time_limits: [chrono::DateTime<chrono::Utc>; 2],
132}
133
134#[derive(Debug, Serialize, Deserialize, Clone)]
135pub struct KalmanEstimatesSummary {
136    pub num_trajectories: u32,
137    pub x_limits: [f64; 2],
138    pub y_limits: [f64; 2],
139    pub z_limits: [f64; 2],
140    pub num_rows: u64,
141    pub tracking_parameters: TrackingParams,
142    /// The sum of total distance in all trajectories.
143    pub total_distance: f64,
144}
145
146pub fn camera_name_from_filename<P: AsRef<std::path::Path>>(
147    full_path: P,
148) -> (String, Option<String>) {
149    let filename = full_path
150        .as_ref()
151        .file_name()
152        .unwrap()
153        .to_os_string()
154        .to_str()
155        .unwrap()
156        .to_string();
157
158    const MOVIE_REGEXP: &str = r"^movie\d{8}_\d{6}(?:.?\d*)_(.*).(?:mp4|mkv|fmf|h264|fmf\.gz)$";
159    let movie_re = regex::Regex::new(MOVIE_REGEXP).unwrap();
160    let cam_from_filename = movie_re.captures(&filename).map(|caps| {
161        // get the raw camera name
162        caps.get(1).unwrap().as_str().to_string()
163    });
164    (filename, cam_from_filename)
165}
166
167#[test]
168fn test_cam_from_filename() {
169    // prior to adding subseconds
170    let fname1 = "dir1/movie20211108_084523_Basler-22445994.mp4";
171    let (_, cam) = camera_name_from_filename(fname1);
172    assert_eq!(cam, Some("Basler-22445994".to_string()));
173
174    // with subseconds
175    let fname2 = "movie20240302_144852.000002145_Basler-40454395.mp4";
176    let (_, cam) = camera_name_from_filename(fname2);
177    assert_eq!(cam, Some("Basler-40454395".to_string()));
178}