Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
amaze.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011 Henrik Andersson.
4 Copyright (C) 2011-2012 johannes hanika.
5 Copyright (C) 2011 Kaminsky Andrey.
6 Copyright (C) 2012 Richard Wonka.
7 Copyright (C) 2012, 2014, 2016 Tobias Ellinghaus.
8 Copyright (C) 2012 Ulrich Pegelow.
9 Copyright (C) 2013 Pascal de Bruijn.
10 Copyright (C) 2014, 2016, 2018 Roman Lebedev.
11 Copyright (C) 2017 luzpaz.
12 Copyright (C) 2018-2019, 2023 Aurélien PIERRE.
13 Copyright (C) 2019 Andreas Schneider.
14 Copyright (C) 2020 Felipe Contreras.
15 Copyright (C) 2020 Hubert Kowalski.
16 Copyright (C) 2020 Pascal Obry.
17 Copyright (C) 2022 Martin Bařinka.
18 Copyright (C) 2025 Alynx Zhou.
19
20 darktable is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation, either version 3 of the License, or
23 (at your option) any later version.
24
25 darktable is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with darktable. If not, see <http://www.gnu.org/licenses/>.
32*/
33
34#define __STDC_FORMAT_MACROS
35
36#include "system/mem_alloc.h"
37#include "system/openmp.h"
39
40
43
44// otherwise the name will be mangled and the linker won't be able to see the function ...
45extern "C" {
47 const dt_dev_pixelpipe_iop_t *piece,
48 const float *const in,
49 float *out,
50 const dt_iop_roi_t *const roi_in,
51 const dt_iop_roi_t *const roi_out,
52 const int filters);
53}
54
55#include <algorithm>
56#include <cmath>
57#include <cstdint>
58#include <cstdlib>
59#include <cstring>
60
61static __inline float clampnan(const float x, const float m, const float M)
62{
63 float r;
64
65 // clamp to [m, M] if x is infinite; return average of m and M if x is NaN; else just return x
66
67 if(!isfinite(x))
68 r = (std::isless(x, m) ? m : (std::isgreater(x, M) ? M : x));
69 else if(isnan(x))
70 r = (m + M) / 2.0f;
71 else // normal number
72 r = x;
73
74 return r;
75}
76
77static __inline float xmul2f(float d)
78{
79 union {
80 float f;
81 uint32_t u;
82 } x;
83 x.f = d;
84 if(x.u & 0x7FFFFFFF) // if f==0 do nothing
85 {
86 x.u += 1 << 23; // add 1 to the exponent
87 }
88 return x.f;
89}
90
91static __inline float xdiv2f(float d)
92{
93 union {
94 float f;
95 uint32_t u;
96 } x;
97 x.f = d;
98 if(x.u & 0x7FFFFFFF) // if f==0 do nothing
99 {
100 x.u -= 1 << 23; // sub 1 from the exponent
101 }
102 return x.f;
103}
104
105static __inline float xdivf(float d, int n)
106{
107 union {
108 float f;
109 uint32_t u;
110 } x;
111 x.f = d;
112 if(x.u & 0x7FFFFFFF) // if f==0 do nothing
113 {
114 x.u -= n << 23; // add n to the exponent
115 }
116 return x.f;
117}
118
119
120/*==================================================================================
121 * begin raw therapee code, hg checkout of march 03, 2016 branch master.
122 *==================================================================================*/
123
124template <typename _Tp> static inline const _Tp SQR(_Tp x)
125{
126 // return std::pow(x,2); Slower than:
127 return (x * x);
128}
129
130template <typename _Tp> static inline const _Tp intp(const _Tp a, const _Tp b, const _Tp c)
131{
132 // calculate a * b + (1 - a) * c
133 // following is valid:
134 // intp(a, b+x, c+x) = intp(a, b, c) + x
135 // intp(a, b*x, c*x) = intp(a, b, c) * x
136 return a * (b - c) + c;
137}
138
139template <typename _Tp> static inline const _Tp LIM(const _Tp a, const _Tp b, const _Tp c)
140{
141 return std::max(b, std::min(a, c));
142}
143
144template <typename _Tp> static inline const _Tp ULIM(const _Tp a, const _Tp b, const _Tp c)
145{
146 return ((b < c) ? LIM(a, b, c) : LIM(a, c, b));
147}
148
149
150
152//
153// AMaZE demosaic algorithm
154// (Aliasing Minimization and Zipper Elimination)
155//
156// copyright (c) 2008-2010 Emil Martinec <ejmartin@uchicago.edu>
157// optimized for speed by Ingo Weyrich
158//
159// incorporating ideas of Luis Sanz Rodrigues and Paul Lee
160//
161// code dated: May 27, 2010
162// latest modification: Ingo Weyrich, January 25, 2016
163//
164// amaze_interpolate_RT.cc is free software: you can redistribute it and/or modify
165// it under the terms of the GNU General Public License as published by
166// the Free Software Foundation, either version 3 of the License, or
167// (at your option) any later version.
168//
169// This program is distributed in the hope that it will be useful,
170// but WITHOUT ANY WARRANTY; without even the implied warranty of
171// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
172// GNU General Public License for more details.
173//
174// You should have received a copy of the GNU General Public License
175// along with this program. If not, see <http://www.gnu.org/licenses/>.
176//
178
179
181void amaze_demosaic_RT(const dt_dev_pixelpipe_iop_t *piece, const float *const in,
182 float *out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
183 const int filters)
184{
185 int winx = roi_out->x;
186 int winy = roi_out->y;
187 int winw = roi_in->width;
188 int winh = roi_in->height;
189
190 const int width = winw, height = winh;
191 const float clip_pt = fminf(piece->dsc_in.processed_maximum[0],
192 fminf(piece->dsc_in.processed_maximum[1], piece->dsc_in.processed_maximum[2]));
193 const float clip_pt8 = 0.8f * clip_pt;
194
195// this allows to pass AMAZETS to the code. On some machines larger AMAZETS is faster
196// If AMAZETS is undefined it will be set to 160, which is the fastest on modern x86/64 machines
197#ifndef AMAZETS
198#define AMAZETS 160
199#endif
200 // Tile size; the image is processed in square tiles to lower memory requirements and facilitate
201 // multi-threading
202 // We assure that Tile size is a multiple of 32 in the range [96;992]
203 constexpr int ts = (AMAZETS & 992) < 96 ? 96 : (AMAZETS & 992);
204 constexpr int tsh = ts / 2; // half of Tile size
205
206 // offset of R pixel within a Bayer quartet
207 int ex, ey;
208
209 // determine GRBG coset; (ey,ex) is the offset of the R subarray
210 if(FC(0, 0, filters) == 1)
211 { // first pixel is G
212 if(FC(0, 1, filters) == 0)
213 {
214 ey = 0;
215 ex = 1;
216 }
217 else
218 {
219 ey = 1;
220 ex = 0;
221 }
222 }
223 else
224 { // first pixel is R or B
225 if(FC(0, 0, filters) == 0)
226 {
227 ey = 0;
228 ex = 0;
229 }
230 else
231 {
232 ey = 1;
233 ex = 1;
234 }
235 }
236
237 // shifts of pointer value to access pixels in vertical and diagonal directions
238 constexpr int v1 = ts, v2 = 2 * ts, v3 = 3 * ts, p1 = -ts + 1, p2 = -2 * ts + 2, p3 = -3 * ts + 3,
239 m1 = ts + 1, m2 = 2 * ts + 2, m3 = 3 * ts + 3;
240
241 // tolerance to avoid dividing by zero
242 constexpr float eps = 1e-5, epssq = 1e-10; // tolerance to avoid dividing by zero
243
244 // adaptive ratios threshold
245 constexpr float arthresh = 0.75;
246
247 // gaussian on 5x5 quincunx, sigma=1.2
248 constexpr float gaussodd[4]
249 = { 0.14659727707323927f, 0.103592713382435f, 0.0732036125103057f, 0.0365543548389495f };
250 // nyquist texture test threshold
251 constexpr float nyqthresh = 0.5;
252 // gaussian on 5x5, sigma=1.2, multiplied with nyqthresh to save some time later in loop
253 // Is this really sigma=1.2????, seems more like sigma = 1.672
254 constexpr float gaussgrad[6] = { nyqthresh * 0.07384411893421103f, nyqthresh * 0.06207511968171489f,
255 nyqthresh * 0.0521818194747806f, nyqthresh * 0.03687419286733595f,
256 nyqthresh * 0.03099732204057846f, nyqthresh * 0.018413194161458882f };
257 // gaussian on 5x5 alt quincunx, sigma=1.5
258 constexpr float gausseven[2] = { 0.13719494435797422f, 0.05640252782101291f };
259 // gaussian on quincunx grid
260 constexpr float gquinc[4] = { 0.169917f, 0.108947f, 0.069855f, 0.0287182f };
261
262 typedef struct
263 {
264 float h;
265 float v;
266 } s_hv;
267
268#ifdef _OPENMP
269#pragma omp parallel
270#endif
271 {
272 // int progresscounter = 0;
273
274 constexpr int cldf = 2; // factor to multiply cache line distance. 1 = 64 bytes, 2 = 128 bytes ...
275 // assign working space
276 char *buffer
277 = (char *)calloc(sizeof(float) * 14 * ts * ts + sizeof(char) * ts * tsh + 18 * cldf * 64 + 63, 1);
278 // aligned to 64 byte boundary
279 char *data = (char *)((uintptr_t(buffer) + uintptr_t(63)) / 64 * 64);
280
281 // green values
282 float *rgbgreen = (float(*))data;
283 // sum of square of horizontal gradient and square of vertical gradient
284 float *delhvsqsum = (float(*))((char *)rgbgreen + sizeof(float) * ts * ts + cldf * 64); // 1
285 // gradient based directional weights for interpolation
286 float *dirwts0 = (float(*))((char *)delhvsqsum + sizeof(float) * ts * ts + cldf * 64); // 1
287 float *dirwts1 = (float(*))((char *)dirwts0 + sizeof(float) * ts * ts + cldf * 64); // 1
288 // vertically interpolated colour differences G-R, G-B
289 float *vcd = (float(*))((char *)dirwts1 + sizeof(float) * ts * ts + cldf * 64); // 1
290 // horizontally interpolated colour differences
291 float *hcd = (float(*))((char *)vcd + sizeof(float) * ts * ts + cldf * 64); // 1
292 // alternative vertical interpolation
293 float *vcdalt = (float(*))((char *)hcd + sizeof(float) * ts * ts + cldf * 64); // 1
294 // alternative horizontal interpolation
295 float *hcdalt = (float(*))((char *)vcdalt + sizeof(float) * ts * ts + cldf * 64); // 1
296 // square of average colour difference
297 float *cddiffsq = (float(*))((char *)hcdalt + sizeof(float) * ts * ts + cldf * 64); // 1
298 // weight to give horizontal vs vertical interpolation
299 float *hvwt = (float(*))((char *)cddiffsq + sizeof(float) * ts * ts + 2 * cldf * 64); // 1
300 // final interpolated colour difference
301 float(*Dgrb)[ts * tsh] = (float(*)[ts * tsh])vcdalt; // there is no overlap in buffer usage => share
302 // gradient in plus (NE/SW) direction
303 float *delp = (float(*))cddiffsq; // there is no overlap in buffer usage => share
304 // gradient in minus (NW/SE) direction
305 float *delm = (float(*))((char *)delp + sizeof(float) * ts * tsh + cldf * 64);
306 // diagonal interpolation of R+B
307 float *rbint = (float(*))delm; // there is no overlap in buffer usage => share
308 // horizontal and vertical curvature of interpolated G (used to refine interpolation in Nyquist texture
309 // regions)
310 s_hv *Dgrb2 = (s_hv(*))((char *)hvwt + sizeof(float) * ts * tsh + cldf * 64); // 1
311 // difference between up/down interpolations of G
312 float *dgintv = (float(*))Dgrb2; // there is no overlap in buffer usage => share
313 // difference between left/right interpolations of G
314 float *dginth = (float(*))((char *)dgintv + sizeof(float) * ts * ts + cldf * 64); // 1
315 // square of diagonal colour differences
316 float *Dgrbsq1m = (float(*))((char *)dginth + sizeof(float) * ts * ts + cldf * 64); // 1
317 float *Dgrbsq1p = (float(*))((char *)Dgrbsq1m + sizeof(float) * ts * tsh + cldf * 64); // 1
318 // tile raw data
319 float *cfa = (float(*))((char *)Dgrbsq1p + sizeof(float) * ts * tsh + cldf * 64); // 1
320 // relative weight for combining plus and minus diagonal interpolations
321 float *pmwt = (float(*))delhvsqsum; // there is no overlap in buffer usage => share
322 // interpolated colour difference R-B in minus and plus direction
323 float *rbm = (float(*))vcd; // there is no overlap in buffer usage => share
324 float *rbp = (float(*))((char *)rbm + sizeof(float) * ts * tsh + cldf * 64);
325 // nyquist texture flags 1=nyquist, 0=not nyquist
326 unsigned char *nyquist = (unsigned char(*))((char *)cfa + sizeof(float) * ts * ts + cldf * 64); // 1
327 unsigned char *nyquist2 = (unsigned char(*))cddiffsq;
328 float *nyqutest = (float(*))((char *)nyquist + sizeof(unsigned char) * ts * tsh + cldf * 64); // 1
329
330// Main algorithm: Tile loop
331// use collapse(2) to collapse the 2 loops to one large loop, so there is better scaling
332
333 __OMP_FOR_SIMD__(collapse(2))
334
335 for(int top = winy - 16; top < winy + height; top += ts - 32)
336 {
337 for(int left = winx - 16; left < winx + width; left += ts - 32)
338 {
339 memset(&nyquist[3 * tsh], 0, sizeof(unsigned char) * (ts - 6) * tsh);
340 // location of tile bottom edge
341 int bottom = MIN(top + ts, winy + height + 16);
342 // location of tile right edge
343 int right = MIN(left + ts, winx + width + 16);
344 // tile width (=ts except for right edge of image)
345 int rr1 = bottom - top;
346 // tile height (=ts except for bottom edge of image)
347 int cc1 = right - left;
348 // bookkeeping for borders
349 // min and max row/column in the tile
350 int rrmin = top < winy ? 16 : 0;
351 int ccmin = left < winx ? 16 : 0;
352 int rrmax = bottom > (winy + height) ? winy + height - top : rr1;
353 int ccmax = right > (winx + width) ? winx + width - left : cc1;
354
355// rgb from input CFA data
356// rgb values should be floating point number between 0 and 1
357// after white balance multipliers are applied
358// a 16 pixel border is added to each side of the image
359
360// begin of tile initialization
361 // fill upper border
362 if(rrmin > 0)
363 {
364 for(int rr = 0; rr < 16; rr++)
365 for(int cc = ccmin, row = 32 - rr + top; cc < ccmax; cc++)
366 {
367 cfa[rr * ts + cc] = (in[row * width + (cc + left)]);
368 rgbgreen[rr * ts + cc] = cfa[rr * ts + cc];
369 }
370 }
371
372 // fill inner part
373 for(int rr = rrmin; rr < rrmax; rr++)
374 {
375 int row = rr + top;
376
377 for(int cc = ccmin; cc < ccmax; cc++)
378 {
379 int indx1 = rr * ts + cc;
380 cfa[indx1] = (in[row * width + (cc + left)]);
381 rgbgreen[indx1] = cfa[indx1];
382 }
383 }
384
385 // fill lower border
386 if(rrmax < rr1)
387 {
388 for(int rr = 0; rr < 16; rr++)
389 for(int cc = ccmin; cc < ccmax; cc++)
390 {
391 cfa[(rrmax + rr) * ts + cc] = (in[(winy + height - rr - 2) * width + (left + cc)]);
392 rgbgreen[(rrmax + rr) * ts + cc] = cfa[(rrmax + rr) * ts + cc];
393 }
394 }
395
396
397
398 // fill left border
399 if(ccmin > 0)
400 {
401 for(int rr = rrmin; rr < rrmax; rr++)
402 for(int cc = 0, row = rr + top; cc < 16; cc++)
403 {
404 cfa[rr * ts + cc] = (in[row * width + (32 - cc + left)]);
405 rgbgreen[rr * ts + cc] = cfa[rr * ts + cc];
406 }
407 }
408
409 // fill right border
410 if(ccmax < cc1)
411 {
412 for(int rr = rrmin; rr < rrmax; rr++)
413 for(int cc = 0; cc < 16; cc++)
414 {
415 cfa[rr * ts + ccmax + cc] = (in[(top + rr) * width + ((winx + width - cc - 2))]);
416 rgbgreen[rr * ts + ccmax + cc] = cfa[rr * ts + ccmax + cc];
417 }
418 }
419
420 // also, fill the image corners
421 if(rrmin > 0 && ccmin > 0)
422 {
423 for(int rr = 0; rr < 16; rr++)
424 for(int cc = 0; cc < 16; cc++)
425 {
426 cfa[(rr)*ts + cc] = (in[(winy + 32 - rr) * width + (winx + 32 - cc)]);
427 rgbgreen[(rr)*ts + cc] = cfa[(rr)*ts + cc];
428 }
429 }
430
431 if(rrmax < rr1 && ccmax < cc1)
432 {
433 for(int rr = 0; rr < 16; rr++)
434 for(int cc = 0; cc < 16; cc++)
435 {
436 cfa[(rrmax + rr) * ts + ccmax + cc]
437 = (in[(winy + height - rr - 2) * width + ((winx + width - cc - 2))]);
438 rgbgreen[(rrmax + rr) * ts + ccmax + cc] = cfa[(rrmax + rr) * ts + ccmax + cc];
439 }
440 }
441
442 if(rrmin > 0 && ccmax < cc1)
443 {
444 for(int rr = 0; rr < 16; rr++)
445 for(int cc = 0; cc < 16; cc++)
446 {
447 cfa[(rr)*ts + ccmax + cc] = (in[(winy + 32 - rr) * width + ((winx + width - cc - 2))]);
448 rgbgreen[(rr)*ts + ccmax + cc] = cfa[(rr)*ts + ccmax + cc];
449 }
450 }
451
452 if(rrmax < rr1 && ccmin > 0)
453 {
454 for(int rr = 0; rr < 16; rr++)
455 for(int cc = 0; cc < 16; cc++)
456 {
457 cfa[(rrmax + rr) * ts + cc] = (in[(winy + height - rr - 2) * width + ((winx + 32 - cc))]);
458 rgbgreen[(rrmax + rr) * ts + cc] = cfa[(rrmax + rr) * ts + cc];
459 }
460 }
461
462// end of tile initialization
463
464// horizontal and vertical gradients
465 for(int rr = 2; rr < rr1 - 2; rr++)
466 for(int cc = 2, indx = (rr)*ts + cc; cc < cc1 - 2; cc++, indx++)
467 {
468 float delh = fabsf(cfa[indx + 1] - cfa[indx - 1]);
469 float delv = fabsf(cfa[indx + v1] - cfa[indx - v1]);
470 dirwts0[indx]
471 = eps + fabsf(cfa[indx + v2] - cfa[indx]) + fabsf(cfa[indx] - cfa[indx - v2]) + delv;
472 dirwts1[indx] = eps + fabsf(cfa[indx + 2] - cfa[indx]) + fabsf(cfa[indx] - cfa[indx - 2]) + delh;
473 delhvsqsum[indx] = SQR(delh) + SQR(delv);
474 }
475
476// interpolate vertical and horizontal colour differences
477
478 for(int rr = 4; rr < rr1 - 4; rr++)
479 {
480 bool fcswitch = FC(rr, 4, filters) & 1;
481
482 for(int cc = 4, indx = rr * ts + cc; cc < cc1 - 4; cc++, indx++)
483 {
484
485 // colour ratios in each cardinal direction
486 float cru = cfa[indx - v1] * (dirwts0[indx - v2] + dirwts0[indx])
487 / (dirwts0[indx - v2] * (eps + cfa[indx]) + dirwts0[indx] * (eps + cfa[indx - v2]));
488 float crd = cfa[indx + v1] * (dirwts0[indx + v2] + dirwts0[indx])
489 / (dirwts0[indx + v2] * (eps + cfa[indx]) + dirwts0[indx] * (eps + cfa[indx + v2]));
490 float crl = cfa[indx - 1] * (dirwts1[indx - 2] + dirwts1[indx])
491 / (dirwts1[indx - 2] * (eps + cfa[indx]) + dirwts1[indx] * (eps + cfa[indx - 2]));
492 float crr = cfa[indx + 1] * (dirwts1[indx + 2] + dirwts1[indx])
493 / (dirwts1[indx + 2] * (eps + cfa[indx]) + dirwts1[indx] * (eps + cfa[indx + 2]));
494
495 // G interpolated in vert/hor directions using Hamilton-Adams method
496 float guha = cfa[indx - v1] + xdiv2f(cfa[indx] - cfa[indx - v2]);
497 float gdha = cfa[indx + v1] + xdiv2f(cfa[indx] - cfa[indx + v2]);
498 float glha = cfa[indx - 1] + xdiv2f(cfa[indx] - cfa[indx - 2]);
499 float grha = cfa[indx + 1] + xdiv2f(cfa[indx] - cfa[indx + 2]);
500
501 // G interpolated in vert/hor directions using adaptive ratios
502 float guar, gdar, glar, grar;
503
504 if(fabsf(1.f - cru) < arthresh)
505 {
506 guar = cfa[indx] * cru;
507 }
508 else
509 {
510 guar = guha;
511 }
512
513 if(fabsf(1.f - crd) < arthresh)
514 {
515 gdar = cfa[indx] * crd;
516 }
517 else
518 {
519 gdar = gdha;
520 }
521
522 if(fabsf(1.f - crl) < arthresh)
523 {
524 glar = cfa[indx] * crl;
525 }
526 else
527 {
528 glar = glha;
529 }
530
531 if(fabsf(1.f - crr) < arthresh)
532 {
533 grar = cfa[indx] * crr;
534 }
535 else
536 {
537 grar = grha;
538 }
539
540 // adaptive weights for vertical/horizontal directions
541 float hwt = dirwts1[indx - 1] / (dirwts1[indx - 1] + dirwts1[indx + 1]);
542 float vwt = dirwts0[indx - v1] / (dirwts0[indx + v1] + dirwts0[indx - v1]);
543
544 // interpolated G via adaptive weights of cardinal evaluations
545 float Gintvha = vwt * gdha + (1.f - vwt) * guha;
546 float Ginthha = hwt * grha + (1.f - hwt) * glha;
547
548 // interpolated colour differences
549 if(fcswitch)
550 {
551 vcd[indx] = cfa[indx] - (vwt * gdar + (1.f - vwt) * guar);
552 hcd[indx] = cfa[indx] - (hwt * grar + (1.f - hwt) * glar);
553 vcdalt[indx] = cfa[indx] - Gintvha;
554 hcdalt[indx] = cfa[indx] - Ginthha;
555 }
556 else
557 {
558 // interpolated colour differences
559 vcd[indx] = (vwt * gdar + (1.f - vwt) * guar) - cfa[indx];
560 hcd[indx] = (hwt * grar + (1.f - hwt) * glar) - cfa[indx];
561 vcdalt[indx] = Gintvha - cfa[indx];
562 hcdalt[indx] = Ginthha - cfa[indx];
563 }
564
565 fcswitch = !fcswitch;
566
567 if(cfa[indx] > clip_pt8 || Gintvha > clip_pt8 || Ginthha > clip_pt8)
568 {
569 // use HA if highlights are (nearly) clipped
570 guar = guha;
571 gdar = gdha;
572 glar = glha;
573 grar = grha;
574 vcd[indx] = vcdalt[indx];
575 hcd[indx] = hcdalt[indx];
576 }
577
578 // differences of interpolations in opposite directions
579 dgintv[indx] = MIN(SQR(guha - gdha), SQR(guar - gdar));
580 dginth[indx] = MIN(SQR(glha - grha), SQR(glar - grar));
581 }
582 }
583
584
585 for(int rr = 4; rr < rr1 - 4; rr++)
586 {
587 for(int cc = 4, indx = rr * ts + cc, c = FC(rr, cc, filters) & 1; cc < cc1 - 4; cc++, indx++)
588 {
589 float hcdvar = 3.f * (SQR(hcd[indx - 2]) + SQR(hcd[indx]) + SQR(hcd[indx + 2]))
590 - SQR(hcd[indx - 2] + hcd[indx] + hcd[indx + 2]);
591 float hcdaltvar = 3.f * (SQR(hcdalt[indx - 2]) + SQR(hcdalt[indx]) + SQR(hcdalt[indx + 2]))
592 - SQR(hcdalt[indx - 2] + hcdalt[indx] + hcdalt[indx + 2]);
593 float vcdvar = 3.f * (SQR(vcd[indx - v2]) + SQR(vcd[indx]) + SQR(vcd[indx + v2]))
594 - SQR(vcd[indx - v2] + vcd[indx] + vcd[indx + v2]);
595 float vcdaltvar = 3.f * (SQR(vcdalt[indx - v2]) + SQR(vcdalt[indx]) + SQR(vcdalt[indx + v2]))
596 - SQR(vcdalt[indx - v2] + vcdalt[indx] + vcdalt[indx + v2]);
597
598 // choose the smallest variance; this yields a smoother interpolation
599 if(hcdaltvar < hcdvar)
600 {
601 hcd[indx] = hcdalt[indx];
602 }
603
604 if(vcdaltvar < vcdvar)
605 {
606 vcd[indx] = vcdalt[indx];
607 }
608
609 // bound the interpolation in regions of high saturation
610 // vertical and horizontal G interpolations
611 float Gintv, Ginth;
612
613 if(c)
614 { // G site
615 Ginth = -hcd[indx] + cfa[indx]; // R or B
616 Gintv = -vcd[indx] + cfa[indx]; // B or R
617
618 if(hcd[indx] > 0)
619 {
620 if(3.f * hcd[indx] > (Ginth + cfa[indx]))
621 {
622 hcd[indx] = -ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) + cfa[indx];
623 }
624 else
625 {
626 float hwt = 1.f - 3.f * hcd[indx] / (eps + Ginth + cfa[indx]);
627 hcd[indx] = hwt * hcd[indx]
628 + (1.f - hwt) * (-ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) + cfa[indx]);
629 }
630 }
631
632 if(vcd[indx] > 0)
633 {
634 if(3.f * vcd[indx] > (Gintv + cfa[indx]))
635 {
636 vcd[indx] = -ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) + cfa[indx];
637 }
638 else
639 {
640 float vwt = 1.f - 3.f * vcd[indx] / (eps + Gintv + cfa[indx]);
641 vcd[indx] = vwt * vcd[indx]
642 + (1.f - vwt) * (-ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) + cfa[indx]);
643 }
644 }
645
646 if(Ginth > clip_pt)
647 {
648 hcd[indx] = -ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) + cfa[indx];
649 }
650
651 if(Gintv > clip_pt)
652 {
653 vcd[indx] = -ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) + cfa[indx];
654 }
655 }
656 else
657 { // R or B site
658
659 Ginth = hcd[indx] + cfa[indx]; // interpolated G
660 Gintv = vcd[indx] + cfa[indx];
661
662 if(hcd[indx] < 0)
663 {
664 if(3.f * hcd[indx] < -(Ginth + cfa[indx]))
665 {
666 hcd[indx] = ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) - cfa[indx];
667 }
668 else
669 {
670 float hwt = 1.f + 3.f * hcd[indx] / (eps + Ginth + cfa[indx]);
671 hcd[indx] = hwt * hcd[indx]
672 + (1.f - hwt) * (ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) - cfa[indx]);
673 }
674 }
675
676 if(vcd[indx] < 0)
677 {
678 if(3.f * vcd[indx] < -(Gintv + cfa[indx]))
679 {
680 vcd[indx] = ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) - cfa[indx];
681 }
682 else
683 {
684 float vwt = 1.f + 3.f * vcd[indx] / (eps + Gintv + cfa[indx]);
685 vcd[indx] = vwt * vcd[indx]
686 + (1.f - vwt) * (ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) - cfa[indx]);
687 }
688 }
689
690 if(Ginth > clip_pt)
691 {
692 hcd[indx] = ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]) - cfa[indx];
693 }
694
695 if(Gintv > clip_pt)
696 {
697 vcd[indx] = ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]) - cfa[indx];
698 }
699
700 cddiffsq[indx] = SQR(vcd[indx] - hcd[indx]);
701 }
702
703 c = !c;
704 }
705 }
706
707 for(int rr = 6; rr < rr1 - 6; rr++)
708 {
709 for(int cc = 6 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc; cc < cc1 - 6; cc += 2, indx += 2)
710 {
711
712 // compute colour difference variances in cardinal directions
713
714 float uave = vcd[indx] + vcd[indx - v1] + vcd[indx - v2] + vcd[indx - v3];
715 float dave = vcd[indx] + vcd[indx + v1] + vcd[indx + v2] + vcd[indx + v3];
716 float lave = hcd[indx] + hcd[indx - 1] + hcd[indx - 2] + hcd[indx - 3];
717 float rave = hcd[indx] + hcd[indx + 1] + hcd[indx + 2] + hcd[indx + 3];
718
719 // colour difference (G-R or G-B) variance in up/down/left/right directions
720 float Dgrbvvaru = SQR(vcd[indx] - uave) + SQR(vcd[indx - v1] - uave) + SQR(vcd[indx - v2] - uave)
721 + SQR(vcd[indx - v3] - uave);
722 float Dgrbvvard = SQR(vcd[indx] - dave) + SQR(vcd[indx + v1] - dave) + SQR(vcd[indx + v2] - dave)
723 + SQR(vcd[indx + v3] - dave);
724 float Dgrbhvarl = SQR(hcd[indx] - lave) + SQR(hcd[indx - 1] - lave) + SQR(hcd[indx - 2] - lave)
725 + SQR(hcd[indx - 3] - lave);
726 float Dgrbhvarr = SQR(hcd[indx] - rave) + SQR(hcd[indx + 1] - rave) + SQR(hcd[indx + 2] - rave)
727 + SQR(hcd[indx + 3] - rave);
728
729 float hwt = dirwts1[indx - 1] / (dirwts1[indx - 1] + dirwts1[indx + 1]);
730 float vwt = dirwts0[indx - v1] / (dirwts0[indx + v1] + dirwts0[indx - v1]);
731
732 float vcdvar = epssq + vwt * Dgrbvvard + (1.f - vwt) * Dgrbvvaru;
733 float hcdvar = epssq + hwt * Dgrbhvarr + (1.f - hwt) * Dgrbhvarl;
734
735 // compute fluctuations in up/down and left/right interpolations of colours
736 Dgrbvvaru = (dgintv[indx]) + (dgintv[indx - v1]) + (dgintv[indx - v2]);
737 Dgrbvvard = (dgintv[indx]) + (dgintv[indx + v1]) + (dgintv[indx + v2]);
738 Dgrbhvarl = (dginth[indx]) + (dginth[indx - 1]) + (dginth[indx - 2]);
739 Dgrbhvarr = (dginth[indx]) + (dginth[indx + 1]) + (dginth[indx + 2]);
740
741 float vcdvar1 = epssq + vwt * Dgrbvvard + (1.f - vwt) * Dgrbvvaru;
742 float hcdvar1 = epssq + hwt * Dgrbhvarr + (1.f - hwt) * Dgrbhvarl;
743
744 // determine adaptive weights for G interpolation
745 float varwt = hcdvar / (vcdvar + hcdvar);
746 float diffwt = hcdvar1 / (vcdvar1 + hcdvar1);
747
748 // if both agree on interpolation direction, choose the one with strongest directional
749 // discrimination;
750 // otherwise, choose the u/d and l/r difference fluctuation weights
751 if((0.5 - varwt) * (0.5 - diffwt) > 0 && fabsf(0.5f - diffwt) < fabsf(0.5f - varwt))
752 {
753 hvwt[indx >> 1] = varwt;
754 }
755 else
756 {
757 hvwt[indx >> 1] = diffwt;
758 }
759 }
760 }
761
762 // precompute nyquist
763 for(int rr = 6; rr < rr1 - 6; rr++)
764 {
765 int cc = 6 + (FC(rr, 2, filters) & 1);
766 int indx = rr * ts + cc;
767
768 for(; cc < cc1 - 6; cc += 2, indx += 2)
769 {
770 nyqutest[indx >> 1]
771 = (gaussodd[0] * cddiffsq[indx]
772 + gaussodd[1] * (cddiffsq[(indx - m1)] + cddiffsq[(indx + p1)] + cddiffsq[(indx - p1)]
773 + cddiffsq[(indx + m1)])
774 + gaussodd[2] * (cddiffsq[(indx - v2)] + cddiffsq[(indx - 2)] + cddiffsq[(indx + 2)]
775 + cddiffsq[(indx + v2)])
776 + gaussodd[3] * (cddiffsq[(indx - m2)] + cddiffsq[(indx + p2)] + cddiffsq[(indx - p2)]
777 + cddiffsq[(indx + m2)]))
778 - (gaussgrad[0] * delhvsqsum[indx]
779 + gaussgrad[1] * (delhvsqsum[indx - v1] + delhvsqsum[indx + 1] + delhvsqsum[indx - 1]
780 + delhvsqsum[indx + v1])
781 + gaussgrad[2] * (delhvsqsum[indx - m1] + delhvsqsum[indx + p1] + delhvsqsum[indx - p1]
782 + delhvsqsum[indx + m1])
783 + gaussgrad[3] * (delhvsqsum[indx - v2] + delhvsqsum[indx - 2] + delhvsqsum[indx + 2]
784 + delhvsqsum[indx + v2])
785 + gaussgrad[4] * (delhvsqsum[indx - v2 - 1] + delhvsqsum[indx - v2 + 1]
786 + delhvsqsum[indx - ts - 2] + delhvsqsum[indx - ts + 2]
787 + delhvsqsum[indx + ts - 2] + delhvsqsum[indx + ts + 2]
788 + delhvsqsum[indx + v2 - 1] + delhvsqsum[indx + v2 + 1])
789 + gaussgrad[5] * (delhvsqsum[indx - m2] + delhvsqsum[indx + p2] + delhvsqsum[indx - p2]
790 + delhvsqsum[indx + m2]));
791 }
792 }
793
794 // Nyquist test
795 int nystartrow = 0;
796 int nyendrow = 0;
797 int nystartcol = ts + 1;
798 int nyendcol = 0;
799
800 for(int rr = 6; rr < rr1 - 6; rr++)
801 {
802 for(int cc = 6 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc; cc < cc1 - 6; cc += 2, indx += 2)
803 {
804
805 // nyquist texture test: ask if difference of vcd compared to hcd is larger or smaller than RGGB
806 // gradients
807 if(nyqutest[indx >> 1] > 0.f)
808 {
809 nyquist[indx >> 1] = 1; // nyquist=1 for nyquist region
810 nystartrow = nystartrow ? nystartrow : rr;
811 nyendrow = rr;
812 nystartcol = nystartcol > cc ? cc : nystartcol;
813 nyendcol = nyendcol < cc ? cc : nyendcol;
814 }
815 }
816 }
817
818
819 bool doNyquist = nystartrow != nyendrow && nystartcol != nyendcol;
820
821 if(doNyquist)
822 {
823 nyendrow++; // because of < condition
824 nyendcol++; // because of < condition
825 nystartcol -= (nystartcol & 1);
826 nystartrow = std::max(8, nystartrow);
827 nyendrow = std::min(rr1 - 8, nyendrow);
828 nystartcol = std::max(8, nystartcol);
829 nyendcol = std::min(cc1 - 8, nyendcol);
830 memset(&nyquist2[4 * tsh], 0, sizeof(char) * (ts - 8) * tsh);
831
832 for(int rr = nystartrow; rr < nyendrow; rr++)
833 {
834 for(int indx = rr * ts + nystartcol + (FC(rr, 2, filters) & 1); indx < rr * ts + nyendcol;
835 indx += 2)
836 {
837 unsigned int nyquisttemp
838 = (nyquist[(indx - v2) >> 1] + nyquist[(indx - m1) >> 1] + nyquist[(indx + p1) >> 1]
839 + nyquist[(indx - 2) >> 1] + nyquist[(indx + 2) >> 1] + nyquist[(indx - p1) >> 1]
840 + nyquist[(indx + m1) >> 1] + nyquist[(indx + v2) >> 1]);
841 // if most of your neighbours are named Nyquist, it's likely that you're one too, or not
842 nyquist2[indx >> 1] = nyquisttemp > 4 ? 1 : (nyquisttemp < 4 ? 0 : nyquist[indx >> 1]);
843 }
844 }
845
846 // end of Nyquist test
847
848 // in areas of Nyquist texture, do area interpolation
849 for(int rr = nystartrow; rr < nyendrow; rr++)
850 for(int indx = rr * ts + nystartcol + (FC(rr, 2, filters) & 1); indx < rr * ts + nyendcol;
851 indx += 2)
852 {
853
854 if(nyquist2[indx >> 1])
855 {
856 // area interpolation
857
858 float sumcfa = 0.f, sumh = 0.f, sumv = 0.f, sumsqh = 0.f, sumsqv = 0.f, areawt = 0.f;
859
860 for(int i = -6; i < 7; i += 2)
861 {
862 int indx1 = indx + (i * ts) - 6;
863
864 for(int j = -6; j < 7; j += 2, indx1 += 2)
865 {
866 if(nyquist2[indx1 >> 1])
867 {
868 float cfatemp = cfa[indx1];
869 sumcfa += cfatemp;
870 sumh += (cfa[indx1 - 1] + cfa[indx1 + 1]);
871 sumv += (cfa[indx1 - v1] + cfa[indx1 + v1]);
872 sumsqh += SQR(cfatemp - cfa[indx1 - 1]) + SQR(cfatemp - cfa[indx1 + 1]);
873 sumsqv += SQR(cfatemp - cfa[indx1 - v1]) + SQR(cfatemp - cfa[indx1 + v1]);
874 areawt += 1;
875 }
876 }
877 }
878
879 // horizontal and vertical colour differences, and adaptive weight
880 sumh = sumcfa - xdiv2f(sumh);
881 sumv = sumcfa - xdiv2f(sumv);
882 areawt = xdiv2f(areawt);
883 float hcdvar = epssq + fabsf(areawt * sumsqh - sumh * sumh);
884 float vcdvar = epssq + fabsf(areawt * sumsqv - sumv * sumv);
885 hvwt[indx >> 1] = hcdvar / (vcdvar + hcdvar);
886
887 // end of area interpolation
888 }
889 }
890 }
891
892
893 // populate G at R/B sites
894 for(int rr = 8; rr < rr1 - 8; rr++)
895 for(int indx = rr * ts + 8 + (FC(rr, 2, filters) & 1); indx < rr * ts + cc1 - 8; indx += 2)
896 {
897
898 // first ask if one gets more directional discrimination from nearby B/R sites
899 float hvwtalt = xdivf(hvwt[(indx - m1) >> 1] + hvwt[(indx + p1) >> 1] + hvwt[(indx - p1) >> 1]
900 + hvwt[(indx + m1) >> 1],
901 2);
902
903 hvwt[indx >> 1]
904 = fabsf(0.5f - hvwt[indx >> 1]) < fabsf(0.5f - hvwtalt) ? hvwtalt : hvwt[indx >> 1];
905 // a better result was obtained from the neighbours
906
907 Dgrb[0][indx >> 1] = intp(hvwt[indx >> 1], vcd[indx], hcd[indx]); // evaluate colour differences
908
909 rgbgreen[indx] = cfa[indx] + Dgrb[0][indx >> 1]; // evaluate G (finally!)
910
911 // local curvature in G (preparation for nyquist refinement step)
912 Dgrb2[indx >> 1].h = nyquist2[indx >> 1]
913 ? SQR(rgbgreen[indx] - xdiv2f(rgbgreen[indx - 1] + rgbgreen[indx + 1]))
914 : 0.f;
915 Dgrb2[indx >> 1].v = nyquist2[indx >> 1]
916 ? SQR(rgbgreen[indx] - xdiv2f(rgbgreen[indx - v1] + rgbgreen[indx + v1]))
917 : 0.f;
918 }
919
920
921 // end of standard interpolation
922
923 // refine Nyquist areas using G curvatures
924 if(doNyquist)
925 {
926 for(int rr = nystartrow; rr < nyendrow; rr++)
927 for(int indx = rr * ts + nystartcol + (FC(rr, 2, filters) & 1); indx < rr * ts + nyendcol;
928 indx += 2)
929 {
930
931 if(nyquist2[indx >> 1])
932 {
933 // local averages (over Nyquist pixels only) of G curvature squared
934 float gvarh
935 = epssq + (gquinc[0] * Dgrb2[indx >> 1].h
936 + gquinc[1] * (Dgrb2[(indx - m1) >> 1].h + Dgrb2[(indx + p1) >> 1].h
937 + Dgrb2[(indx - p1) >> 1].h + Dgrb2[(indx + m1) >> 1].h)
938 + gquinc[2] * (Dgrb2[(indx - v2) >> 1].h + Dgrb2[(indx - 2) >> 1].h
939 + Dgrb2[(indx + 2) >> 1].h + Dgrb2[(indx + v2) >> 1].h)
940 + gquinc[3] * (Dgrb2[(indx - m2) >> 1].h + Dgrb2[(indx + p2) >> 1].h
941 + Dgrb2[(indx - p2) >> 1].h + Dgrb2[(indx + m2) >> 1].h));
942 float gvarv
943 = epssq + (gquinc[0] * Dgrb2[indx >> 1].v
944 + gquinc[1] * (Dgrb2[(indx - m1) >> 1].v + Dgrb2[(indx + p1) >> 1].v
945 + Dgrb2[(indx - p1) >> 1].v + Dgrb2[(indx + m1) >> 1].v)
946 + gquinc[2] * (Dgrb2[(indx - v2) >> 1].v + Dgrb2[(indx - 2) >> 1].v
947 + Dgrb2[(indx + 2) >> 1].v + Dgrb2[(indx + v2) >> 1].v)
948 + gquinc[3] * (Dgrb2[(indx - m2) >> 1].v + Dgrb2[(indx + p2) >> 1].v
949 + Dgrb2[(indx - p2) >> 1].v + Dgrb2[(indx + m2) >> 1].v));
950 // use the results as weights for refined G interpolation
951 Dgrb[0][indx >> 1] = (hcd[indx] * gvarv + vcd[indx] * gvarh) / (gvarv + gvarh);
952 rgbgreen[indx] = cfa[indx] + Dgrb[0][indx >> 1];
953 }
954 }
955 }
956
957 for(int rr = 6; rr < rr1 - 6; rr++)
958 {
959 if((FC(rr, 2, filters) & 1) == 0)
960 {
961 for(int cc = 6, indx = rr * ts + cc; cc < cc1 - 6; cc += 2, indx += 2)
962 {
963 delp[indx >> 1] = fabsf(cfa[indx + p1] - cfa[indx - p1]);
964 delm[indx >> 1] = fabsf(cfa[indx + m1] - cfa[indx - m1]);
965 Dgrbsq1p[indx >> 1]
966 = (SQR(cfa[indx + 1] - cfa[indx + 1 - p1]) + SQR(cfa[indx + 1] - cfa[indx + 1 + p1]));
967 Dgrbsq1m[indx >> 1]
968 = (SQR(cfa[indx + 1] - cfa[indx + 1 - m1]) + SQR(cfa[indx + 1] - cfa[indx + 1 + m1]));
969 }
970 }
971 else
972 {
973 for(int cc = 6, indx = rr * ts + cc; cc < cc1 - 6; cc += 2, indx += 2)
974 {
975 Dgrbsq1p[indx >> 1] = (SQR(cfa[indx] - cfa[indx - p1]) + SQR(cfa[indx] - cfa[indx + p1]));
976 Dgrbsq1m[indx >> 1] = (SQR(cfa[indx] - cfa[indx - m1]) + SQR(cfa[indx] - cfa[indx + m1]));
977 delp[indx >> 1] = fabsf(cfa[indx + 1 + p1] - cfa[indx + 1 - p1]);
978 delm[indx >> 1] = fabsf(cfa[indx + 1 + m1] - cfa[indx + 1 - m1]);
979 }
980 }
981 }
982
983// diagonal interpolation correction
984
985
986 for(int rr = 8; rr < rr1 - 8; rr++)
987 {
988 for(int cc = 8 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc, indx1 = indx >> 1; cc < cc1 - 8;
989 cc += 2, indx += 2, indx1++)
990 {
991
992 // diagonal colour ratios
993 float crse = xmul2f(cfa[indx + m1]) / (eps + cfa[indx] + (cfa[indx + m2]));
994 float crnw = xmul2f(cfa[indx - m1]) / (eps + cfa[indx] + (cfa[indx - m2]));
995 float crne = xmul2f(cfa[indx + p1]) / (eps + cfa[indx] + (cfa[indx + p2]));
996 float crsw = xmul2f(cfa[indx - p1]) / (eps + cfa[indx] + (cfa[indx - p2]));
997 // colour differences in diagonal directions
998 float rbse, rbnw, rbne, rbsw;
999
1000 // assign B/R at R/B sites
1001 if(fabsf(1.f - crse) < arthresh)
1002 {
1003 rbse = cfa[indx] * crse; // use this if more precise diag interp is necessary
1004 }
1005 else
1006 {
1007 rbse = (cfa[indx + m1]) + xdiv2f(cfa[indx] - cfa[indx + m2]);
1008 }
1009
1010 if(fabsf(1.f - crnw) < arthresh)
1011 {
1012 rbnw = cfa[indx] * crnw;
1013 }
1014 else
1015 {
1016 rbnw = (cfa[indx - m1]) + xdiv2f(cfa[indx] - cfa[indx - m2]);
1017 }
1018
1019 if(fabsf(1.f - crne) < arthresh)
1020 {
1021 rbne = cfa[indx] * crne;
1022 }
1023 else
1024 {
1025 rbne = (cfa[indx + p1]) + xdiv2f(cfa[indx] - cfa[indx + p2]);
1026 }
1027
1028 if(fabsf(1.f - crsw) < arthresh)
1029 {
1030 rbsw = cfa[indx] * crsw;
1031 }
1032 else
1033 {
1034 rbsw = (cfa[indx - p1]) + xdiv2f(cfa[indx] - cfa[indx - p2]);
1035 }
1036
1037 float wtse = eps + delm[indx1] + delm[(indx + m1) >> 1]
1038 + delm[(indx + m2) >> 1]; // same as for wtu,wtd,wtl,wtr
1039 float wtnw = eps + delm[indx1] + delm[(indx - m1) >> 1] + delm[(indx - m2) >> 1];
1040 float wtne = eps + delp[indx1] + delp[(indx + p1) >> 1] + delp[(indx + p2) >> 1];
1041 float wtsw = eps + delp[indx1] + delp[(indx - p1) >> 1] + delp[(indx - p2) >> 1];
1042
1043
1044 rbm[indx1] = (wtse * rbnw + wtnw * rbse) / (wtse + wtnw);
1045 rbp[indx1] = (wtne * rbsw + wtsw * rbne) / (wtne + wtsw);
1046
1047 // variance of R-B in plus/minus directions
1048 float rbvarm
1049 = epssq
1050 + (gausseven[0] * (Dgrbsq1m[(indx - v1) >> 1] + Dgrbsq1m[(indx - 1) >> 1]
1051 + Dgrbsq1m[(indx + 1) >> 1] + Dgrbsq1m[(indx + v1) >> 1])
1052 + gausseven[1] * (Dgrbsq1m[(indx - v2 - 1) >> 1] + Dgrbsq1m[(indx - v2 + 1) >> 1]
1053 + Dgrbsq1m[(indx - 2 - v1) >> 1] + Dgrbsq1m[(indx + 2 - v1) >> 1]
1054 + Dgrbsq1m[(indx - 2 + v1) >> 1] + Dgrbsq1m[(indx + 2 + v1) >> 1]
1055 + Dgrbsq1m[(indx + v2 - 1) >> 1] + Dgrbsq1m[(indx + v2 + 1) >> 1]));
1056 pmwt[indx1]
1057 = rbvarm
1058 / ((epssq + (gausseven[0] * (Dgrbsq1p[(indx - v1) >> 1] + Dgrbsq1p[(indx - 1) >> 1]
1059 + Dgrbsq1p[(indx + 1) >> 1] + Dgrbsq1p[(indx + v1) >> 1])
1060 + gausseven[1]
1061 * (Dgrbsq1p[(indx - v2 - 1) >> 1] + Dgrbsq1p[(indx - v2 + 1) >> 1]
1062 + Dgrbsq1p[(indx - 2 - v1) >> 1] + Dgrbsq1p[(indx + 2 - v1) >> 1]
1063 + Dgrbsq1p[(indx - 2 + v1) >> 1] + Dgrbsq1p[(indx + 2 + v1) >> 1]
1064 + Dgrbsq1p[(indx + v2 - 1) >> 1] + Dgrbsq1p[(indx + v2 + 1) >> 1])))
1065 + rbvarm);
1066
1067 // bound the interpolation in regions of high saturation
1068
1069 if(rbp[indx1] < cfa[indx])
1070 {
1071 if(xmul2f(rbp[indx1]) < cfa[indx])
1072 {
1073 rbp[indx1] = ULIM(rbp[indx1], cfa[indx - p1], cfa[indx + p1]);
1074 }
1075 else
1076 {
1077 float pwt = xmul2f(cfa[indx] - rbp[indx1]) / (eps + rbp[indx1] + cfa[indx]);
1078 rbp[indx1]
1079 = pwt * rbp[indx1] + (1.f - pwt) * ULIM(rbp[indx1], cfa[indx - p1], cfa[indx + p1]);
1080 }
1081 }
1082
1083 if(rbm[indx1] < cfa[indx])
1084 {
1085 if(xmul2f(rbm[indx1]) < cfa[indx])
1086 {
1087 rbm[indx1] = ULIM(rbm[indx1], cfa[indx - m1], cfa[indx + m1]);
1088 }
1089 else
1090 {
1091 float mwt = xmul2f(cfa[indx] - rbm[indx1]) / (eps + rbm[indx1] + cfa[indx]);
1092 rbm[indx1]
1093 = mwt * rbm[indx1] + (1.f - mwt) * ULIM(rbm[indx1], cfa[indx - m1], cfa[indx + m1]);
1094 }
1095 }
1096
1097 if(rbp[indx1] > clip_pt)
1098 {
1099 rbp[indx1] = ULIM(rbp[indx1], cfa[indx - p1], cfa[indx + p1]);
1100 }
1101
1102 if(rbm[indx1] > clip_pt)
1103 {
1104 rbm[indx1] = ULIM(rbm[indx1], cfa[indx - m1], cfa[indx + m1]);
1105 }
1106 }
1107 }
1108
1109 for(int rr = 10; rr < rr1 - 10; rr++)
1110 for(int cc = 10 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc, indx1 = indx >> 1; cc < cc1 - 10;
1111 cc += 2, indx += 2, indx1++)
1112 {
1113
1114 // first ask if one gets more directional discrimination from nearby B/R sites
1115 float pmwtalt = xdivf(pmwt[(indx - m1) >> 1] + pmwt[(indx + p1) >> 1] + pmwt[(indx - p1) >> 1]
1116 + pmwt[(indx + m1) >> 1],
1117 2);
1118
1119 if(fabsf(0.5f - pmwt[indx1]) < fabsf(0.5f - pmwtalt))
1120 {
1121 pmwt[indx1] = pmwtalt; // a better result was obtained from the neighbours
1122 }
1123
1124 rbint[indx1] = xdiv2f(cfa[indx] + rbm[indx1] * (1.f - pmwt[indx1])
1125 + rbp[indx1] * pmwt[indx1]); // this is R+B, interpolated
1126 }
1127
1128
1129 for(int rr = 12; rr < rr1 - 12; rr++)
1130 for(int cc = 12 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc, indx1 = indx >> 1; cc < cc1 - 12;
1131 cc += 2, indx += 2, indx1++)
1132 {
1133
1134 if(fabsf(0.5f - pmwt[indx >> 1]) < fabsf(0.5f - hvwt[indx >> 1]))
1135 {
1136 continue;
1137 }
1138
1139 // now interpolate G vertically/horizontally using R+B values
1140 // unfortunately, since G interpolation cannot be done diagonally this may lead to colour shifts
1141
1142 // colour ratios for G interpolation
1143 float cru = cfa[indx - v1] * 2.0 / (eps + rbint[indx1] + rbint[(indx1 - v1)]);
1144 float crd = cfa[indx + v1] * 2.0 / (eps + rbint[indx1] + rbint[(indx1 + v1)]);
1145 float crl = cfa[indx - 1] * 2.0 / (eps + rbint[indx1] + rbint[(indx1 - 1)]);
1146 float crr = cfa[indx + 1] * 2.0 / (eps + rbint[indx1] + rbint[(indx1 + 1)]);
1147
1148 // interpolation of G in four directions
1149 float gu, gd, gl, gr;
1150
1151 // interpolated G via adaptive ratios or Hamilton-Adams in each cardinal direction
1152 if(fabsf(1.f - cru) < arthresh)
1153 {
1154 gu = rbint[indx1] * cru;
1155 }
1156 else
1157 {
1158 gu = cfa[indx - v1] + xdiv2f(rbint[indx1] - rbint[(indx1 - v1)]);
1159 }
1160
1161 if(fabsf(1.f - crd) < arthresh)
1162 {
1163 gd = rbint[indx1] * crd;
1164 }
1165 else
1166 {
1167 gd = cfa[indx + v1] + xdiv2f(rbint[indx1] - rbint[(indx1 + v1)]);
1168 }
1169
1170 if(fabsf(1.f - crl) < arthresh)
1171 {
1172 gl = rbint[indx1] * crl;
1173 }
1174 else
1175 {
1176 gl = cfa[indx - 1] + xdiv2f(rbint[indx1] - rbint[(indx1 - 1)]);
1177 }
1178
1179 if(fabsf(1.f - crr) < arthresh)
1180 {
1181 gr = rbint[indx1] * crr;
1182 }
1183 else
1184 {
1185 gr = cfa[indx + 1] + xdiv2f(rbint[indx1] - rbint[(indx1 + 1)]);
1186 }
1187
1188 // interpolated G via adaptive weights of cardinal evaluations
1189 float Gintv = (dirwts0[indx - v1] * gd + dirwts0[indx + v1] * gu)
1190 / (dirwts0[indx + v1] + dirwts0[indx - v1]);
1191 float Ginth
1192 = (dirwts1[indx - 1] * gr + dirwts1[indx + 1] * gl) / (dirwts1[indx - 1] + dirwts1[indx + 1]);
1193
1194 // bound the interpolation in regions of high saturation
1195 if(Gintv < rbint[indx1])
1196 {
1197 if(2 * Gintv < rbint[indx1])
1198 {
1199 Gintv = ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]);
1200 }
1201 else
1202 {
1203 float vwt = 2.0 * (rbint[indx1] - Gintv) / (eps + Gintv + rbint[indx1]);
1204 Gintv = vwt * Gintv + (1.f - vwt) * ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]);
1205 }
1206 }
1207
1208 if(Ginth < rbint[indx1])
1209 {
1210 if(2 * Ginth < rbint[indx1])
1211 {
1212 Ginth = ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]);
1213 }
1214 else
1215 {
1216 float hwt = 2.0 * (rbint[indx1] - Ginth) / (eps + Ginth + rbint[indx1]);
1217 Ginth = hwt * Ginth + (1.f - hwt) * ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]);
1218 }
1219 }
1220
1221 if(Ginth > clip_pt)
1222 {
1223 Ginth = ULIM(Ginth, cfa[indx - 1], cfa[indx + 1]);
1224 }
1225
1226 if(Gintv > clip_pt)
1227 {
1228 Gintv = ULIM(Gintv, cfa[indx - v1], cfa[indx + v1]);
1229 }
1230
1231 rgbgreen[indx] = Ginth * (1.f - hvwt[indx1]) + Gintv * hvwt[indx1];
1232 Dgrb[0][indx >> 1] = rgbgreen[indx] - cfa[indx];
1233 }
1234
1235 // end of diagonal interpolation correction
1236
1237 // fancy chrominance interpolation
1238 //(ey,ex) is location of R site
1239 for(int rr = 13 - ey; rr < rr1 - 12; rr += 2)
1240 for(int indx1 = (rr * ts + 13 - ex) >> 1; indx1<(rr * ts + cc1 - 12)>> 1; indx1++)
1241 { // B coset
1242 Dgrb[1][indx1] = Dgrb[0][indx1]; // split out G-B from G-R
1243 Dgrb[0][indx1] = 0;
1244 }
1245
1246 for(int rr = 14; rr < rr1 - 14; rr++)
1247 for(int cc = 14 + (FC(rr, 2, filters) & 1), indx = rr * ts + cc, c = 1 - FC(rr, cc, filters) / 2;
1248 cc < cc1 - 14; cc += 2, indx += 2)
1249 {
1250 float wtnw = 1.f / (eps + fabsf(Dgrb[c][(indx - m1) >> 1] - Dgrb[c][(indx + m1) >> 1])
1251 + fabsf(Dgrb[c][(indx - m1) >> 1] - Dgrb[c][(indx - m3) >> 1])
1252 + fabsf(Dgrb[c][(indx + m1) >> 1] - Dgrb[c][(indx - m3) >> 1]));
1253 float wtne = 1.f / (eps + fabsf(Dgrb[c][(indx + p1) >> 1] - Dgrb[c][(indx - p1) >> 1])
1254 + fabsf(Dgrb[c][(indx + p1) >> 1] - Dgrb[c][(indx + p3) >> 1])
1255 + fabsf(Dgrb[c][(indx - p1) >> 1] - Dgrb[c][(indx + p3) >> 1]));
1256 float wtsw = 1.f / (eps + fabsf(Dgrb[c][(indx - p1) >> 1] - Dgrb[c][(indx + p1) >> 1])
1257 + fabsf(Dgrb[c][(indx - p1) >> 1] - Dgrb[c][(indx + m3) >> 1])
1258 + fabsf(Dgrb[c][(indx + p1) >> 1] - Dgrb[c][(indx - p3) >> 1]));
1259 float wtse = 1.f / (eps + fabsf(Dgrb[c][(indx + m1) >> 1] - Dgrb[c][(indx - m1) >> 1])
1260 + fabsf(Dgrb[c][(indx + m1) >> 1] - Dgrb[c][(indx - p3) >> 1])
1261 + fabsf(Dgrb[c][(indx - m1) >> 1] - Dgrb[c][(indx + m3) >> 1]));
1262
1263 Dgrb[c][indx >> 1]
1264 = (wtnw * (1.325f * Dgrb[c][(indx - m1) >> 1] - 0.175f * Dgrb[c][(indx - m3) >> 1]
1265 - 0.075f * Dgrb[c][(indx - m1 - 2) >> 1] - 0.075f * Dgrb[c][(indx - m1 - v2) >> 1])
1266 + wtne * (1.325f * Dgrb[c][(indx + p1) >> 1] - 0.175f * Dgrb[c][(indx + p3) >> 1]
1267 - 0.075f * Dgrb[c][(indx + p1 + 2) >> 1]
1268 - 0.075f * Dgrb[c][(indx + p1 + v2) >> 1])
1269 + wtsw * (1.325f * Dgrb[c][(indx - p1) >> 1] - 0.175f * Dgrb[c][(indx - p3) >> 1]
1270 - 0.075f * Dgrb[c][(indx - p1 - 2) >> 1]
1271 - 0.075f * Dgrb[c][(indx - p1 - v2) >> 1])
1272 + wtse * (1.325f * Dgrb[c][(indx + m1) >> 1] - 0.175f * Dgrb[c][(indx + m3) >> 1]
1273 - 0.075f * Dgrb[c][(indx + m1 + 2) >> 1]
1274 - 0.075f * Dgrb[c][(indx + m1 + v2) >> 1]))
1275 / (wtnw + wtne + wtsw + wtse);
1276 }
1277
1278 for(int rr = 16; rr < rr1 - 16; rr++)
1279 {
1280 int row = rr + top;
1281 int col = left + 16;
1282 int indx = rr * ts + 16;
1283
1284 if((FC(rr, 2, filters) & 1) == 1)
1285 {
1286 for(; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++)
1287 {
1288 if(col < roi_out->width && row < roi_out->height)
1289 {
1290 float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1]
1291 - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
1292 out[(row * roi_out->width + col) * 4]
1293 = clampnan(rgbgreen[indx]
1294 - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1]
1295 + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1]
1296 + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1]
1297 + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1])
1298 * temp,
1299 0.0, 1.0);
1300 out[(row * roi_out->width + col) * 4 + 2]
1301 = clampnan(rgbgreen[indx]
1302 - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1]
1303 + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1]
1304 + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1]
1305 + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1])
1306 * temp,
1307 0.0, 1.0);
1308 }
1309
1310 indx++;
1311 col++;
1312 if(col < roi_out->width && row < roi_out->height)
1313 {
1314 out[(row * roi_out->width + col) * 4]
1315 = clampnan(rgbgreen[indx] - Dgrb[0][indx >> 1], 0.0, 1.0);
1316 out[(row * roi_out->width + col) * 4 + 2]
1317 = clampnan(rgbgreen[indx] - Dgrb[1][indx >> 1], 0.0, 1.0);
1318 }
1319 }
1320
1321 if(cc1 & 1)
1322 { // width of tile is odd
1323 if(col < roi_out->width && row < roi_out->height)
1324 {
1325 float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1]
1326 - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
1327 out[(row * roi_out->width + col) * 4]
1328 = clampnan(rgbgreen[indx]
1329 - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1]
1330 + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1]
1331 + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1]
1332 + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1])
1333 * temp,
1334 0.0, 1.0);
1335 out[(row * roi_out->width + col) * 4 + 2]
1336 = clampnan(rgbgreen[indx]
1337 - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1]
1338 + (1.f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1]
1339 + (1.f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1]
1340 + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1])
1341 * temp,
1342 0.0, 1.0);
1343 }
1344 }
1345 }
1346 else
1347 {
1348 for(; indx < rr * ts + cc1 - 16 - (cc1 & 1); indx++, col++)
1349 {
1350 if(col < roi_out->width && row < roi_out->height)
1351 {
1352 out[(row * roi_out->width + col) * 4]
1353 = clampnan(rgbgreen[indx] - Dgrb[0][indx >> 1], 0.0f, 1.0f);
1354 out[(row * roi_out->width + col) * 4 + 2]
1355 = clampnan(rgbgreen[indx] - Dgrb[1][indx >> 1], 0.0f, 1.0f);
1356 }
1357
1358 indx++;
1359 col++;
1360 if(col < roi_out->width && row < roi_out->height)
1361 {
1362 float temp = 1.f / (hvwt[(indx - v1) >> 1] + 2.f - hvwt[(indx + 1) >> 1]
1363 - hvwt[(indx - 1) >> 1] + hvwt[(indx + v1) >> 1]);
1364
1365 out[(row * roi_out->width + col) * 4]
1366 = clampnan(rgbgreen[indx]
1367 - ((hvwt[(indx - v1) >> 1]) * Dgrb[0][(indx - v1) >> 1]
1368 + (1.0f - hvwt[(indx + 1) >> 1]) * Dgrb[0][(indx + 1) >> 1]
1369 + (1.0f - hvwt[(indx - 1) >> 1]) * Dgrb[0][(indx - 1) >> 1]
1370 + (hvwt[(indx + v1) >> 1]) * Dgrb[0][(indx + v1) >> 1])
1371 * temp,
1372 0.0f, 1.0f);
1373
1374 out[(row * roi_out->width + col) * 4 + 2]
1375 = clampnan(rgbgreen[indx]
1376 - ((hvwt[(indx - v1) >> 1]) * Dgrb[1][(indx - v1) >> 1]
1377 + (1.0f - hvwt[(indx + 1) >> 1]) * Dgrb[1][(indx + 1) >> 1]
1378 + (1.0f - hvwt[(indx - 1) >> 1]) * Dgrb[1][(indx - 1) >> 1]
1379 + (hvwt[(indx + v1) >> 1]) * Dgrb[1][(indx + v1) >> 1])
1380 * temp,
1381 0.0f, 1.0f);
1382 }
1383 }
1384
1385 if(cc1 & 1)
1386 { // width of tile is odd
1387 if(col < roi_out->width && row < roi_out->height)
1388 {
1389 out[(row * roi_out->width + col) * 4]
1390 = clampnan(rgbgreen[indx] - Dgrb[0][indx >> 1], 0.0f, 1.0f);
1391 out[(row * roi_out->width + col) * 4 + 2]
1392 = clampnan(rgbgreen[indx] - Dgrb[1][indx >> 1], 0.0f, 1.0f);
1393 }
1394 }
1395 }
1396 }
1397
1398 // copy smoothed results back to image matrix
1399 for(int rr = 16; rr < rr1 - 16; rr++)
1400 {
1401 int row = rr + top;
1402 int cc = 16;
1403 for(; cc < cc1 - 16; cc++)
1404 {
1405 int col = cc + left;
1406 int indx = rr * ts + cc;
1407 if(col < roi_out->width && row < roi_out->height)
1408 out[(row * roi_out->width + col) * 4 + 1] = clampnan(rgbgreen[indx], 0.0f, 1.0f);
1409 }
1410 }
1411 }
1412 } // end of main loop
1413
1414 // clean up
1415 dt_free(buffer);
1416 }
1417}
1418
1419/*==================================================================================
1420 * end of raw therapee code
1421 *==================================================================================*/
1422
1423// clang-format off
1424// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1425// vim: shiftwidth=2 expandtab tabstop=2 cindent
1426// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1427// clang-format on
static __inline float xmul2f(float d)
Definition amaze.cc:77
void amaze_demosaic_RT(const dt_dev_pixelpipe_iop_t *piece, const float *const in, float *out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int filters)
Definition amaze.cc:181
static const _Tp intp(const _Tp a, const _Tp b, const _Tp c)
Definition amaze.cc:130
static __inline float clampnan(const float x, const float m, const float M)
Definition amaze.cc:61
static const _Tp LIM(const _Tp a, const _Tp b, const _Tp c)
Definition amaze.cc:139
static __inline float xdiv2f(float d)
Definition amaze.cc:91
static const _Tp ULIM(const _Tp a, const _Tp b, const _Tp c)
Definition amaze.cc:144
static __inline float xdivf(float d, int n)
Definition amaze.cc:105
#define AMAZETS
#define SQR(a)
Definition ashift.c:132
#define m
Definition basecurve.c:283
static const float x
const float f
const float v
const dt_colormatrix_t dt_aligned_pixel_t out
const float top
static const int row
static const dt_colormatrix_t M
static int FC(const int row, const int col, const unsigned int filters)
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define __OMP_FOR_SIMD__(...)
Definition openmp.h:97
#define eps
Definition rcd.c:81
#define epssq
Definition rcd.c:82
const float r
dt_iop_buffer_dsc_t dsc_in
dt_aligned_pixel_t processed_maximum
Definition format.h:114
Region of interest passed through the pixelpipe.
Definition format.h:49
int width
Definition format.h:50
int height
Definition format.h:50
#define __DT_CLONE_TARGETS__
#define MIN(a, b)
Definition thinplate.c:32