Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
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
53 template <typename T>
54 T 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 
59 template <typename T>
60 T 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 
65 template <typename T>
66 T 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 
71 template <typename T>
72 T 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
78 template <typename T>
79 T 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 
86 template <typename T>
87 T 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 
94 template <typename T>
95 T 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 
102 template <typename T>
103 T 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 
109 template <typename T>
110 void 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 
220 template<typename T>
221 void 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 
331 template<typename T>
332 void 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 
442 template<typename T>
443 void 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 
555 template<typename T>
556 void 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 
720 template<typename T>
721 void 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 
887 template<typename T>
888 void 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 
1052 template<typename T>
1053 void 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