Visual Servoing Platform version 3.5.0
vpBayerConversion.h
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See http://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Bayer conversion tools.
33 *
34 *****************************************************************************/
35
41#ifndef vpBAYERCONVERSION_H
42#define vpBAYERCONVERSION_H
43
44#include <cassert>
45
46#include <visp3/core/vpMath.h>
47
48// Workaround to avoid warning: "left operand of comma operator has no effect" when compiled in g++ with
49// "-Wunused-value"
50#define m_assert(msg, expr) assert( ( (void)( msg ), ( expr ) ) )
51
52// Bilinear
53template <typename T>
54T demosaicPhiBilinear(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
55{
56 return static_cast<T>(0.5f*bayer[(i-1)*width + j] + 0.5f*bayer[(i+1)*width + j]);
57}
58
59template <typename T>
60T demosaicThetaBilinear(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
61{
62 return static_cast<T>(0.5f*bayer[i*width + j - 1] + 0.5f*bayer[i*width + j + 1]);
63}
64
65template <typename T>
66T demosaicCheckerBilinear(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
67{
68 return static_cast<T>(0.25f*bayer[(i-1)*width + j-1] + 0.25f*bayer[(i-1)*width + j+1] + 0.25f*bayer[(i+1)*width + j-1] + 0.25f*bayer[(i+1)*width + j+1]);
69}
70
71template <typename T>
72T demosaicCrossBilinear(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
73{
74 return static_cast<T>(0.25f*bayer[(i-1)*width + j] + 0.25f*bayer[i*width + j-1] + 0.25f*bayer[i*width + j+1] + 0.25f*bayer[(i+1)*width + j]);
75}
76
77// Malvar
78template <typename T>
79T demosaicPhiMalvar(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
80{
81 return vpMath::saturate<T>((-bayer[(i-2)*width + j] - bayer[(i-1)*width + j-1] + 4*bayer[(i-1)*width + j] - bayer[(i-1)*width + j+1] +
82 0.5f*bayer[i*width + j-2] + 5*bayer[i*width + j] + 0.5f*bayer[i*width + j+2] - bayer[(i+1)*width + j-1] + 4*bayer[(i+1)*width + j] -
83 bayer[(i+1)*width + j+1] - bayer[(i+2)*width + j]) * 0.125f);
84}
85
86template <typename T>
87T demosaicThetaMalvar(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
88{
89 return vpMath::saturate<T>((0.5f*bayer[(i-2)*width + j] - bayer[(i-1)*width + j-1] - bayer[(i-1)*width + j+1] - bayer[i*width + j-2] +
90 4*bayer[i*width + j-1] + 5*bayer[i*width + j] + 4*bayer[i*width + j+1] - bayer[i*width + j+2] - bayer[(i+1)*width + j-1] -
91 bayer[(i+1)*width + j+1] + 0.5f*bayer[(i+2)*width + j]) * 0.125f);
92}
93
94template <typename T>
95T demosaicCheckerMalvar(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
96{
97 return vpMath::saturate<T>((-1.5f*bayer[(i-2)*width + j] + 2*bayer[(i-1)*width + j-1] + 2*bayer[(i-1)*width + j+1] -
98 1.5f*bayer[i*width + j-2] + 6*bayer[i*width + j] - 1.5f*bayer[i*width + j+2] + 2*bayer[(i+1)*width + j-1] +
99 2*bayer[(i+1)*width + j+1] - 1.5f*bayer[(i+2)*width + j]) * 0.125f);
100}
101
102template <typename T>
103T demosaicCrossMalvar(const T *bayer, unsigned int width, unsigned int i, unsigned int j)
104{
105 return vpMath::saturate<T>((-bayer[(i-2)*width + j] + 2*bayer[(i-1)*width + j] - bayer[i*width + j-2] + 2*bayer[i*width + j-1] +
106 4*bayer[i*width + j] + 2*bayer[i*width + j+1] - bayer[i*width + j+2] + 2*bayer[(i+1)*width + j] - bayer[(i+2)*width + j]) * 0.125f);
107}
108
109template <typename T>
110void demosaicBGGRToRGBaBilinearTpl(const T *bggr, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
111{
112 m_assert("width must be >= 4", width >= 4);
113 m_assert("height must be >= 4", height >= 4);
114 m_assert("width must be a multiple of 2", width % 2 == 0);
115 m_assert("height must be a multiple of 2", height % 2 == 0);
116
117 // (0,0)
118 rgba[0] = bggr[width + 1];
119 rgba[1] = bggr[1];
120 rgba[2] = bggr[0];
121
122 // (0,w-1)
123 rgba[(width-1)*4 + 0] = bggr[2*width - 1];
124 rgba[(width-1)*4 + 1] = bggr[width - 1];
125 rgba[(width-1)*4 + 2] = bggr[width - 2];
126
127 // (h-1,0)
128 rgba[((height-1)*width)*4 + 0] = bggr[(height-1)*width + 1];
129 rgba[((height-1)*width)*4 + 1] = bggr[(height-1)*width];
130 rgba[((height-1)*width)*4 + 2] = bggr[(height-2)*width];
131
132 // (h-1,w-1)
133 rgba[((height-1)*width + width-1)*4 + 0] = bggr[height*width - 1];
134 rgba[((height-1)*width + width-1)*4 + 1] = bggr[height*width - 2];
135 rgba[((height-1)*width + width-1)*4 + 2] = bggr[(height-1)*width - 2];
136
137 // i == 0
138 for (unsigned int j = 1; j < width-1; j++) {
139 if (j % 2 == 0) {
140 rgba[j*4 + 0] = static_cast<T>(0.5f*bggr[width + j - 1] + 0.5f*bggr[width + j + 1]);
141 rgba[j*4 + 1] = static_cast<T>(0.5f*bggr[j - 1] + 0.5f*bggr[j + 1]);
142 rgba[j*4 + 2] = bggr[j];
143 } else {
144 rgba[j*4 + 0] = bggr[width + j];
145 rgba[j*4 + 1] = bggr[j];
146 rgba[j*4 + 2] = static_cast<T>(0.5f*bggr[j - 1] + 0.5f*bggr[j + 1]);
147 }
148 }
149
150 // j == 0
151 for (unsigned int i = 1; i < height-1; i++) {
152 if (i % 2 == 0) {
153 rgba[i*width*4 + 0] = static_cast<T>(0.5f*bggr[(i-1)*width + 1] + 0.5f*bggr[(i+1)*width + 1]);
154 rgba[i*width*4 + 1] = bggr[i*width + 1];
155 rgba[i*width*4 + 2] = bggr[i*width];
156 } else {
157 rgba[i*width*4 + 0] = bggr[i*width + 1];
158 rgba[i*width*4 + 1] = bggr[i*width];
159 rgba[i*width*4 + 2] = static_cast<T>(0.5f*bggr[(i-1)*width] + 0.5f*bggr[(i+1)*width]);
160 }
161 }
162
163 // j == width-1
164 for (unsigned int i = 1; i < height-1; i++) {
165 if (i % 2 == 0) {
166 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*bggr[i*width - 1] + 0.5f*bggr[(i+2)*width - 1]);
167 rgba[(i*width + width-1)*4 + 1] = bggr[(i+1)*width - 1];
168 rgba[(i*width + width-1)*4 + 2] = bggr[(i+1)*width - 2];
169 } else {
170 rgba[(i*width + width-1)*4 + 0] = bggr[(i+1)*width - 1];
171 rgba[(i*width + width-1)*4 + 1] = bggr[(i+1)*width - 2];
172 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*bggr[i*width - 2] + 0.5f*bggr[(i+2)*width - 2]);
173 }
174 }
175
176 // i == height-1
177 for (unsigned int j = 1; j < width-1; j++) {
178 if (j % 2 == 0) {
179 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*bggr[(height-1)*width + j - 1] + 0.5f*bggr[(height-1)*width + j + 1]);
180 rgba[((height-1)*width + j)*4 + 1] = bggr[(height-1)*width + j];
181 rgba[((height-1)*width + j)*4 + 2] = bggr[(height-2)*width + j];
182 } else {
183 rgba[((height-1)*width + j)*4 + 0] = bggr[(height-1)*width + j];
184 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*bggr[(height-1)*width + j - 1] + 0.5f*bggr[(height-1)*width + j + 1]);
185 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*bggr[(height-2)*width + j - 1] + 0.5f*bggr[(height-2)*width + j + 1]);
186 }
187 }
188
189#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
190 if (nThreads > 0) {
191 omp_set_num_threads(static_cast<int>(nThreads));
192 }
193 #pragma omp parallel for schedule(dynamic)
194#else
195 (void) nThreads;
196#endif
197 for (unsigned int i = 1; i < height-1; i++) {
198 for (unsigned int j = 1; j < width-1; j++) {
199 if (i % 2 == 0 && j % 2 == 0) {
200 rgba[(i*width + j) * 4 + 0] = demosaicCheckerBilinear(bggr, width, i, j);
201 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(bggr, width, i, j);
202 rgba[(i*width + j) * 4 + 2] = bggr[i*width + j];
203 } else if (i % 2 == 0 && j % 2 != 0) {
204 rgba[(i*width + j) * 4 + 0] = demosaicPhiBilinear(bggr, width, i, j);
205 rgba[(i*width + j) * 4 + 1] = bggr[i*width + j];
206 rgba[(i*width + j) * 4 + 2] = demosaicThetaBilinear(bggr, width, i, j);
207 } else if (i % 2 != 0 && j % 2 == 0) {
208 rgba[(i*width + j) * 4 + 0] = demosaicThetaBilinear(bggr, width, i, j);
209 rgba[(i*width + j) * 4 + 1] = bggr[i*width + j];
210 rgba[(i*width + j) * 4 + 2] = demosaicPhiBilinear(bggr, width, i, j);
211 } else {
212 rgba[(i*width + j) * 4 + 0] = bggr[i*width + j];
213 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(bggr, width, i, j);
214 rgba[(i*width + j) * 4 + 2] = demosaicCheckerBilinear(bggr, width, i, j);
215 }
216 }
217 }
218}
219
220template<typename T>
221void demosaicGBRGToRGBaBilinearTpl(const T *gbrg, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
222{
223 m_assert("width must be >= 4", width >= 4);
224 m_assert("height must be >= 4", height >= 4);
225 m_assert("width must be a multiple of 2", width % 2 == 0);
226 m_assert("height must be a multiple of 2", height % 2 == 0);
227
228 // (0,0)
229 rgba[0] = gbrg[width];
230 rgba[1] = gbrg[0];
231 rgba[2] = gbrg[1];
232
233 // (0,w-1)
234 rgba[(width-1)*4 + 0] = gbrg[2*width - 2];
235 rgba[(width-1)*4 + 1] = gbrg[width - 2];
236 rgba[(width-1)*4 + 2] = gbrg[width - 1];
237
238 // (h-1,0)
239 rgba[((height-1)*width)*4 + 0] = gbrg[(height-1)*width];
240 rgba[((height-1)*width)*4 + 1] = gbrg[(height-1)*width + 1];
241 rgba[((height-1)*width)*4 + 2] = gbrg[(height-2)*width + 1];
242
243 // (h-1,w-1)
244 rgba[((height-1)*width + width-1)*4 + 0] = gbrg[height*width - 2];
245 rgba[((height-1)*width + width-1)*4 + 1] = gbrg[height*width - 1];
246 rgba[((height-1)*width + width-1)*4 + 2] = gbrg[(height-1)*width - 1];
247
248 // i == 0
249 for (unsigned int j = 1; j < width-1; j++) {
250 if (j % 2 == 0) {
251 rgba[j*4 + 0] = gbrg[width + j];
252 rgba[j*4 + 1] = gbrg[j];
253 rgba[j*4 + 2] = static_cast<T>(0.5f*gbrg[j - 1] + 0.5f*gbrg[j + 1]);
254 } else {
255 rgba[j*4 + 0] = static_cast<T>(0.5f*gbrg[width + j - 1] + 0.5f*gbrg[width + j + 1]);
256 rgba[j*4 + 1] = static_cast<T>(0.5f*gbrg[j - 1] + 0.5f*gbrg[j + 1]);
257 rgba[j*4 + 2] = gbrg[j];
258 }
259 }
260
261 // j == 0
262 for (unsigned int i = 1; i < height-1; i++) {
263 if (i % 2 == 0) {
264 rgba[i*width*4 + 0] = static_cast<T>(0.5f*gbrg[(i-1)*width] + 0.5f*gbrg[(i+1)*width]);
265 rgba[i*width*4 + 1] = gbrg[i*width];
266 rgba[i*width*4 + 2] = gbrg[i*width + 1];
267 } else {
268 rgba[i*width*4 + 0] = gbrg[i*width];
269 rgba[i*width*4 + 1] = static_cast<T>(0.5f*gbrg[(i-1)*width] + 0.5f*gbrg[(i+1)*width]);
270 rgba[i*width*4 + 2] = static_cast<T>(0.5f*gbrg[(i-1)*width + 1] + 0.5f*gbrg[(i+1)*width + 1]);
271 }
272 }
273
274 // j == width-1
275 for (unsigned int i = 1; i < height-1; i++) {
276 if (i % 2 == 0) {
277 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*gbrg[i*width - 2] + 0.5f*gbrg[(i+2)*width - 2]);
278 rgba[(i*width + width-1)*4 + 1] = gbrg[(i+1)*width - 2];
279 rgba[(i*width + width-1)*4 + 2] = gbrg[(i+1)*width - 1];
280 } else {
281 rgba[(i*width + width-1)*4 + 0] = gbrg[(i+1)*width - 2];
282 rgba[(i*width + width-1)*4 + 1] = gbrg[(i+1)*width - 1];
283 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*gbrg[i*width - 1] + 0.5f*gbrg[(i+2)*width - 1]);
284 }
285 }
286
287 // i == height-1
288 for (unsigned int j = 1; j < width-1; j++) {
289 if (j % 2 == 0) {
290 rgba[((height-1)*width + j)*4 + 0] = gbrg[(height-1)*width + j];
291 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*gbrg[(height-1)*width + j - 1] + 0.5f*gbrg[(height-1)*width + j + 1]);
292 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*gbrg[(height-2)*width + j - 1] + 0.5f*gbrg[(height-2)*width + j + 1]);
293 } else {
294 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*gbrg[(height-1)*width + j - 1] + 0.5f*gbrg[(height-1)*width + j + 1]);
295 rgba[((height-1)*width + j)*4 + 1] = gbrg[(height-1)*width + j];
296 rgba[((height-1)*width + j)*4 + 2] = gbrg[(height-2)*width + j];
297 }
298 }
299
300#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
301 if (nThreads > 0) {
302 omp_set_num_threads(static_cast<int>(nThreads));
303 }
304 #pragma omp parallel for schedule(dynamic)
305#else
306 (void) nThreads;
307#endif
308 for (unsigned int i = 1; i < height-1; i++) {
309 for (unsigned int j = 1; j < width-1; j++) {
310 if (i % 2 == 0 && j % 2 == 0) {
311 rgba[(i*width + j) * 4 + 0] = demosaicPhiBilinear(gbrg, width, i, j);
312 rgba[(i*width + j) * 4 + 1] = gbrg[i*width + j];
313 rgba[(i*width + j) * 4 + 2] = demosaicThetaBilinear(gbrg, width, i, j);
314 } else if (i % 2 == 0 && j % 2 != 0) {
315 rgba[(i*width + j) * 4 + 0] = demosaicCheckerBilinear(gbrg, width, i, j);
316 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(gbrg, width, i, j);
317 rgba[(i*width + j) * 4 + 2] = gbrg[i*width + j];
318 } else if (i % 2 != 0 && j % 2 == 0) {
319 rgba[(i*width + j) * 4 + 0] = gbrg[i*width + j];
320 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(gbrg, width, i, j);
321 rgba[(i*width + j) * 4 + 2] = demosaicCheckerBilinear(gbrg, width, i, j);
322 } else {
323 rgba[(i*width + j) * 4 + 0] = demosaicThetaBilinear(gbrg, width, i, j);
324 rgba[(i*width + j) * 4 + 1] = gbrg[i*width + j];
325 rgba[(i*width + j) * 4 + 2] = demosaicPhiBilinear(gbrg, width, i, j);
326 }
327 }
328 }
329}
330
331template<typename T>
332void demosaicGRBGToRGBaBilinearTpl(const T *grbg, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
333{
334 m_assert("width must be >= 4", width >= 4);
335 m_assert("height must be >= 4", height >= 4);
336 m_assert("width must be a multiple of 2", width % 2 == 0);
337 m_assert("height must be a multiple of 2", height % 2 == 0);
338
339 // (0,0)
340 rgba[0] = grbg[1];
341 rgba[1] = grbg[0];
342 rgba[2] = grbg[width];
343
344 // (0,w-1)
345 rgba[(width-1)*4 + 0] = grbg[width - 1];
346 rgba[(width-1)*4 + 1] = grbg[width - 2];
347 rgba[(width-1)*4 + 2] = grbg[2*width - 2];
348
349 // (h-1,0)
350 rgba[((height-1)*width)*4 + 0] = grbg[(height-2)*width + 1];
351 rgba[((height-1)*width)*4 + 1] = grbg[(height-1)*width + 1];
352 rgba[((height-1)*width)*4 + 2] = grbg[(height-1)*width];
353
354 // (h-1,w-1)
355 rgba[((height-1)*width + width-1)*4 + 0] = grbg[(height-1)*width - 1];
356 rgba[((height-1)*width + width-1)*4 + 1] = grbg[height*width - 1];
357 rgba[((height-1)*width + width-1)*4 + 2] = grbg[height*width - 2];
358
359 // i == 0
360 for (unsigned int j = 1; j < width-1; j++) {
361 if (j % 2 == 0) {
362 rgba[j*4 + 0] = static_cast<T>(0.5f*grbg[j - 1] + 0.5f*grbg[j + 1]);
363 rgba[j*4 + 1] = grbg[j];
364 rgba[j*4 + 2] = grbg[width + j];
365 } else {
366 rgba[j*4 + 0] = grbg[j];
367 rgba[j*4 + 1] = static_cast<T>(0.5f*grbg[j - 1] + 0.5f*grbg[j + 1]);
368 rgba[j*4 + 2] = static_cast<T>(0.5f*grbg[width + j - 1] + 0.5f*grbg[width + j + 1]);
369 }
370 }
371
372 // j == 0
373 for (unsigned int i = 1; i < height-1; i++) {
374 if (i % 2 == 0) {
375 rgba[i*width*4 + 0] = grbg[i*width + 1];
376 rgba[i*width*4 + 1] = grbg[i*width];
377 rgba[i*width*4 + 2] = static_cast<T>(0.5f*grbg[(i-1)*width] + 0.5f*grbg[(i+1)*width]);
378 } else {
379 rgba[i*width*4 + 0] = static_cast<T>(0.5f*grbg[(i-1)*width + 1] + 0.5f*grbg[(i+1)*width + 1]);
380 rgba[i*width*4 + 1] = grbg[i*width + 1];
381 rgba[i*width*4 + 2] = grbg[i*width];
382 }
383 }
384
385 // j == width-1
386 for (unsigned int i = 1; i < height-1; i++) {
387 if (i % 2 == 0) {
388 rgba[(i*width + width-1)*4 + 0] = grbg[(i+1)*width - 1];
389 rgba[(i*width + width-1)*4 + 1] = grbg[(i+1)*width - 2];
390 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*grbg[i*width - 2] + 0.5f*grbg[(i+2)*width - 2]);
391 } else {
392 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*grbg[i*width - 1] + 0.5f*grbg[(i+2)*width - 1]);
393 rgba[(i*width + width-1)*4 + 1] = grbg[(i+1)*width - 1];
394 rgba[(i*width + width-1)*4 + 2] = grbg[(i+1)*width - 2];
395 }
396 }
397
398 // i == height-1
399 for (unsigned int j = 1; j < width-1; j++) {
400 if (j % 2 == 0) {
401 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*grbg[(height-2)*width + j - 1] + 0.5f*grbg[(height-2)*width + j + 1]);
402 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*grbg[(height-1)*width + j - 1] + 0.5f*grbg[(height-1)*width + j + 1]);
403 rgba[((height-1)*width + j)*4 + 2] = grbg[(height-1)*width + j];
404 } else {
405 rgba[((height-1)*width + j)*4 + 0] = grbg[(height-2)*width + j];
406 rgba[((height-1)*width + j)*4 + 1] = grbg[(height-1)*width + j];
407 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*grbg[(height-1)*width + j - 1] + 0.5f*grbg[(height-1)*width + j + 1]);
408 }
409 }
410
411#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
412 if (nThreads > 0) {
413 omp_set_num_threads(static_cast<int>(nThreads));
414 }
415 #pragma omp parallel for schedule(dynamic)
416#else
417 (void) nThreads;
418#endif
419 for (unsigned int i = 1; i < height-1; i++) {
420 for (unsigned int j = 1; j < width-1; j++) {
421 if (i % 2 == 0 && j % 2 == 0) {
422 rgba[(i*width + j) * 4 + 0] = demosaicThetaBilinear(grbg, width, i, j);
423 rgba[(i*width + j) * 4 + 1] = grbg[i*width + j];
424 rgba[(i*width + j) * 4 + 2] = demosaicPhiBilinear(grbg, width, i, j);
425 } else if (i % 2 == 0 && j % 2 != 0) {
426 rgba[(i*width + j) * 4 + 0] = grbg[i*width + j];
427 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(grbg, width, i, j);
428 rgba[(i*width + j) * 4 + 2] = demosaicCheckerBilinear(grbg, width, i, j);
429 } else if (i % 2 != 0 && j % 2 == 0) {
430 rgba[(i*width + j) * 4 + 0] = demosaicCheckerBilinear(grbg, width, i, j);
431 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(grbg, width, i, j);
432 rgba[(i*width + j) * 4 + 2] = grbg[i*width + j];
433 } else {
434 rgba[(i*width + j) * 4 + 0] = demosaicPhiBilinear(grbg, width, i, j);
435 rgba[(i*width + j) * 4 + 1] = grbg[i*width + j];
436 rgba[(i*width + j) * 4 + 2] = demosaicThetaBilinear(grbg, width, i, j);
437 }
438 }
439 }
440}
441
442template<typename T>
443void demosaicRGGBToRGBaBilinearTpl(const T *rggb, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
444{
445 m_assert("width must be >= 4", width >= 4);
446 m_assert("height must be >= 4", height >= 4);
447 m_assert("width must be a multiple of 2", width % 2 == 0);
448 m_assert("height must be a multiple of 2", height % 2 == 0);
449
450 // (0,0)
451 rgba[0] = rggb[0];
452 rgba[1] = rggb[1];
453 rgba[2] = rggb[width + 1];
454
455 // (0,w-1)
456 rgba[(width-1)*4 + 0] = rggb[width - 2];
457 rgba[(width-1)*4 + 1] = rggb[width - 1];
458 rgba[(width-1)*4 + 2] = rggb[2*width - 1];
459
460 // (h-1,0)
461 rgba[((height-1)*width)*4 + 0] = rggb[(height-2)*width];
462 rgba[((height-1)*width)*4 + 1] = rggb[(height-1)*width];
463 rgba[((height-1)*width)*4 + 2] = rggb[(height-1)*width + 1];
464
465 // (h-1,w-1)
466 rgba[((height-1)*width + width-1)*4 + 0] = rggb[(height-1)*width - 2];
467 rgba[((height-1)*width + width-1)*4 + 1] = rggb[height*width - 2];
468 rgba[((height-1)*width + width-1)*4 + 2] = rggb[height*width - 1];
469
470 // i == 0
471 for (unsigned int j = 1; j < width-1; j++) {
472 if (j % 2 == 0) {
473 rgba[j*4 + 0] = rggb[j];
474 rgba[j*4 + 1] = static_cast<T>(0.5f*rggb[j - 1] + 0.5f*rggb[j + 1]);
475 rgba[j*4 + 2] = static_cast<T>(0.5f*rggb[width + j - 1] + 0.5f*rggb[width + j + 1]);
476 } else {
477 rgba[j*4 + 0] = static_cast<T>(0.5f*rggb[j - 1] + 0.5f*rggb[j + 1]);
478 rgba[j*4 + 1] = rggb[j];
479 rgba[j*4 + 2] = rggb[width + j];
480 }
481 }
482
483 // j == 0
484 for (unsigned int i = 1; i < height-1; i++) {
485 if (i % 2 == 0) {
486 rgba[i*width*4 + 0] = rggb[i*width];
487 rgba[i*width*4 + 1] = rggb[i*width + 1];
488 rgba[i*width*4 + 2] = static_cast<T>(0.5f*rggb[(i-1)*width + 1] + 0.5f*rggb[(i+1)*width + 1]);
489 } else {
490 rgba[i*width*4 + 0] = static_cast<T>(0.5f*rggb[(i-1)*width] + 0.5f*rggb[(i+1)*width]);
491 rgba[i*width*4 + 1] = rggb[i*width];
492 rgba[i*width*4 + 2] = rggb[i*width + 1];
493 }
494 }
495
496 // j == width-1
497 for (unsigned int i = 1; i < height-1; i++) {
498 if (i % 2 == 0) {
499 rgba[(i*width + width-1)*4 + 0] = rggb[(i+1)*width - 2];
500 rgba[(i*width + width-1)*4 + 1] = rggb[(i+1)*width - 1];
501 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*rggb[i*width - 1] + 0.5f*rggb[(i+2)*width - 1]);
502 } else {
503 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*rggb[i*width - 2] + 0.5f*rggb[(i+2)*width - 2]);
504 rgba[(i*width + width-1)*4 + 1] = rggb[(i+1)*width - 2];
505 rgba[(i*width + width-1)*4 + 2] = rggb[(i+1)*width - 1];
506 }
507 }
508
509 // i == height-1
510 for (unsigned int j = 1; j < width-1; j++) {
511 if (j % 2 == 0) {
512 rgba[((height-1)*width + j)*4 + 0] = rggb[(height-2)*width + j];
513 rgba[((height-1)*width + j)*4 + 1] = rggb[(height-1)*width + j];
514 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*rggb[(height-1)*width + j - 1] + 0.5f*rggb[(height-1)*width + j + 1]);
515 } else {
516 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*rggb[(height-2)*width + j - 1] + 0.5f*rggb[(height-2)*width + j + 1]);
517 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*rggb[(height-1)*width + j - 1] + 0.5f*rggb[(height-1)*width + j + 1]);
518 rgba[((height-1)*width + j)*4 + 2] = rggb[(height-1)*width + j];
519 }
520 }
521
522#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
523 if (nThreads > 0) {
524 omp_set_num_threads(static_cast<int>(nThreads));
525 }
526 #pragma omp parallel for schedule(dynamic)
527#else
528 (void) nThreads;
529#endif
530 for (unsigned int i = 1; i < height-1; i++) {
531 for (unsigned int j = 1; j < width-1; j++) {
532 if (i % 2 == 0 && j % 2 == 0) {
533 rgba[(i*width + j) * 4 + 0] = rggb[i*width + j];
534 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(rggb, width, i, j);
535 rgba[(i*width + j) * 4 + 2] = demosaicCheckerBilinear(rggb, width, i, j);
536 } else if (i % 2 == 0 && j % 2 != 0) {
537 rgba[(i*width + j) * 4 + 0] = demosaicThetaBilinear(rggb, width, i, j);
538 rgba[(i*width + j) * 4 + 1] = rggb[i*width + j];
539 rgba[(i*width + j) * 4 + 2] = demosaicPhiBilinear(rggb, width, i, j);
540 } else if (i % 2 != 0 && j % 2 == 0) {
541 rgba[(i*width + j) * 4 + 0] = demosaicPhiBilinear(rggb, width, i, j);
542 rgba[(i*width + j) * 4 + 1] = rggb[i*width + j];
543 rgba[(i*width + j) * 4 + 2] = demosaicThetaBilinear(rggb, width, i, j);
544 } else {
545 rgba[(i*width + j) * 4 + 0] = demosaicCheckerBilinear(rggb, width, i, j);
546 rgba[(i*width + j) * 4 + 1] = demosaicCrossBilinear(rggb, width, i, j);
547 rgba[(i*width + j) * 4 + 2] = rggb[i*width + j];
548 }
549 }
550 }
551}
552
553// Malvar
554
555template<typename T>
556void demosaicBGGRToRGBaMalvarTpl(const T *bggr, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
557{
558 m_assert("width must be >= 4", width >= 4);
559 m_assert("height must be >= 4", height >= 4);
560 m_assert("width must be a multiple of 2", width % 2 == 0);
561 m_assert("height must be a multiple of 2", height % 2 == 0);
562
563 // (0,0)
564 rgba[0] = bggr[width + 1];
565 rgba[1] = bggr[1];
566 rgba[2] = bggr[0];
567
568 // (0,w-1)
569 rgba[(width-1)*4 + 0] = bggr[2*width - 1];
570 rgba[(width-1)*4 + 1] = bggr[width - 1];
571 rgba[(width-1)*4 + 2] = bggr[width - 2];
572
573 // (h-1,0)
574 rgba[((height-1)*width)*4 + 0] = bggr[(height-1)*width + 1];
575 rgba[((height-1)*width)*4 + 1] = bggr[(height-1)*width];
576 rgba[((height-1)*width)*4 + 2] = bggr[(height-2)*width];
577
578 // (h-1,w-1)
579 rgba[((height-1)*width + width-1)*4 + 0] = bggr[height*width - 1];
580 rgba[((height-1)*width + width-1)*4 + 1] = bggr[height*width - 2];
581 rgba[((height-1)*width + width-1)*4 + 2] = bggr[(height-1)*width - 2];
582
583 // i == 0
584 for (unsigned int j = 1; j < width-1; j++) {
585 if (j % 2 == 0) {
586 rgba[j*4 + 0] = static_cast<T>(0.5f*bggr[width + j - 1] + 0.5f*bggr[width + j + 1]);
587 rgba[j*4 + 1] = static_cast<T>(0.5f*bggr[j - 1] + 0.5f*bggr[j + 1]);
588 rgba[j*4 + 2] = bggr[j];
589 } else {
590 rgba[j*4 + 0] = bggr[width + j];
591 rgba[j*4 + 1] = bggr[j];
592 rgba[j*4 + 2] = static_cast<T>(0.5f*bggr[j - 1] + 0.5f*bggr[j + 1]);
593 }
594 }
595
596 // i == 1
597 for (unsigned int j = 1; j < width-1; j++) {
598 if (j % 2 == 0) {
599 rgba[(width + j)*4 + 0] = static_cast<T>(0.5f*bggr[width + j - 1] + 0.5f*bggr[width + j + 1]);
600 rgba[(width + j)*4 + 1] = bggr[width + j];
601 rgba[(width + j)*4 + 2] = static_cast<T>(0.5f*bggr[j] + 0.5f*bggr[2*width + j]);
602 } else {
603 rgba[(width + j)*4 + 0] = bggr[width + j];
604 rgba[(width + j)*4 + 1] = static_cast<T>(0.25f*bggr[j] + 0.25f*bggr[width + j - 1] + 0.25f*bggr[width + j + 1] + 0.25f*bggr[2*width + j]);
605 rgba[(width + j)*4 + 2] = static_cast<T>(0.25f*bggr[j - 1] + 0.25f*bggr[j + 1] + 0.25f*bggr[2*width + j - 1] + 0.25f*bggr[2*width + j + 1]);
606 }
607 }
608
609 // j == 0
610 for (unsigned int i = 1; i < height-1; i++) {
611 if (i % 2 == 0) {
612 rgba[i*width*4 + 0] = static_cast<T>(0.5f*bggr[(i-1)*width + 1] + 0.5f*bggr[(i+1)*width + 1]);
613 rgba[i*width*4 + 1] = bggr[i*width + 1];
614 rgba[i*width*4 + 2] = bggr[i*width];
615 } else {
616 rgba[i*width*4 + 0] = bggr[i*width + 1];
617 rgba[i*width*4 + 1] = bggr[i*width];
618 rgba[i*width*4 + 2] = static_cast<T>(0.5f*bggr[(i-1)*width] + 0.5f*bggr[(i+1)*width]);
619 }
620 }
621
622 // j == 1
623 for (unsigned int i = 1; i < height-1; i++) {
624 if (i % 2 == 0) {
625 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.5f*bggr[(i-1)*width + 1] + 0.5f*bggr[(i+1)*width + 1]);
626 rgba[(i*width + 1)*4 + 1] = bggr[i*width + 1];
627 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.5f*bggr[i*width] + 0.5f*bggr[i*width + 2]);
628 } else {
629 rgba[(i*width + 1)*4 + 0] = bggr[i*width + 1];
630 rgba[(i*width + 1)*4 + 1] = static_cast<T>(0.25f*bggr[(i-1)*width + 1] + 0.25f*bggr[i*width] + 0.25f*bggr[i*width + 2] + 0.25f*bggr[(i+1)*width + 1]);
631 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.25f*bggr[(i-1)*width] + 0.25f*bggr[(i-1)*width + 2] + 0.25f*bggr[(i+1)*width] + 0.25f*bggr[(i+1)*width + 2]);
632 }
633 }
634
635 // j == width-2
636 for (unsigned int i = 1; i < height-1; i++) {
637 if (i % 2 == 0) {
638 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.25f*bggr[i*width - 3] + 0.25f*bggr[i*width - 1] + 0.25f*bggr[(i+2)*width - 3] + 0.25f*bggr[(i+2)*width - 1]);
639 rgba[(i*width + width-2)*4 + 1] = static_cast<T>(0.25f*bggr[i*width - 2] + 0.25f*bggr[(i+1)*width - 3] +
640 0.25f*bggr[(i+1)*width - 1] + 0.25f*bggr[(i+2)*width - 2]);
641 rgba[(i*width + width-2)*4 + 2] = bggr[(i+1)*width - 2];
642 } else {
643 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.5f*bggr[(i+1)*width - 3] + 0.5f*bggr[(i+1)*width - 1]);
644 rgba[(i*width + width-2)*4 + 1] = bggr[(i+1)*width - 2];
645 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.5f*bggr[i*width - 2] + 0.5f*bggr[(i+2)*width - 2]);
646 }
647 }
648
649 // j == width-1
650 for (unsigned int i = 1; i < height-1; i++) {
651 if (i % 2 == 0) {
652 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*bggr[i*width - 1] + 0.5f*bggr[(i+2)*width - 1]);
653 rgba[(i*width + width-1)*4 + 1] = bggr[(i+1)*width - 1];
654 rgba[(i*width + width-1)*4 + 2] = bggr[(i+1)*width - 2];
655 } else {
656 rgba[(i*width + width-1)*4 + 0] = bggr[(i+1)*width - 1];
657 rgba[(i*width + width-1)*4 + 1] = bggr[(i+1)*width - 2];
658 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*bggr[i*width - 2] + 0.5f*bggr[(i+2)*width - 2]);
659 }
660 }
661
662 // i == height-2
663 for (unsigned int j = 1; j < width-1; j++) {
664 if (j % 2 == 0) {
665 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.25f*bggr[(height-3)*width + j - 1] + 0.25f*bggr[(height-3)*width + j + 1] +
666 0.25f*bggr[(height-1)*width + j - 1] + 0.25f*bggr[(height-1)*width + j + 1]);
667 rgba[((height-2)*width + j)*4 + 1] = static_cast<T>(0.5f*bggr[(height-2)*width + j - 1] + 0.5f*bggr[(height-2)*width + j + 1]);
668 rgba[((height-2)*width + j)*4 + 2] = bggr[(height-2)*width + j];
669 } else {
670 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.5f*bggr[(height-3)*width + j] + 0.5f*bggr[(height-1)*width + j]);
671 rgba[((height-2)*width + j)*4 + 1] = bggr[(height-2)*width + j];
672 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.5f*bggr[(height-2)*width + j - 1] + 0.5f*bggr[(height-2)*width + j + 1]);
673 }
674 }
675
676 // i == height-1
677 for (unsigned int j = 1; j < width-1; j++) {
678 if (j % 2 == 0) {
679 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*bggr[(height-1)*width + j - 1] + 0.5f*bggr[(height-1)*width + j + 1]);
680 rgba[((height-1)*width + j)*4 + 1] = bggr[(height-1)*width + j];
681 rgba[((height-1)*width + j)*4 + 2] = bggr[(height-2)*width + j];
682 } else {
683 rgba[((height-1)*width + j)*4 + 0] = bggr[(height-1)*width + j];
684 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*bggr[(height-1)*width + j - 1] + 0.5f*bggr[(height-1)*width + j + 1]);
685 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*bggr[(height-2)*width + j - 1] + 0.5f*bggr[(height-2)*width + j + 1]);
686 }
687 }
688
689#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
690 if (nThreads > 0) {
691 omp_set_num_threads(static_cast<int>(nThreads));
692 }
693 #pragma omp parallel for schedule(dynamic)
694#else
695 (void) nThreads;
696#endif
697 for (unsigned int i = 2; i < height-2; i++) {
698 for (unsigned int j = 2; j < width-2; j++) {
699 if (i % 2 == 0 && j % 2 == 0) {
700 rgba[(i*width + j) * 4 + 0] = demosaicCheckerMalvar(bggr, width, i, j);
701 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(bggr, width, i, j);
702 rgba[(i*width + j) * 4 + 2] = bggr[i*width + j];
703 } else if (i % 2 == 0 && j % 2 != 0) {
704 rgba[(i*width + j) * 4 + 0] = demosaicPhiMalvar(bggr, width, i, j);
705 rgba[(i*width + j) * 4 + 1] = bggr[i*width + j];
706 rgba[(i*width + j) * 4 + 2] = demosaicThetaMalvar(bggr, width, i, j);
707 } else if (i % 2 != 0 && j % 2 == 0) {
708 rgba[(i*width + j) * 4 + 0] = demosaicThetaMalvar(bggr, width, i, j);
709 rgba[(i*width + j) * 4 + 1] = bggr[i*width + j];
710 rgba[(i*width + j) * 4 + 2] = demosaicPhiMalvar(bggr, width, i, j);
711 } else {
712 rgba[(i*width + j) * 4 + 0] = bggr[i*width + j];
713 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(bggr, width, i, j);
714 rgba[(i*width + j) * 4 + 2] = demosaicCheckerMalvar(bggr, width, i, j);
715 }
716 }
717 }
718}
719
720template<typename T>
721void demosaicGBRGToRGBaMalvarTpl(const T *gbrg, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
722{
723 m_assert("width must be >= 4", width >= 4);
724 m_assert("height must be >= 4", height >= 4);
725 m_assert("width must be a multiple of 2", width % 2 == 0);
726 m_assert("height must be a multiple of 2", height % 2 == 0);
727
728 // (0,0)
729 rgba[0] = gbrg[width];
730 rgba[1] = gbrg[0];
731 rgba[2] = gbrg[1];
732
733 // (0,w-1)
734 rgba[(width-1)*4 + 0] = gbrg[2*width - 2];
735 rgba[(width-1)*4 + 1] = gbrg[width - 2];
736 rgba[(width-1)*4 + 2] = gbrg[width - 1];
737
738 // (h-1,0)
739 rgba[((height-1)*width)*4 + 0] = gbrg[(height-1)*width];
740 rgba[((height-1)*width)*4 + 1] = gbrg[(height-1)*width + 1];
741 rgba[((height-1)*width)*4 + 2] = gbrg[(height-2)*width + 1];
742
743 // (h-1,w-1)
744 rgba[((height-1)*width + width-1)*4 + 0] = gbrg[height*width - 2];
745 rgba[((height-1)*width + width-1)*4 + 1] = gbrg[height*width - 1];
746 rgba[((height-1)*width + width-1)*4 + 2] = gbrg[(height-1)*width - 1];
747
748 // i == 0
749 for (unsigned int j = 1; j < width-1; j++) {
750 if (j % 2 == 0) {
751 rgba[j*4 + 0] = gbrg[width + j];
752 rgba[j*4 + 1] = gbrg[j];
753 rgba[j*4 + 2] = static_cast<T>(0.5f*gbrg[j - 1] + 0.5f*gbrg[j + 1]);
754 } else {
755 rgba[j*4 + 0] = static_cast<T>(0.5f*gbrg[width + j - 1] + 0.5f*gbrg[width + j + 1]);
756 rgba[j*4 + 1] = static_cast<T>(0.5f*gbrg[j - 1] + 0.5f*gbrg[j + 1]);
757 rgba[j*4 + 2] = gbrg[j];
758 }
759 }
760
761 // i == 1
762 for (unsigned int j = 1; j < width-1; j++) {
763 if (j % 2 == 0) {
764 rgba[(width + j)*4 + 0] = gbrg[width + j];
765 rgba[(width + j)*4 + 1] = static_cast<T>(0.25f*gbrg[j] + 0.25f*gbrg[width + j - 1] + 0.25f*gbrg[width + j + 1] + 0.25f*gbrg[2*width + j]);
766 rgba[(width + j)*4 + 2] = static_cast<T>(0.25f*gbrg[j - 1] + 0.25f*gbrg[j + 1] + 0.25f*gbrg[2*width + j - 1] + 0.25f*gbrg[2*width + j + 1]);
767 } else {
768 rgba[(width + j)*4 + 0] = static_cast<T>(0.5f*gbrg[width + j - 1] + 0.5f*gbrg[width + j + 1]);
769 rgba[(width + j)*4 + 1] = gbrg[width + j];
770 rgba[(width + j)*4 + 2] = static_cast<T>(0.5f*gbrg[j] + 0.5f*gbrg[2*width + j]);
771 }
772 }
773
774 // j == 0
775 for (unsigned int i = 1; i < height-1; i++) {
776 if (i % 2 == 0) {
777 rgba[i*width*4 + 0] = static_cast<T>(0.5f*gbrg[(i-1)*width] + 0.5f*gbrg[(i+1)*width]);
778 rgba[i*width*4 + 1] = gbrg[i*width];
779 rgba[i*width*4 + 2] = gbrg[i*width + 1];
780 } else {
781 rgba[i*width*4 + 0] = gbrg[i*width];
782 rgba[i*width*4 + 1] = static_cast<T>(0.5f*gbrg[(i-1)*width] + 0.5f*gbrg[(i+1)*width]);
783 rgba[i*width*4 + 2] = static_cast<T>(0.5f*gbrg[(i-1)*width + 1] + 0.5f*gbrg[(i+1)*width + 1]);
784 }
785 }
786
787 // j == 1
788 for (unsigned int i = 1; i < height-1; i++) {
789 if (i % 2 == 0) {
790 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.25f*gbrg[(i-1)*width] + 0.25f*gbrg[(i-1)*width + 2] + 0.25f*gbrg[(i+1)*width] + 0.5f*gbrg[(i+1)*width + 2]);
791 rgba[(i*width + 1)*4 + 1] = static_cast<T>(0.25f*gbrg[(i-1)*width + 1] + 0.25f*gbrg[i*width] + 0.25f*gbrg[i*width + 2] + 0.5f*gbrg[(i+1)*width + 1]);
792 rgba[(i*width + 1)*4 + 2] = gbrg[i*width + 1];
793 } else {
794 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.5f*gbrg[i*width] + 0.5f*gbrg[i*width + 2]);
795 rgba[(i*width + 1)*4 + 1] = gbrg[i*width + 1];
796 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.5f*gbrg[(i-1)*width + 1] + 0.5f*gbrg[(i+1)*width + 1]);
797 }
798 }
799
800 // j == width-2
801 for (unsigned int i = 1; i < height-1; i++) {
802 if (i % 2 == 0) {
803 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.5f*gbrg[i*width - 2] + 0.5f*gbrg[(i+2)*width - 2]);
804 rgba[(i*width + width-2)*4 + 1] = gbrg[(i+1)*width - 2];
805 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.5f*gbrg[(i+1)*width - 3] + 0.5f*gbrg[(i+1)*width - 1]);
806 } else {
807 rgba[(i*width + width-2)*4 + 0] = gbrg[(i+1)*width - 2];
808 rgba[(i*width + width-2)*4 + 1] = static_cast<T>(0.25f*gbrg[i*width - 2] + 0.25f*gbrg[(i+1)*width - 3] +
809 0.25f*gbrg[(i+1)*width - 1] + 0.25f*gbrg[(i+2)*width - 2]);
810 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.25f*gbrg[i*width - 3] + 0.25f*gbrg[i*width - 1] +
811 0.25f*gbrg[(i+2)*width - 3] + 0.25f*gbrg[(i+2)*width - 1]);
812 }
813 }
814
815 // j == width-1
816 for (unsigned int i = 1; i < height-1; i++) {
817 if (i % 2 == 0) {
818 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*gbrg[i*width - 2] + 0.5f*gbrg[(i+2)*width - 2]);
819 rgba[(i*width + width-1)*4 + 1] = gbrg[(i+1)*width - 2];
820 rgba[(i*width + width-1)*4 + 2] = gbrg[(i+1)*width - 1];
821 } else {
822 rgba[(i*width + width-1)*4 + 0] = gbrg[(i+1)*width - 2];
823 rgba[(i*width + width-1)*4 + 1] = gbrg[(i+1)*width - 1];
824 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*gbrg[i*width - 1] + 0.5f*gbrg[(i+2)*width - 1]);
825 }
826 }
827
828 // i == height-2
829 for (unsigned int j = 1; j < width-1; j++) {
830 if (j % 2 == 0) {
831 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.5f*gbrg[(height-3)*width + j] + 0.5f*gbrg[(height-1)*width + j]);
832 rgba[((height-2)*width + j)*4 + 1] = gbrg[(height-2)*width + j];
833 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.5f*gbrg[(height-2)*width + j - 1] + 0.5f*gbrg[(height-2)*width + j + 1]);
834 } else {
835 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.25f*gbrg[(height-3)*width + j - 1] + 0.25f*gbrg[(height-3)*width + j + 1] +
836 0.25f*gbrg[(height-1)*width + j - 1] + 0.25f*gbrg[(height-1)*width + j + 1]);
837 rgba[((height-2)*width + j)*4 + 1] = static_cast<T>(0.25f*gbrg[(height-3)*width + j] + 0.25f*gbrg[(height-2)*width + j - 1] +
838 0.25f*gbrg[(height-2)*width + j + 1] + 0.25f*gbrg[(height-1)*width + j]);
839 rgba[((height-2)*width + j)*4 + 2] = gbrg[(height-2)*width + j];
840 }
841 }
842
843 // i == height-1
844 for (unsigned int j = 1; j < width-1; j++) {
845 if (j % 2 == 0) {
846 rgba[((height-1)*width + j)*4 + 0] = gbrg[(height-1)*width + j];
847 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*gbrg[(height-1)*width + j - 1] + 0.5f*gbrg[(height-1)*width + j + 1]);
848 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*gbrg[(height-2)*width + j - 1] + 0.5f*gbrg[(height-2)*width + j + 1]);
849 } else {
850 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*gbrg[(height-1)*width + j - 1] + 0.5f*gbrg[(height-1)*width + j + 1]);
851 rgba[((height-1)*width + j)*4 + 1] = gbrg[(height-1)*width + j];
852 rgba[((height-1)*width + j)*4 + 2] = gbrg[(height-2)*width + j];
853 }
854 }
855
856#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
857 if (nThreads > 0) {
858 omp_set_num_threads(static_cast<int>(nThreads));
859 }
860 #pragma omp parallel for schedule(dynamic)
861#else
862 (void) nThreads;
863#endif
864 for (unsigned int i = 2; i < height-2; i++) {
865 for (unsigned int j = 2; j < width-2; j++) {
866 if (i % 2 == 0 && j % 2 == 0) {
867 rgba[(i*width + j) * 4 + 0] = demosaicPhiMalvar(gbrg, width, i, j);
868 rgba[(i*width + j) * 4 + 1] = gbrg[i*width + j];
869 rgba[(i*width + j) * 4 + 2] = demosaicThetaMalvar(gbrg, width, i, j);
870 } else if (i % 2 == 0 && j % 2 != 0) {
871 rgba[(i*width + j) * 4 + 0] = demosaicCheckerMalvar(gbrg, width, i, j);
872 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(gbrg, width, i, j);
873 rgba[(i*width + j) * 4 + 2] = gbrg[i*width + j];
874 } else if (i % 2 != 0 && j % 2 == 0) {
875 rgba[(i*width + j) * 4 + 0] = gbrg[i*width + j];
876 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(gbrg, width, i, j);
877 rgba[(i*width + j) * 4 + 2] = demosaicCheckerMalvar(gbrg, width, i, j);
878 } else {
879 rgba[(i*width + j) * 4 + 0] = demosaicThetaMalvar(gbrg, width, i, j);
880 rgba[(i*width + j) * 4 + 1] = gbrg[i*width + j];
881 rgba[(i*width + j) * 4 + 2] = demosaicPhiMalvar(gbrg, width, i, j);
882 }
883 }
884 }
885}
886
887template<typename T>
888void demosaicGRBGToRGBaMalvarTpl(const T *grbg, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
889{
890 m_assert("width must be >= 4", width >= 4);
891 m_assert("height must be >= 4", height >= 4);
892 m_assert("width must be a multiple of 2", width % 2 == 0);
893 m_assert("height must be a multiple of 2", height % 2 == 0);
894
895 // (0,0)
896 rgba[0] = grbg[1];
897 rgba[1] = grbg[0];
898 rgba[2] = grbg[width];
899
900 // (0,w-1)
901 rgba[(width-1)*4 + 0] = grbg[width - 1];
902 rgba[(width-1)*4 + 1] = grbg[width - 2];
903 rgba[(width-1)*4 + 2] = grbg[2*width - 2];
904
905 // (h-1,0)
906 rgba[((height-1)*width)*4 + 0] = grbg[(height-2)*width + 1];
907 rgba[((height-1)*width)*4 + 1] = grbg[(height-1)*width + 1];
908 rgba[((height-1)*width)*4 + 2] = grbg[(height-1)*width];
909
910 // (h-1,w-1)
911 rgba[((height-1)*width + width-1)*4 + 0] = grbg[(height-1)*width - 1];
912 rgba[((height-1)*width + width-1)*4 + 1] = grbg[height*width - 1];
913 rgba[((height-1)*width + width-1)*4 + 2] = grbg[height*width - 2];
914
915 // i == 0
916 for (unsigned int j = 1; j < width-1; j++) {
917 if (j % 2 == 0) {
918 rgba[j*4 + 0] = static_cast<T>(0.5f*grbg[j - 1] + 0.5f*grbg[j + 1]);
919 rgba[j*4 + 1] = grbg[j];
920 rgba[j*4 + 2] = grbg[width + j];
921 } else {
922 rgba[j*4 + 0] = grbg[j];
923 rgba[j*4 + 1] = static_cast<T>(0.5f*grbg[j - 1] + 0.5f*grbg[j + 1]);
924 rgba[j*4 + 2] = static_cast<T>(0.5f*grbg[width + j - 1] + 0.5f*grbg[width + j + 1]);
925 }
926 }
927
928 // i == 1
929 for (unsigned int j = 1; j < width-1; j++) {
930 if (j % 2 == 0) {
931 rgba[(width + j)*4 + 0] = static_cast<T>(0.25f*grbg[j - 1] + 0.25f*grbg[j + 1] + 0.25f*grbg[2*width + j - 1] + 0.25f*grbg[2*width + j + 1]);
932 rgba[(width + j)*4 + 1] = static_cast<T>(0.25f*grbg[j] + 0.25f*grbg[width + j - 1] + 0.25f*grbg[width + j + 1] + 0.25f*grbg[2*width + j]);
933 rgba[(width + j)*4 + 2] = grbg[width + j];
934 } else {
935 rgba[(width + j)*4 + 0] = static_cast<T>(0.5f*grbg[j] + 0.5f*grbg[2*width + j]);
936 rgba[(width + j)*4 + 1] = grbg[width + j];
937 rgba[(width + j)*4 + 2] = static_cast<T>(0.5f*grbg[width + j - 1] + 0.5f*grbg[width + j + 1]);
938 }
939 }
940
941 // j == 0
942 for (unsigned int i = 1; i < height-1; i++) {
943 if (i % 2 == 0) {
944 rgba[i*width*4 + 0] = grbg[i*width + 1];
945 rgba[i*width*4 + 1] = grbg[i*width];
946 rgba[i*width*4 + 2] = static_cast<T>(0.5f*grbg[(i-1)*width] + 0.5f*grbg[(i+1)*width]);
947 } else {
948 rgba[i*width*4 + 0] = static_cast<T>(0.5f*grbg[(i-1)*width + 1] + 0.5f*grbg[(i+1)*width + 1]);
949 rgba[i*width*4 + 1] = grbg[i*width + 1];
950 rgba[i*width*4 + 2] = grbg[i*width];
951 }
952 }
953
954 // j == 1
955 for (unsigned int i = 1; i < height-1; i++) {
956 if (i % 2 == 0) {
957 rgba[(i*width + 1)*4 + 0] = grbg[i*width + 1];
958 rgba[(i*width + 1)*4 + 1] = static_cast<T>(0.25f*grbg[(i-1)*width + 1] + 0.25f*grbg[i*width] + 0.25f*grbg[i*width + 2] + 0.25f*grbg[(i+1)*width + 1]);
959 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.25f*grbg[(i-1)*width] + 0.25f*grbg[(i-1)*width + 2] + 0.25f*grbg[(i+1)*width] + 0.25f*grbg[(i+1)*width + 2]);
960 } else {
961 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.5f*grbg[(i-1)*width + 1] + 0.5f*grbg[(i+1)*width + 1]);
962 rgba[(i*width + 1)*4 + 1] = grbg[i*width + 1];
963 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.5f*grbg[i*width] + 0.5f*grbg[i*width + 2]);
964 }
965 }
966
967 // j == width-2
968 for (unsigned int i = 1; i < height-1; i++) {
969 if (i % 2 == 0) {
970 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.5f*grbg[(i+1)*width - 3] + 0.5f*grbg[(i+1)*width - 1]);
971 rgba[(i*width + width-2)*4 + 1] = grbg[(i+1)*width - 2];
972 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.5f*grbg[i*width - 2] + 0.5f*grbg[(i+2)*width - 2]);
973 } else {
974 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.25f*grbg[i*width - 3] + 0.25f*grbg[i*width - 1] + 0.25f*grbg[(i+2)*width - 3] + 0.25f*grbg[(i+2)*width - 1]);
975 rgba[(i*width + width-2)*4 + 1] = static_cast<T>(0.25f*grbg[i*width - 2] + 0.25f*grbg[(i+1)*width - 3] + 0.25f*grbg[(i+1)*width - 1] + 0.25f*grbg[(i+2)*width - 2]);
976 rgba[(i*width + width-2)*4 + 2] = grbg[(i+1)*width - 2];
977 }
978 }
979
980 // j == width-1
981 for (unsigned int i = 1; i < height-1; i++) {
982 if (i % 2 == 0) {
983 rgba[(i*width + width-1)*4 + 0] = grbg[(i+1)*width - 1];
984 rgba[(i*width + width-1)*4 + 1] = grbg[(i+1)*width - 2];
985 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*grbg[i*width - 2] + 0.5f*grbg[(i+2)*width - 2]);
986 } else {
987 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*grbg[i*width - 1] + 0.5f*grbg[(i+2)*width - 1]);
988 rgba[(i*width + width-1)*4 + 1] = grbg[(i+1)*width - 1];
989 rgba[(i*width + width-1)*4 + 2] = grbg[(i+1)*width - 2];
990 }
991 }
992
993 // i == height-2
994 for (unsigned int j = 1; j < width-1; j++) {
995 if (j % 2 == 0) {
996 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.5f*grbg[(height-2)*width + j - 1] + 0.5f*grbg[(height-2)*width + j + 1]);
997 rgba[((height-2)*width + j)*4 + 1] = grbg[(height-2)*width + j];
998 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.5f*grbg[(height-3)*width + j] + 0.5f*grbg[(height-1)*width + j]);
999 } else {
1000 rgba[((height-2)*width + j)*4 + 0] = grbg[(height-2)*width + j];
1001 rgba[((height-2)*width + j)*4 + 1] = static_cast<T>(0.25f*grbg[(height-3)*width + j] + 0.25f*grbg[(height-2)*width + j - 1] +
1002 0.25f*grbg[(height-2)*width + j + 1] + 0.25f*grbg[(height-1)*width + j]);
1003 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.25f*grbg[(height-3)*width + j - 1] + 0.25f*grbg[(height-3)*width + j + 1] +
1004 0.25f*grbg[(height-1)*width + j - 1] + 0.25f*grbg[(height-1)*width + j + 1]);
1005 }
1006 }
1007
1008 // i == height-1
1009 for (unsigned int j = 1; j < width-1; j++) {
1010 if (j % 2 == 0) {
1011 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*grbg[(height-2)*width + j - 1] + 0.5f*grbg[(height-2)*width + j + 1]);
1012 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*grbg[(height-1)*width + j - 1] + 0.5f*grbg[(height-1)*width + j + 1]);
1013 rgba[((height-1)*width + j)*4 + 2] = grbg[(height-1)*width + j];
1014 } else {
1015 rgba[((height-1)*width + j)*4 + 0] = grbg[(height-2)*width + j];
1016 rgba[((height-1)*width + j)*4 + 1] = grbg[(height-1)*width + j];
1017 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*grbg[(height-1)*width + j - 1] + 0.5f*grbg[(height-1)*width + j + 1]);
1018 }
1019 }
1020
1021#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
1022 if (nThreads > 0) {
1023 omp_set_num_threads(static_cast<int>(nThreads));
1024 }
1025 #pragma omp parallel for schedule(dynamic)
1026#else
1027 (void) nThreads;
1028#endif
1029 for (unsigned int i = 2; i < height-2; i++) {
1030 for (unsigned int j = 2; j < width-2; j++) {
1031 if (i % 2 == 0 && j % 2 == 0) {
1032 rgba[(i*width + j) * 4 + 0] = demosaicThetaMalvar(grbg, width, i, j);
1033 rgba[(i*width + j) * 4 + 1] = grbg[i*width + j];
1034 rgba[(i*width + j) * 4 + 2] = demosaicPhiMalvar(grbg, width, i, j);
1035 } else if (i % 2 == 0 && j % 2 != 0) {
1036 rgba[(i*width + j) * 4 + 0] = grbg[i*width + j];
1037 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(grbg, width, i, j);
1038 rgba[(i*width + j) * 4 + 2] = demosaicCheckerMalvar(grbg, width, i, j);
1039 } else if (i % 2 != 0 && j % 2 == 0) {
1040 rgba[(i*width + j) * 4 + 0] = demosaicCheckerMalvar(grbg, width, i, j);
1041 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(grbg, width, i, j);
1042 rgba[(i*width + j) * 4 + 2] = grbg[i*width + j];
1043 } else {
1044 rgba[(i*width + j) * 4 + 0] = demosaicPhiMalvar(grbg, width, i, j);
1045 rgba[(i*width + j) * 4 + 1] = grbg[i*width + j];
1046 rgba[(i*width + j) * 4 + 2] = demosaicThetaMalvar(grbg, width, i, j);
1047 }
1048 }
1049 }
1050}
1051
1052template<typename T>
1053void demosaicRGGBToRGBaMalvarTpl(const T *rggb, T *rgba, unsigned int width, unsigned int height, unsigned int nThreads)
1054{
1055 m_assert("width must be >= 4", width >= 4);
1056 m_assert("height must be >= 4", height >= 4);
1057 m_assert("width must be a multiple of 2", width % 2 == 0);
1058 m_assert("height must be a multiple of 2", height % 2 == 0);
1059
1060 // (0,0)
1061 rgba[0] = rggb[0];
1062 rgba[1] = rggb[1];
1063 rgba[2] = rggb[width + 1];
1064
1065 // (0,w-1)
1066 rgba[(width-1)*4 + 0] = rggb[width - 2];
1067 rgba[(width-1)*4 + 1] = rggb[width - 1];
1068 rgba[(width-1)*4 + 2] = rggb[2*width - 1];
1069
1070 // (h-1,0)
1071 rgba[((height-1)*width)*4 + 0] = rggb[(height-2)*width];
1072 rgba[((height-1)*width)*4 + 1] = rggb[(height-1)*width];
1073 rgba[((height-1)*width)*4 + 2] = rggb[(height-1)*width + 1];
1074
1075 // (h-1,w-1)
1076 rgba[((height-1)*width + width-1)*4 + 0] = rggb[(height-1)*width - 2];
1077 rgba[((height-1)*width + width-1)*4 + 1] = rggb[height*width - 2];
1078 rgba[((height-1)*width + width-1)*4 + 2] = rggb[height*width - 1];
1079
1080 // i == 0
1081 for (unsigned int j = 1; j < width-1; j++) {
1082 if (j % 2 == 0) {
1083 rgba[j*4 + 0] = rggb[j];
1084 rgba[j*4 + 1] = static_cast<T>(0.5f*rggb[j - 1] + 0.5f*rggb[j + 1]);
1085 rgba[j*4 + 2] = static_cast<T>(0.5f*rggb[width + j - 1] + 0.5f*rggb[width + j + 1]);
1086 } else {
1087 rgba[j*4 + 0] = static_cast<T>(0.5f*rggb[j - 1] + 0.5f*rggb[j + 1]);
1088 rgba[j*4 + 1] = rggb[j];
1089 rgba[j*4 + 2] = rggb[width + j];
1090 }
1091 }
1092
1093 // i == 1
1094 for (unsigned int j = 1; j < width-1; j++) {
1095 if (j % 2 == 0) {
1096 rgba[(width + j)*4 + 0] = static_cast<T>(0.5f*rggb[j] + 0.5f*rggb[2*width + j]);
1097 rgba[(width + j)*4 + 1] = rggb[width + j];
1098 rgba[(width + j)*4 + 2] = static_cast<T>(0.5f*rggb[width + j - 1] + 0.5f*rggb[width + j + 1]);
1099 } else {
1100 rgba[(width + j)*4 + 0] = static_cast<T>(0.25f*rggb[j - 1] + 0.25f*rggb[j + 1] + 0.25f*rggb[2*width + j - 1] + 0.25f*rggb[2*width + j + 1]);
1101 rgba[(width + j)*4 + 1] = static_cast<T>(0.25f*rggb[j] + 0.25f*rggb[width + j - 1] + 0.25f*rggb[width + j + 1] + 0.25f*rggb[2*width + j]);
1102 rgba[(width + j)*4 + 2] = rggb[width + j];
1103 }
1104 }
1105
1106 // j == 0
1107 for (unsigned int i = 1; i < height-1; i++) {
1108 if (i % 2 == 0) {
1109 rgba[i*width*4 + 0] = rggb[i*width];
1110 rgba[i*width*4 + 1] = rggb[i*width + 1];
1111 rgba[i*width*4 + 2] = static_cast<T>(0.5f*rggb[(i-1)*width + 1] + 0.5f*rggb[(i+1)*width + 1]);
1112 } else {
1113 rgba[i*width*4 + 0] = static_cast<T>(0.5f*rggb[(i-1)*width] + 0.5f*rggb[(i+1)*width]);
1114 rgba[i*width*4 + 1] = rggb[i*width];
1115 rgba[i*width*4 + 2] = rggb[i*width + 1];
1116 }
1117 }
1118
1119 // j == 1
1120 for (unsigned int i = 1; i < height-1; i++) {
1121 if (i % 2 == 0) {
1122 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.5f*rggb[i*width] + 0.5f*rggb[i*width + 2]);
1123 rgba[(i*width + 1)*4 + 1] = rggb[i*width + 1];
1124 rgba[(i*width + 1)*4 + 2] = static_cast<T>(0.5f*rggb[(i-1)*width + 1] + 0.5f*rggb[(i+1)*width + 1]);
1125 } else {
1126 rgba[(i*width + 1)*4 + 0] = static_cast<T>(0.25f*rggb[(i-1)*width] + 0.25f*rggb[(i-1)*width + 2] + 0.25f*rggb[(i+1)*width] + 0.25f*rggb[(i+1)*width + 2]);
1127 rgba[(i*width + 1)*4 + 1] = static_cast<T>(0.25f*rggb[(i-1)*width + 1] + 0.25f*rggb[i*width] + 0.25f*rggb[i*width + 2] + 0.25f*rggb[(i+1)*width + 1]);
1128 rgba[(i*width + 1)*4 + 2] = rggb[i*width + 1];
1129 }
1130 }
1131
1132 // j == width-2
1133 for (unsigned int i = 1; i < height-1; i++) {
1134 if (i % 2 == 0) {
1135 rgba[(i*width + width-2)*4 + 0] = rggb[(i+1)*width - 2];
1136 rgba[(i*width + width-2)*4 + 1] = static_cast<T>(0.25f*rggb[i*width - 2] + 0.25f*rggb[(i+1)*width - 3] + 0.25f*rggb[(i+1)*width - 1] + 0.25f*rggb[(i+2)*width - 2]);
1137 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.25f*rggb[i*width - 3] + 0.25f*rggb[i*width - 1] + 0.25f*rggb[(i+2)*width - 3] + 0.25f*rggb[(i+2)*width - 1]);
1138 } else {
1139 rgba[(i*width + width-2)*4 + 0] = static_cast<T>(0.5f*rggb[i*width - 2] + 0.5f*rggb[(i+2)*width - 2]);
1140 rgba[(i*width + width-2)*4 + 1] = rggb[(i+1)*width - 2];
1141 rgba[(i*width + width-2)*4 + 2] = static_cast<T>(0.5f*rggb[(i+1)*width - 3] + 0.5f*rggb[(i+1)*width - 1]);
1142 }
1143 }
1144
1145 // j == width-1
1146 for (unsigned int i = 1; i < height-1; i++) {
1147 if (i % 2 == 0) {
1148 rgba[(i*width + width-1)*4 + 0] = rggb[(i+1)*width - 2];
1149 rgba[(i*width + width-1)*4 + 1] = rggb[(i+1)*width - 1];
1150 rgba[(i*width + width-1)*4 + 2] = static_cast<T>(0.5f*rggb[i*width - 1] + 0.5f*rggb[(i+2)*width - 1]);
1151 } else {
1152 rgba[(i*width + width-1)*4 + 0] = static_cast<T>(0.5f*rggb[i*width - 2] + 0.5f*rggb[(i+2)*width - 2]);
1153 rgba[(i*width + width-1)*4 + 1] = rggb[(i+1)*width - 2];
1154 rgba[(i*width + width-1)*4 + 2] = rggb[(i+1)*width - 1];
1155 }
1156 }
1157
1158 // i == height-2
1159 for (unsigned int j = 1; j < width-1; j++) {
1160 if (j % 2 == 0) {
1161 rgba[((height-2)*width + j)*4 + 0] = rggb[(height-2)*width + j];
1162 rgba[((height-2)*width + j)*4 + 1] = static_cast<T>(0.25f*rggb[(height-3)*width + j] + 0.25f*rggb[(height-2)*width + j - 1] +
1163 0.25f*rggb[(height-2)*width + j + 1] + 0.25f*rggb[(height-1)*width + j]);
1164 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.25f*rggb[(height-3)*width + j - 1] + 0.25f*rggb[(height-3)*width + j + 1] +
1165 0.25f*rggb[(height-1)*width + j - 1] + 0.25f*rggb[(height-1)*width + j + 1]);
1166 } else {
1167 rgba[((height-2)*width + j)*4 + 0] = static_cast<T>(0.5f*rggb[(height-2)*width + j - 1] + 0.5f*rggb[(height-2)*width + j + 1]);
1168 rgba[((height-2)*width + j)*4 + 1] = rggb[(height-2)*width + j];
1169 rgba[((height-2)*width + j)*4 + 2] = static_cast<T>(0.5f*rggb[(height-3)*width + j] + 0.5f*rggb[(height-1)*width + j]);
1170 }
1171 }
1172
1173 // i == height-1
1174 for (unsigned int j = 1; j < width-1; j++) {
1175 if (j % 2 == 0) {
1176 rgba[((height-1)*width + j)*4 + 0] = rggb[(height-2)*width + j];
1177 rgba[((height-1)*width + j)*4 + 1] = rggb[(height-1)*width + j];
1178 rgba[((height-1)*width + j)*4 + 2] = static_cast<T>(0.5f*rggb[(height-1)*width + j - 1] + 0.5f*rggb[(height-1)*width + j + 1]);
1179 } else {
1180 rgba[((height-1)*width + j)*4 + 0] = static_cast<T>(0.5f*rggb[(height-2)*width + j - 1] + 0.5f*rggb[(height-2)*width + j + 1]);
1181 rgba[((height-1)*width + j)*4 + 1] = static_cast<T>(0.5f*rggb[(height-1)*width + j - 1] + 0.5f*rggb[(height-1)*width + j + 1]);
1182 rgba[((height-1)*width + j)*4 + 2] = rggb[(height-1)*width + j];
1183 }
1184 }
1185
1186#if defined _OPENMP && _OPENMP >= 200711 // OpenMP 3.1
1187 if (nThreads > 0) {
1188 omp_set_num_threads(static_cast<int>(nThreads));
1189 }
1190 #pragma omp parallel for schedule(dynamic)
1191#else
1192 (void) nThreads;
1193#endif
1194 for (unsigned int i = 2; i < height-2; i++) {
1195 for (unsigned int j = 2; j < width-2; j++) {
1196 if (i % 2 == 0 && j % 2 == 0) {
1197 rgba[(i*width + j) * 4 + 0] = rggb[i*width + j];
1198 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(rggb, width, i, j);
1199 rgba[(i*width + j) * 4 + 2] = demosaicCheckerMalvar(rggb, width, i, j);
1200 } else if (i % 2 == 0 && j % 2 != 0) {
1201 rgba[(i*width + j) * 4 + 0] = demosaicThetaMalvar(rggb, width, i, j);
1202 rgba[(i*width + j) * 4 + 1] = rggb[i*width + j];
1203 rgba[(i*width + j) * 4 + 2] = demosaicPhiMalvar(rggb, width, i, j);
1204 } else if (i % 2 != 0 && j % 2 == 0) {
1205 rgba[(i*width + j) * 4 + 0] = demosaicPhiMalvar(rggb, width, i, j);
1206 rgba[(i*width + j) * 4 + 1] = rggb[i*width + j];
1207 rgba[(i*width + j) * 4 + 2] = demosaicThetaMalvar(rggb, width, i, j);
1208 } else {
1209 rgba[(i*width + j) * 4 + 0] = demosaicCheckerMalvar(rggb, width, i, j);
1210 rgba[(i*width + j) * 4 + 1] = demosaicCrossMalvar(rggb, width, i, j);
1211 rgba[(i*width + j) * 4 + 2] = rggb[i*width + j];
1212 }
1213 }
1214 }
1215}
1216
1217#endif