imagepipe/ops/
demosaic.rs

1use crate::opbasics::*;
2
3#[derive(Clone, Debug, Serialize, Deserialize)]
4pub struct OpDemosaic {
5  pub cfa: String,
6}
7
8impl OpDemosaic {
9  pub fn new(img: &ImageSource) -> OpDemosaic {
10    match img {
11      ImageSource::Raw(img) => {
12        OpDemosaic{
13          cfa: img.cropped_cfa().to_string(),
14        }
15      },
16      ImageSource::Other(_) => {
17        OpDemosaic{
18          cfa: "".to_string(),
19        }
20      }
21    }
22  }
23}
24
25impl<'a> ImageOp<'a> for OpDemosaic {
26  fn name(&self) -> &str {"demosaic"}
27  fn run(&self, pipeline: &PipelineGlobals, buf: Arc<OpBuffer>) -> Arc<OpBuffer> {
28    let nwidth = pipeline.settings.demosaic_width;
29    let nheight = pipeline.settings.demosaic_height;
30    let scale = crate::scaling::calculate_scale(buf.width, buf.height, nwidth, nheight);
31
32    let cfa = CFA::new(&self.cfa);
33    let minscale = match cfa.width {
34      2  => 2.0,  // RGGB/RGBE bayer
35      6  => 3.0,  // x-trans is 6 wide but has all colors in every 3x3 block
36      8  => 2.0,  // Canon pro 70 has a 8x2 patern that has all four colors every 2x2 block
37      12 => 12.0, // some crazy sensor I haven't actually encountered, use full block
38      _  => 2.0,  // default
39    };
40
41    if scale <= 1.0 && buf.colors == 4 {
42      // We want full size and the image is already 4 color, pass it through
43      buf
44    } else if buf.colors == 4 {
45      // Scale down a 4 colour image
46      Arc::new(crate::scaling::scale_down_opbuf(&buf, nwidth, nheight))
47    } else if scale >= minscale {
48      // We're scaling down enough that each pixel has all four colors under it so do the
49      // demosaic and scale down in one go
50      Arc::new(crate::scaling::scaled_demosaic(cfa, &buf, nwidth, nheight))
51    } else {
52      // We're in a close to full scale output that needs full demosaic and possibly
53      // minimal scale down
54      let fullsize = full(cfa, &buf);
55      if scale > 1.0 {
56        Arc::new(crate::scaling::scale_down_opbuf(&fullsize, nwidth, nheight))
57      } else {
58        Arc::new(fullsize)
59      }
60    }
61  }
62
63  // We don't transform_reverse as image sizing is relative to the scaling done
64  // at the demosaic step, so whatever scale down is needed can be achieved here
65}
66
67pub fn full(cfa: CFA, buf: &OpBuffer) -> OpBuffer {
68  let mut out = OpBuffer::new(buf.width, buf.height, 4, buf.monochrome);
69
70  let offsets3x3: [(isize,isize);9] = [
71    (-1,-1), (-1, 0), (-1, 1),
72    ( 0,-1), ( 0, 0), ( 0, 1),
73    ( 1,-1), ( 1, 0), ( 1, 1),
74  ];
75
76  // Initialize a lookup table for the colors of each pixel in a 3x3 grid
77  let mut lookups = [[[0;9];48];48];
78  for (row, line) in lookups.iter_mut().enumerate() {
79    for (col, colors) in line.iter_mut().enumerate() {
80      let pixcolor = cfa.color_at(row, col);
81
82      for (i, o) in offsets3x3.iter().enumerate() {
83        let (dy, dx) = *o;
84        let row = (48+dy) as usize + row;
85        let col = (48+dx) as usize + col;
86        let ocolor = cfa.color_at(row, col);
87        colors[i] = if ocolor != pixcolor || (dx == 0 && dy == 0) { ocolor } else { 4 };
88      }
89    }
90  }
91
92  // Now calculate RGBE for each pixel based on the lookup table
93  out.mutate_lines(&(|line: &mut [f32], row| {
94    for (col, pix) in line.chunks_exact_mut(4).enumerate() {
95      let ref colors = lookups[row%48][col%48];
96      let mut sums = [0f32;5];
97      let mut counts = [0f32;5];
98
99      for (i, o) in offsets3x3.iter().enumerate() {
100        let (dy, dx) = *o;
101        let row = row as isize + dy;
102        let col = col as isize + dx;
103        if row >= 0 && row < (buf.height as isize) &&
104           col >= 0 && col < (buf.width as isize) {
105          sums[colors[i]] += buf.data[(row as usize)*buf.width+(col as usize)];
106          counts[colors[i]] += 1.0;
107        }
108      }
109
110      for c in 0..4 {
111        if counts[c] > 0.0 {
112          pix[c] = sums[c] / counts[c];
113        }
114      }
115    }
116  }));
117
118  out
119}