1use crate::{error, imagebuffer::ImageBuffer, rgbimage::RgbImage};
2
3#[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#[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#[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#[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 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 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 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 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}