Skip to main content

braidz_types/
lib.rs

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