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 */
39static inline double
40m4 (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 */
80or_error
81bimedian_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*/