libopenraw
bimedian_demosaic.cpp
1 /*
2  * libopenraw - demosaic.cpp
3  *
4  * This library is free software: you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  * This code has been adapted from GEGL:
19  * Copyright 2006 Øyvind Kolås <pippin@gimp.org>
20  * Copyright 2008 Bradley Broom <bmbroom@gmail.com>
21  *
22  * In libopenraw:
23  * Copyright 2008-2015 Hubert Figuiere <hub@figuiere.net>
24  * Copyright 2008 Novell Inc.
25  */
26 
27 #include <stdlib.h>
28 
29 #include <algorithm>
30 
31 #include <libopenraw/consts.h>
32 
33 #include "bimedian_demosaic.hpp"
34 
35 
36 /* Returns the median of four floats. We define the median as the average of
37  * the central two elements.
38  */
39 static inline double
40 m4 (double a, double b, double c, double d)
41 {
42  double t;
43 
44  /* Sort ab */
45  if (a > b)
46  {
47  t = b;
48  b = a;
49  a = t;
50  }
51  /* Sort abc */
52  if (b > c)
53  {
54  t = c;
55  c = b;
56  if (a > t)
57  {
58  b = a;
59  a = t;
60  }
61  else
62  b = t;
63  }
64  /* Return average of central two elements. */
65  if (d >= c) /* Sorted order would be abcd */
66  return (b + c) / 2.0;
67  else if (d >= a) /* Sorted order would be either abdc or adbc */
68  return (b + d) / 2.0;
69  else /* Sorted order would be dabc */
70  return (a + b) / 2.0;
71 }
72 
73 /* Defines to make the row/col offsets below obvious. */
74 #define ROW src_x
75 #define COL 1
76 
77 /* We expect src_extent to have a one pixel border around all four sides
78  * of dst_extent.
79  */
80 or_error
81 bimedian_demosaic (uint16_t *src, uint32_t src_x, uint32_t src_y,
82  or_cfa_pattern pattern, uint8_t *dst, uint32_t &out_x, uint32_t &out_y)
83 {
84  uint32_t x,y;
85  uint32_t offset, doffset;
86  double *src_buf;
87  double *dst_buf;
88 
89  int npattern = 0;
90  switch(pattern) {
91  case OR_CFA_PATTERN_GRBG:
92  npattern = 0;
93  break;
94  case OR_CFA_PATTERN_BGGR:
95  npattern = 1;
96  break;
97  case OR_CFA_PATTERN_GBRG:
98  npattern = 2;
99  break;
100  case OR_CFA_PATTERN_RGGB:
101  npattern = 3;
102  break;
103 
104  default:
105  // invalid
106  return OR_ERROR_INVALID_FORMAT;
107  }
108 
109  out_x = out_y = 0;
110  src_buf = (double*)calloc(src_x * src_y, sizeof(*src_buf));
111  dst_buf = (double*)calloc(src_x * src_y * 3, sizeof(*dst_buf));
112 
113  std::copy(src, src + (src_x * src_y), src_buf);
114 
115  offset = ROW + COL;
116  doffset = 0;
117  for(y = 1 ; y < src_y - 1; y++)
118  {
119  for (x = 1 ; x < src_x - 1; x++)
120  {
121  double red=0.0;
122  double green=0.0;
123  double blue=0.0;
124 
125  if ((y + npattern%2)%2==0) {
126  if ((x+npattern/2)%2==1) {
127  /* GRG
128  * BGB
129  * GRG
130  */
131  blue =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
132  green=src_buf[offset];
133  red =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
134  }
135  else {
136  /* RGR
137  * GBG
138  * RGR
139  */
140  blue =src_buf[offset];
141  green=m4(src_buf[offset-ROW], src_buf[offset-COL],
142  src_buf[offset+COL], src_buf[offset+ROW]);
143  red =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
144  src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
145  }
146  }
147  else {
148  if ((x+npattern/2)%2==1) {
149  /* BGB
150  * GRG
151  * BGB
152  */
153  blue =m4(src_buf[offset-ROW-COL], src_buf[offset-ROW+COL],
154  src_buf[offset+ROW-COL], src_buf[offset+ROW+COL]);
155  green=m4(src_buf[offset-ROW], src_buf[offset-COL],
156  src_buf[offset+COL], src_buf[offset+ROW]);
157  red =src_buf[offset];
158  }
159  else {
160  /* GBG
161  * RGR
162  * GBG
163  */
164  blue =(src_buf[offset-ROW]+src_buf[offset+ROW])/2.0;
165  green=src_buf[offset];
166  red =(src_buf[offset-COL]+src_buf[offset+COL])/2.0;
167  }
168  }
169 
170  dst_buf [doffset*3+0] = red / 16.0;
171  dst_buf [doffset*3+1] = green / 16.0;
172  dst_buf [doffset*3+2] = blue / 16.0;
173 
174  offset++;
175  doffset++;
176  }
177  offset+=2;
178  }
179  out_x = src_x - 2;
180  out_y = src_y - 2;
181  std::copy(dst_buf, dst_buf + (out_x * out_y * 3), dst);
182  free(src_buf);
183  free(dst_buf);
184 
185  return OR_ERROR_NONE;
186 }
187 
188 
189 
190 /*
191  Local Variables:
192  mode:c++
193  c-file-style:"stroustrup"
194  c-file-offsets:((innamespace . 0))
195  indent-tabs-mode:nil
196  fill-column:80
197  End:
198 */