Skip to main content

outline/
config.rs

1#[cfg(any(feature = "backend-ort", feature = "backend-rten"))]
2use std::path::{Path, PathBuf};
3
4#[cfg(any(feature = "backend-ort", feature = "backend-rten"))]
5use image::imageops::FilterType;
6
7/// Environment variable name for specifying the model path.
8pub const ENV_MODEL_PATH: &str = "OUTLINE_MODEL_PATH";
9
10/// Default model path used when no explicit path is provided.
11///
12/// This is the fallback when neither `--model` nor `OUTLINE_MODEL_PATH` is set.
13/// By default it points to `model.onnx` in the current working directory.
14pub const DEFAULT_MODEL_PATH: &str = "model.onnx";
15
16/// Inference backend used to execute the model.
17#[cfg(any(feature = "backend-ort", feature = "backend-rten"))]
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19#[non_exhaustive]
20pub enum InferenceBackend {
21    /// Use ONNX Runtime through the `ort` crate.
22    #[cfg(feature = "backend-ort")]
23    #[default]
24    Ort,
25    /// Use the pure Rust RTen backend.
26    #[cfg(feature = "backend-rten")]
27    #[cfg_attr(not(feature = "backend-ort"), default)]
28    Rten,
29}
30
31/// Height and width used to override the model-declared input size.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct ModelInputSize {
34    height: usize,
35    width: usize,
36}
37
38impl ModelInputSize {
39    /// Creates a height/width override for model input tensors.
40    ///
41    /// # Panics
42    ///
43    /// Panics if either dimension is zero.
44    pub fn new(height: usize, width: usize) -> Self {
45        assert!(height > 0 && width > 0, "model input size must be non-zero");
46        Self { height, width }
47    }
48
49    /// Input height in pixels.
50    pub fn height(&self) -> usize {
51        self.height
52    }
53
54    /// Input width in pixels.
55    pub fn width(&self) -> usize {
56        self.width
57    }
58}
59
60/// Configuration for ONNX model inference and image preprocessing.
61///
62/// Controls the model path, image resize filters for input/output, and threading behavior.
63/// Use builder methods like [`with_input_resize_filter`](InferenceSettings::with_input_resize_filter)
64/// to customize settings.
65///
66/// This struct is non-exhaustive; use [`new`](InferenceSettings::new) to construct it.
67#[cfg(any(feature = "backend-ort", feature = "backend-rten"))]
68#[derive(Debug, Clone)]
69#[non_exhaustive]
70pub struct InferenceSettings {
71    /// Path to the ONNX model file.
72    model_path: PathBuf,
73    /// Backend used to execute the model.
74    backend: InferenceBackend,
75    /// Filter to use when resizing the input image for the model.
76    input_resize_filter: FilterType,
77    /// Filter to use when resizing the output matte to the original image size.
78    output_resize_filter: FilterType,
79    /// Override for the image size used as model input.
80    ///
81    /// When set, callers are responsible for choosing a size the model supports.
82    model_input_size: Option<ModelInputSize>,
83    /// Number of intra-op threads for the inference (ORT backend).
84    intra_threads: Option<usize>,
85}
86
87#[cfg(any(feature = "backend-ort", feature = "backend-rten"))]
88impl InferenceSettings {
89    /// Create new inference settings with default values.
90    pub fn new(model_path: impl Into<PathBuf>) -> Self {
91        Self {
92            model_path: model_path.into(),
93            backend: InferenceBackend::default(),
94            input_resize_filter: FilterType::Triangle,
95            output_resize_filter: FilterType::Lanczos3,
96            model_input_size: None,
97            intra_threads: None,
98        }
99    }
100
101    /// Path to the ONNX model file.
102    pub fn model_path(&self) -> &Path {
103        &self.model_path
104    }
105
106    /// Backend used to execute the model.
107    pub fn backend(&self) -> InferenceBackend {
108        self.backend
109    }
110
111    /// Filter to use when resizing the input image for the model.
112    pub fn input_resize_filter(&self) -> FilterType {
113        self.input_resize_filter
114    }
115
116    /// Filter to use when resizing the output matte to the original image size.
117    pub fn output_resize_filter(&self) -> FilterType {
118        self.output_resize_filter
119    }
120
121    /// Override for the image size used as model input.
122    ///
123    /// When set, callers are responsible for choosing a size the model supports.
124    pub fn model_input_size(&self) -> Option<ModelInputSize> {
125        self.model_input_size
126    }
127
128    /// Number of intra-op threads for the inference (ORT backend).
129    pub fn intra_threads(&self) -> Option<usize> {
130        self.intra_threads
131    }
132
133    /// Set the inference backend.
134    pub fn with_backend(mut self, backend: InferenceBackend) -> Self {
135        self.backend = backend;
136        self
137    }
138
139    /// Override the image size used as model input.
140    ///
141    /// This bypasses the size inferred from the model; callers are responsible for choosing a
142    /// size the model supports.
143    ///
144    /// # Panics
145    ///
146    /// Panics if either dimension is zero.
147    pub fn with_model_input_size(mut self, height: usize, width: usize) -> Self {
148        self.model_input_size = Some(ModelInputSize::new(height, width));
149        self
150    }
151
152    /// Set the model resize filter.
153    pub fn with_input_resize_filter(mut self, filter: FilterType) -> Self {
154        self.input_resize_filter = filter;
155        self
156    }
157
158    /// Set the matte resize filter.
159    pub fn with_output_resize_filter(mut self, filter: FilterType) -> Self {
160        self.output_resize_filter = filter;
161        self
162    }
163
164    /// Set the number of intra-op threads for the inference (ORT backend).
165    pub fn with_intra_threads(mut self, intra_threads: Option<usize>) -> Self {
166        self.intra_threads = intra_threads;
167        self
168    }
169}
170
171/// How erosion treats pixels outside the image bounds.
172#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
173pub enum ErosionBorderMode {
174    /// Treat pixels outside the image as background, allowing edge-touching foreground to shrink.
175    #[default]
176    OutsideIsBackground,
177    /// Treat pixels outside the image as unknown, so erosion only uses visible in-image background.
178    OutsideIsUnknown,
179}
180
181/// Default parameters used by no-argument mask processing methods.
182///
183/// This does not define which operations run. Use [`MaskPipeline`](crate::MaskPipeline) or the
184/// chained methods on [`MatteHandle`](crate::MatteHandle) and [`MaskHandle`](crate::MaskHandle)
185/// to choose an explicit operation order.
186///
187/// This struct is non-exhaustive; start with [`Default`] and then adjust fields as needed.
188#[derive(Debug, Clone, PartialEq)]
189#[non_exhaustive]
190pub struct MaskProcessingDefaults {
191    /// Standard deviation (sigma) for Gaussian blur.
192    pub blur_sigma: f32,
193    /// Threshold value (0–255) used for binary conversion and hole-filling.
194    pub mask_threshold: u8,
195    /// Radius in pixels for the dilation operation.
196    pub dilation_radius: f32,
197    /// Radius in pixels for the erosion operation.
198    pub erosion_radius: f32,
199    /// How erosion treats pixels outside the image bounds.
200    pub erosion_border_mode: ErosionBorderMode,
201}
202
203impl Default for MaskProcessingDefaults {
204    fn default() -> Self {
205        Self {
206            blur_sigma: 6.0,
207            mask_threshold: 120,
208            dilation_radius: 5.0,
209            erosion_radius: 5.0,
210            erosion_border_mode: ErosionBorderMode::default(),
211        }
212    }
213}