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