Skip to main content

fpm_rs/measurements/
manifest.rs

1use std::{
2    fs::File,
3    io::{BufReader, BufWriter},
4    path::{Path, PathBuf},
5};
6
7use serde::{Deserialize, Serialize};
8
9use crate::Result;
10
11use super::PreprocessingConfig;
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14#[serde(deny_unknown_fields)]
15/// Serializable specification for loading a measurement stack.
16pub struct MeasurementSpec {
17    pub frames: Vec<FrameSpec>,
18    #[serde(default)]
19    pub dark_frame: Option<PathBuf>,
20    #[serde(default)]
21    pub flat_field: Option<PathBuf>,
22    #[serde(default)]
23    pub background: Option<ImageSet>,
24    #[serde(default)]
25    pub mask: Option<ImageSet>,
26    #[serde(default)]
27    pub preprocessing: PreprocessingConfig,
28}
29
30impl MeasurementSpec {
31    pub fn new(frames: Vec<FrameSpec>) -> Self {
32        Self {
33            frames,
34            dark_frame: None,
35            flat_field: None,
36            background: None,
37            mask: None,
38            preprocessing: PreprocessingConfig::default(),
39        }
40    }
41
42    pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
43        let writer = BufWriter::new(File::create(path)?);
44        serde_json::to_writer_pretty(writer, self)?;
45        Ok(())
46    }
47
48    pub fn load(path: impl AsRef<Path>) -> Result<Self> {
49        let reader = BufReader::new(File::open(path)?);
50        Ok(serde_json::from_reader(reader)?)
51    }
52}
53
54#[derive(Clone, Debug, Serialize, Deserialize)]
55#[serde(deny_unknown_fields)]
56/// Path and acquisition metadata for one measurement frame.
57pub struct FrameSpec {
58    pub path: PathBuf,
59    #[serde(default)]
60    pub illumination_index: Option<usize>,
61    #[serde(default = "unit_value")]
62    pub exposure_time: f64,
63    #[serde(default = "unit_value")]
64    pub weight: f64,
65    #[serde(default)]
66    pub label: Option<String>,
67}
68
69impl FrameSpec {
70    pub fn new(path: impl Into<PathBuf>) -> Self {
71        Self {
72            path: path.into(),
73            illumination_index: None,
74            exposure_time: 1.0,
75            weight: 1.0,
76            label: None,
77        }
78    }
79}
80
81#[derive(Clone, Debug, Serialize, Deserialize)]
82#[serde(untagged)]
83/// A single image shared by all frames or one image per frame.
84pub enum ImageSet {
85    Single(PathBuf),
86    PerFrame(Vec<PathBuf>),
87}
88
89fn unit_value() -> f64 {
90    1.0
91}