rawshift_image/processing/demosaic/
mod.rs1use crate::core::image::{RawImage, RgbImage};
2
3#[derive(Debug, Clone)]
5pub enum DemosaicError {
6 BufferSizeMismatch {
8 expected: usize,
10 actual: usize,
12 },
13 InvalidDimensions,
15 UnsupportedAlgorithm(&'static str),
17}
18
19impl std::fmt::Display for DemosaicError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 DemosaicError::BufferSizeMismatch { expected, actual } => {
23 write!(
24 f,
25 "buffer size mismatch: expected {} elements, got {}",
26 expected, actual
27 )
28 }
29 DemosaicError::InvalidDimensions => write!(f, "invalid image dimensions"),
30 DemosaicError::UnsupportedAlgorithm(name) => {
31 write!(f, "demosaicing algorithm '{}' is not yet implemented", name)
32 }
33 }
34 }
35}
36
37impl std::error::Error for DemosaicError {}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub enum DemosaicMethod {
51 #[default]
54 Auto,
55
56 Bayer(BayerAlgorithm),
58
59 XTrans(XTransAlgorithm),
61
62 None,
64}
65
66impl std::fmt::Display for DemosaicMethod {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 match self {
69 DemosaicMethod::Auto => write!(f, "Auto"),
70 DemosaicMethod::Bayer(algo) => write!(f, "Bayer({})", algo),
71 DemosaicMethod::XTrans(algo) => write!(f, "XTrans({})", algo),
72 DemosaicMethod::None => write!(f, "None"),
73 }
74 }
75}
76
77impl DemosaicMethod {
78 pub fn to_demosaic(&self) -> Box<dyn Demosaic + Send + Sync> {
83 match self {
84 DemosaicMethod::Auto => {
85 Box::new(bayer::Amaze)
87 }
88 DemosaicMethod::Bayer(algo) => algo.to_demosaic(),
89 DemosaicMethod::XTrans(algo) => algo.to_demosaic(),
90 DemosaicMethod::None => Box::new(NoDemosaic),
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
98pub enum BayerAlgorithm {
99 #[default]
101 Amaze,
102 Lmmse,
104 Rcd,
106 Bilinear,
108}
109
110impl std::fmt::Display for BayerAlgorithm {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 BayerAlgorithm::Amaze => write!(f, "AMaZE"),
114 BayerAlgorithm::Lmmse => write!(f, "LMMSE"),
115 BayerAlgorithm::Rcd => write!(f, "RCD"),
116 BayerAlgorithm::Bilinear => write!(f, "Bilinear"),
117 }
118 }
119}
120
121impl BayerAlgorithm {
122 pub fn to_demosaic(&self) -> Box<dyn Demosaic + Send + Sync> {
124 match self {
125 BayerAlgorithm::Amaze => Box::new(bayer::Amaze),
126 BayerAlgorithm::Lmmse => Box::new(bayer::Lmmse),
127 BayerAlgorithm::Rcd => Box::new(bayer::Rcd),
128 BayerAlgorithm::Bilinear => Box::new(Bilinear),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136pub enum XTransAlgorithm {
137 #[default]
139 Markesteijn,
140 Markesteijn3Pass,
142 Fast,
144}
145
146impl std::fmt::Display for XTransAlgorithm {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 match self {
149 XTransAlgorithm::Markesteijn => write!(f, "Markesteijn"),
150 XTransAlgorithm::Markesteijn3Pass => write!(f, "Markesteijn 3-Pass"),
151 XTransAlgorithm::Fast => write!(f, "Fast"),
152 }
153 }
154}
155
156impl XTransAlgorithm {
157 pub fn to_demosaic(&self) -> Box<dyn Demosaic + Send + Sync> {
159 match self {
160 XTransAlgorithm::Markesteijn => Box::new(xtrans::Markesteijn),
161 XTransAlgorithm::Markesteijn3Pass => Box::new(xtrans::Markesteijn3Pass),
162 XTransAlgorithm::Fast => Box::new(xtrans::XTransFast),
163 }
164 }
165}
166
167pub trait Demosaic {
184 fn demosaic_into(&self, raw: &RawImage, output: &mut [u16]) -> Result<(), DemosaicError>;
196
197 #[must_use]
202 fn demosaic(&self, raw: &RawImage) -> RgbImage {
203 let width = raw.active_area().size.width;
204 let height = raw.active_area().size.height;
205 let mut data = vec![0u16; (width as usize) * (height as usize) * 3];
206 self.demosaic_into(raw, &mut data)
207 .expect("demosaic_into failed with correctly sized buffer");
208 RgbImage::new(width, height, data)
209 }
210}
211
212mod bilinear;
217pub use bilinear::Bilinear;
218
219pub mod bayer;
220pub mod xtrans;
221
222pub struct NoDemosaic;
231
232impl Demosaic for NoDemosaic {
233 fn demosaic_into(&self, raw: &RawImage, output: &mut [u16]) -> Result<(), DemosaicError> {
234 let width = raw.active_area().size.width as usize;
235 let height = raw.active_area().size.height as usize;
236 let x_offset = raw.active_area().origin.x as usize;
237 let y_offset = raw.active_area().origin.y as usize;
238 let raw_width = raw.width() as usize;
239
240 let expected_size = width * height * 3;
241 if output.len() != expected_size {
242 return Err(DemosaicError::BufferSizeMismatch {
243 expected: expected_size,
244 actual: output.len(),
245 });
246 }
247
248 for y in 0..height {
250 for x in 0..width {
251 let raw_idx = (y + y_offset) * raw_width + (x + x_offset);
252 let out_idx = (y * width + x) * 3;
253 let value = raw.data[raw_idx];
254 output[out_idx] = value;
255 output[out_idx + 1] = value;
256 output[out_idx + 2] = value;
257 }
258 }
259
260 Ok(())
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_demosaic_error_display() {
270 let err = DemosaicError::BufferSizeMismatch {
271 expected: 300,
272 actual: 100,
273 };
274 let msg = format!("{}", err);
275 assert!(msg.contains("300"));
276 assert!(msg.contains("100"));
277
278 let err = DemosaicError::InvalidDimensions;
279 let msg = format!("{}", err);
280 assert!(msg.contains("dimension"));
281 }
282
283 #[test]
284 fn test_demosaic_method_default() {
285 let method = DemosaicMethod::default();
286 assert_eq!(method, DemosaicMethod::Auto);
287 }
288
289 #[test]
290 fn test_bayer_algorithm_default() {
291 let algo = BayerAlgorithm::default();
292 assert_eq!(algo, BayerAlgorithm::Amaze);
293 }
294
295 #[test]
296 fn test_xtrans_algorithm_default() {
297 let algo = XTransAlgorithm::default();
298 assert_eq!(algo, XTransAlgorithm::Markesteijn);
299 }
300
301 #[test]
302 fn test_demosaic_method_variants() {
303 let _ = DemosaicMethod::Auto;
305 let _ = DemosaicMethod::Bayer(BayerAlgorithm::Bilinear);
306 let _ = DemosaicMethod::XTrans(XTransAlgorithm::Fast);
307 let _ = DemosaicMethod::None;
308 }
309}