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