use crate::cfa::CfaPattern;
pub fn demosaic(input: &[f32], width: usize, height: usize, cfa: &CfaPattern, output: &mut [f32]) {
let npix = width * height;
for y in 0..height {
for x in 0..width {
let idx = y * width + x;
let mut rgb = [0.0f32; 3];
let mut count = [0u32; 3];
let y_lo = y.saturating_sub(1);
let y_hi = (y + 1).min(height - 1);
let x_lo = x.saturating_sub(1);
let x_hi = (x + 1).min(width - 1);
for ny in y_lo..=y_hi {
for nx in x_lo..=x_hi {
let ch = cfa.color_at(ny, nx) as usize;
rgb[ch] += input[ny * width + nx];
count[ch] += 1;
}
}
for c in 0..3 {
output[c * npix + idx] = if count[c] > 0 {
rgb[c] / count[c] as f32
} else {
0.0
};
}
}
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use super::*;
use crate::cfa::Channel;
#[test]
fn known_pixels_preserved() {
let cfa = CfaPattern::bayer_rggb();
let w = 4;
let h = 4;
let mut input = vec![0.0f32; w * h];
for y in 0..h {
for x in 0..w {
input[y * w + x] = match cfa.color_at(y, x) {
Channel::Red => 0.8,
Channel::Green => 0.5,
Channel::Blue => 0.3,
};
}
}
let mut output = vec![0.0f32; 3 * w * h];
demosaic(&input, w, h, &cfa, &mut output);
let idx = 1 * w + 1;
let g = output[w * h + idx]; assert!((g - 0.5).abs() < 0.01, "G at (1,1) = {g}");
for i in 0..w * h {
let r = output[i];
let g = output[w * h + i];
let b = output[2 * w * h + i];
assert!(r >= 0.0 && r <= 1.0, "R out of range at {i}: {r}");
assert!(g >= 0.0 && g <= 1.0, "G out of range at {i}: {g}");
assert!(b >= 0.0 && b <= 1.0, "B out of range at {i}: {b}");
}
}
}