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