sciimg/
debayer.rs

1use crate::{error, imagebuffer::ImageBuffer, rgbimage::RgbImage};
2
3// G at R locations
4// G at B locations
5#[allow(non_upper_case_globals)]
6pub const GR_GB: [f32; 25] = [
7    0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, -1.0, 2.0, 4.0, 2.0, -1.0, 0.0, 0.0, 2.0,
8    0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0,
9];
10
11// R at G in R row, B column
12// B at G in B row, R column
13#[allow(non_upper_case_globals)]
14pub const Rg_RB_Bg_BR: [f32; 25] = [
15    0.0, 0.0, 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0, 0.0, -1.0, 4.0, 5.0, 4.0, -1.0, 0.0, -1.0, 0.0,
16    -1.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0,
17];
18
19// R at G in B row, R column
20// B at G in R row, B column
21#[allow(non_upper_case_globals)]
22pub const Rg_BR_Bg_RB: [f32; 25] = [
23    0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 4.0, -1.0, 0.0, 0.5, 0.0, 5.0, 0.0, 0.5, 0.0, -1.0, 4.0,
24    -1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0,
25];
26
27//R at B in B row, B column
28//B at R in R row, R column
29#[allow(non_upper_case_globals)]
30pub const Rb_BB_Br_RR: [f32; 25] = [
31    0.0, 0.0, -1.5, 0.0, 0.0, 0.0, 2.0, 0.0, 2.0, 0.0, -1.5, 0.0, 6.0, 0.0, -1.5, 0.0, 2.0, 0.0,
32    2.0, 0.0, 0.0, 0.0, -1.5, 0.0, 0.0,
33];
34
35fn extract_window(
36    buffer: &ImageBuffer,
37    x: usize,
38    y: usize,
39    data_5x5_window: &mut [f32; 25],
40    mask_5x5_window: &mut [bool; 25],
41) {
42    for ny in -2..3_i32 {
43        for nx in -2..3_i32 {
44            let bx = x as i32 + nx;
45            let by = y as i32 + ny;
46
47            if bx < 0 || by < 0 || bx >= buffer.width as i32 || by >= buffer.height as i32 {
48                mask_5x5_window[((ny + 2) * 5 + (nx + 2)) as usize] = false;
49            } else {
50                mask_5x5_window[((ny + 2) * 5 + (nx + 2)) as usize] = true;
51                data_5x5_window[((ny + 2) * 5 + (nx + 2)) as usize] =
52                    buffer.get(bx as usize, by as usize).unwrap();
53            }
54        }
55    }
56}
57
58fn solve(
59    data_5x5_window: &[f32; 25],
60    mask_5x5_window: &[bool; 25],
61    coefficients: &[f32; 25],
62) -> f32 {
63    let mut v = 0.0;
64    let mut s = 0.0;
65    for i in 0..25_usize {
66        if mask_5x5_window[i] {
67            v += data_5x5_window[i] * coefficients[i];
68            s += coefficients[i];
69        }
70    }
71    v * (1.0 / s)
72}
73
74pub fn debayer(buffer: &ImageBuffer) -> error::Result<RgbImage> {
75    let mut red =
76        ImageBuffer::new_with_mask(buffer.width, buffer.height, &buffer.to_mask()).unwrap();
77    let mut green =
78        ImageBuffer::new_with_mask(buffer.width, buffer.height, &buffer.to_mask()).unwrap();
79    let mut blue =
80        ImageBuffer::new_with_mask(buffer.width, buffer.height, &buffer.to_mask()).unwrap();
81
82    let mut data_5x5_window: [f32; 25] = [0.0; 25];
83    let mut mask_5x5_window: [bool; 25] = [false; 25];
84
85    for y in 0..buffer.height {
86        for x in 0..buffer.width {
87            extract_window(buffer, x, y, &mut data_5x5_window, &mut mask_5x5_window);
88
89            let mut r = 0.0;
90            let mut g = 0.0;
91            let mut b = 0.0;
92
93            if x % 2 == 0 && y % 2 == 0 {
94                // Then we're at a red pixel
95                r = data_5x5_window[12];
96                g = solve(&data_5x5_window, &mask_5x5_window, &GR_GB);
97                b = solve(&data_5x5_window, &mask_5x5_window, &Rb_BB_Br_RR);
98            } else if x % 2 != 0 && y % 2 != 0 {
99                // Then we're a blue pixel
100                r = solve(&data_5x5_window, &mask_5x5_window, &Rb_BB_Br_RR);
101                g = solve(&data_5x5_window, &mask_5x5_window, &GR_GB);
102                b = data_5x5_window[12];
103            } else if x % 2 != 0 && y % 2 == 0 {
104                // Then we're at Green, R row, B column
105                r = solve(&data_5x5_window, &mask_5x5_window, &Rg_RB_Bg_BR);
106                g = data_5x5_window[12];
107                b = solve(&data_5x5_window, &mask_5x5_window, &Rg_BR_Bg_RB);
108            } else if x % 2 == 0 && y % 2 != 0 {
109                // Then we're at Green, B row, R column
110                r = solve(&data_5x5_window, &mask_5x5_window, &Rg_BR_Bg_RB);
111                g = data_5x5_window[12];
112                b = solve(&data_5x5_window, &mask_5x5_window, &Rg_RB_Bg_BR);
113            }
114
115            red.put(x, y, r);
116            green.put(x, y, g);
117            blue.put(x, y, b);
118        }
119    }
120
121    let newimage = RgbImage::new_from_buffers_rgb(&red, &green, &blue, buffer.mode).unwrap();
122    Ok(newimage)
123}