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