Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gather.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Bruce Guenter.
4 Copyright (C) 2010-2011 Henrik Andersson.
5 Copyright (C) 2010-2014, 2016 johannes hanika.
6 Copyright (C) 2010 Stuart Henderson.
7 Copyright (C) 2011 Antony Dovgal.
8 Copyright (C) 2011 Robert Bieber.
9 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
10 Copyright (C) 2011-2012, 2014, 2016-2017 Ulrich Pegelow.
11 Copyright (C) 2012, 2015 Edouard Gomez.
12 Copyright (C) 2012 Jérémy Rosen.
13 Copyright (C) 2012 Richard Wonka.
14 Copyright (C) 2013, 2020 Aldric Renaudin.
15 Copyright (C) 2014, 2016 Dan Torop.
16 Copyright (C) 2014-2016 Roman Lebedev.
17 Copyright (C) 2015-2016 Pedro Côrte-Real.
18 Copyright (C) 2017 Heiko Bauke.
19 Copyright (C) 2017 luzpaz.
20 Copyright (C) 2018, 2020-2026 Aurélien PIERRE.
21 Copyright (C) 2018 Edgardo Hoszowski.
22 Copyright (C) 2018 Maurizio Paglia.
23 Copyright (C) 2018-2020, 2022 Pascal Obry.
24 Copyright (C) 2018 rawfiner.
25 Copyright (C) 2019 Andreas Schneider.
26 Copyright (C) 2019 Diederik ter Rahe.
27 Copyright (C) 2019-2020, 2022 Hanno Schwalm.
28 Copyright (C) 2020 Chris Elston.
29 Copyright (C) 2020, 2022 Diederik Ter Rahe.
30 Copyright (C) 2020-2021 Ralf Brown.
31 Copyright (C) 2021 Hubert Kowalski.
32 Copyright (C) 2022 Martin Bařinka.
33 Copyright (C) 2022 Philipp Lutz.
34 Copyright (C) 2022 Victor Forsiuk.
35 Copyright (C) 2023 Alynx Zhou.
36 Copyright (C) 2023 Guillaume Stutin.
37 Copyright (C) 2023 Luca Zulberti.
38
39 darktable is free software: you can redistribute it and/or modify
40 it under the terms of the GNU General Public License as published by
41 the Free Software Foundation, either version 3 of the License, or
42 (at your option) any later version.
43
44 darktable is distributed in the hope that it will be useful,
45 but WITHOUT ANY WARRANTY; without even the implied warranty of
46 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 GNU General Public License for more details.
48
49 You should have received a copy of the GNU General Public License
50 along with darktable. If not, see <http://www.gnu.org/licenses/>.
51 */
52
53// Shared CFA gather/remosaic helpers for the highlights module: bilinear interpolation of the
54// raw mosaic into [R,G,B,norm] planes + clip masks, the guided-laplacian normalization channel,
55// and the remosaic back to the CFA. Used by both the guided-laplacian mode (highlights.c) and the
56// harmonic-transposition driver (process.c). (implementation; see gather.h for the public API.)
57
58#include "common/darktable.h"
59#include "develop/imageop.h"
62#include <math.h>
63#include <string.h>
64
66void _interpolate_and_mask(const float *const restrict input, float *const restrict interpolated,
67 float *const restrict clipping_mask, const dt_aligned_pixel_t clips_in,
68 const dt_aligned_pixel_t det_scale, const dt_aligned_pixel_t white_balance,
69 const uint32_t filters, const size_t width, const size_t height)
70{
71 // Per-channel effective detection thresholds. det_scale = 1 is the plain clip detection;
72 // below 1 it extends the reconstructable set down into the sensor's rolloff band
73 // (the BAND OVERRIDE: the knee can restore the band's level but not the slope the sensor
74 // never recorded, while the colour-line model, anchored on truly linear data below the
75 // band, can -- the measured band value then acts as the per-pixel floor).
77 for_four_channels(c) clips[c] = clips_in[c] * det_scale[c];
78
79 // Step 1 (article "The algorithm"): bilinear demosaic of the raw CFA to a throwaway [R,G,B,norm]
80 // buffer, plus a binary per-channel validity mask keyed on the clip flag v > 0.995*c (here
81 // clips[] already folds in the 0.995 detection factor and the det_scale band override above).
82 // Every channel gets a value at every pixel so the downstream guided fit is a regression, not
83 // an inpainting, problem. Refinements: masks stay binary (0/1), borders mirror (see below).
84 // Bilinear interpolation
85 __OMP_PARALLEL_FOR__(collapse(2))
86 for(size_t i = 0; i < height; i++)
87 for(size_t j = 0; j < width; j++)
88 {
89 const size_t c = FC(i, j, filters);
90 const size_t i_center = i * width;
91 const float center = input[i_center + j];
92
93 float R = 0.f;
94 float G = 0.f;
95 float B = 0.f;
96
97 int R_clipped = 0;
98 int G_clipped = 0;
99 int B_clipped = 0;
100
101 {
102 // Mirrored neighbour indexing on the image border ring: reflection preserves each
103 // neighbour's CFA colour (the Bayer pattern is 2-periodic), so the per-channel
104 // interpolation and clip flags below stay valid on the borders. The previous shortcut
105 // (R = G = B = center, all three clip flags keyed on the centre's own channel)
106 // corrupted the guide planes and produced dashed per-channel masks along the border
107 // ring : fits anchored on them dragged the border-row reconstruction down to the clip
108 // level (a one-pixel V-dip through the raw value at every contour on the border rows).
109 const size_t i_prev = ((i == 0) ? 1 : i - 1) * width;
110 const size_t i_next = ((i == height - 1) ? height - 2 : i + 1) * width;
111 const size_t j_prev = (j == 0) ? 1 : j - 1;
112 const size_t j_next = (j == width - 1) ? width - 2 : j + 1;
113
114 const float north = input[i_prev + j];
115 const float south = input[i_next + j];
116 const float west = input[i_center + j_prev];
117 const float east = input[i_center + j_next];
118
119 const float north_east = input[i_prev + j_next];
120 const float north_west = input[i_prev + j_prev];
121 const float south_east = input[i_next + j_next];
122 const float south_west = input[i_next + j_prev];
123
124 if(c == GREEN) // green pixel
125 {
126 G = center; // channel measured here: pass the raw value through
127 G_clipped = (center > clips[GREEN]); // clip flag: raw > 0.995*c
128 }
129 else // non-green pixel
130 {
131 // interpolate inside an X/Y cross: green sits on the 4 orthogonal neighbours (Bayer),
132 // so G = mean of {N,S,E,W} = equal 1/4 bilinear weights over the valid green support.
133 G = (north + south + east + west) / 4.f;
134 // validity is the OR of the neighbours' clip flags (a channel counts as clipped if ANY
135 // photosite that fed its interpolation was itself clipped).
136 G_clipped = (north > clips[GREEN] || south > clips[GREEN] || east > clips[GREEN] || west > clips[GREEN]);
137 }
138
139 if(c == RED) // red pixel
140 {
141 R = center;
142 R_clipped = (center > clips[RED]);
143 }
144 else // non-red pixel
145 {
146 if(FC(i + 1, j, filters) == RED)
147 {
148 // red neighbours are directly above/below: R = mean of {N,S}, equal 1/2 weights
149 // we are on a red column (FC(i-1) == FC(i+1) on Bayer), interpolate column-wise
150 R = (north + south) / 2.f;
151 R_clipped = (north > clips[RED] || south > clips[RED]); // OR of the 2 contributors
152 }
153 else if(FC(i, j + 1, filters) == RED)
154 {
155 // red neighbours are left/right: R = mean of {W,E}, equal 1/2 weights
156 // we are on a red row, interpolate row-wise
157 R = (west + east) / 2.f;
158 R_clipped = (west > clips[RED] || east > clips[RED]); // OR of the 2 contributors
159 }
160 else
161 {
162 // red neighbours are the 4 diagonal corners: R = mean of the square, equal 1/4 weights
163 // we are on a blue row, so interpolate inside a square
164 R = (north_west + north_east + south_east + south_west) / 4.f;
165 R_clipped = (north_west > clips[RED] || north_east > clips[RED] || south_west > clips[RED]
166 || south_east > clips[RED]); // OR of the 4 contributors
167 }
168 }
169
170 if(c == BLUE) // blue pixel
171 {
172 B = center;
173 B_clipped = (center > clips[BLUE]);
174 }
175 else // non-blue pixel
176 {
177 if(FC(i + 1, j, filters) == BLUE)
178 {
179 // blue neighbours are directly above/below: B = mean of {N,S}, equal 1/2 weights
180 // we are on a blue column (FC(i-1) == FC(i+1) on Bayer), interpolate column-wise
181 B = (north + south) / 2.f;
182 B_clipped = (north > clips[BLUE] || south > clips[BLUE]); // OR of the 2 contributors
183 }
184 else if(FC(i, j + 1, filters) == BLUE)
185 {
186 // blue neighbours are left/right: B = mean of {W,E}, equal 1/2 weights
187 // we are on a blue row, interpolate row-wise
188 B = (west + east) / 2.f;
189 B_clipped = (west > clips[BLUE] || east > clips[BLUE]); // OR of the 2 contributors
190 }
191 else
192 {
193 // blue neighbours are the 4 diagonal corners: B = mean of the square, equal 1/4 weights
194 // we are on a red row, so interpolate inside a square
195 B = (north_west + north_east + south_east + south_west) / 4.f;
196
197 B_clipped = (north_west > clips[BLUE] || north_east > clips[BLUE] || south_west > clips[BLUE]
198 || south_east > clips[BLUE]); // OR of the 4 contributors
199 }
200 }
201 }
202
203 // ALPHA slot carries the magnitude norm = sqrt(R^2 + G^2 + B^2) (Euclidean, as coded);
204 // the any-clip opacity is the OR of the three per-channel validity flags.
205 dt_aligned_pixel_t RGB = { R, G, B, sqrtf(sqf(R) + sqf(G) + sqf(B)) };
206 dt_aligned_pixel_t clipped = { R_clipped, G_clipped, B_clipped, (R_clipped || G_clipped || B_clipped) };
207
208 for_each_channel(k, aligned(RGB, interpolated, clipping_mask, clipped, white_balance))
209 {
210 const size_t idx = (i * width + j) * 4 + k;
211 // Local channel normalization (article "Local channel normalization"): divide each channel
212 // by white_balance[k] = the tile-average of that CFA colour (from _compute_laplacian_
213 // normalization), a crude local white balance so the guide-selection variance is not biased
214 // toward whichever channel carries the largest raw numbers. Clamp >= 0 (raw can dip negative).
215 interpolated[idx] = fmaxf(RGB[k] / white_balance[k], 0.f);
216 clipping_mask[idx] = clipped[k]; // store the binary flag; no feathering here (masks stay hard)
217 }
218 }
219}
220
222void _compute_laplacian_normalization(const float *const restrict input, const dt_iop_roi_t *const roi_in,
223 const uint32_t filters, const uint8_t (*const xtrans)[6],
224 dt_aligned_pixel_t normalization)
225{
226 // Local channel normalization (article "Local channel normalization"): for each CFA colour,
227 // compute its plain average over the whole ROI, sum_c = (1/N) * sum over photosites of colour c.
228 // Note the division by n_pixels here uses the FULL pixel count N (not the per-colour count), so
229 // these factors also carry the CFA fill fraction of each colour -- they are the exact divisors
230 // that _interpolate_and_mask/_remosaic later divide by / multiply back.
231 float sum_R = 0.f;
232 float sum_G = 0.f;
233 float sum_B = 0.f;
234 const float n_pixels = roi_in->height * roi_in->width;
235 __OMP_PARALLEL_FOR__(collapse(2) reduction(+ : sum_R, sum_G, sum_B))
236 for(size_t i = 0; i < roi_in->height; i++)
237 for(size_t j = 0; j < roi_in->width; j++)
238 {
239 const int c = (filters == 9u) ? FCxtrans((int)i, (int)j, roi_in, xtrans) : FC(i, j, filters);
240 if(c < 0 || c > 2) continue;
241
242 const float value = input[i * roi_in->width + j] / n_pixels; // accumulate value/N into its colour
243 if(c == RED)
244 sum_R += value;
245 else if(c == GREEN)
246 sum_G += value;
247 else
248 sum_B += value;
249 }
250
251 normalization[RED] = sum_R;
252 normalization[GREEN] = sum_G;
253 normalization[BLUE] = sum_B;
254 normalization[ALPHA] = 1.f; // norm/opacity slot is untouched by the local white balance
255}
256
258void _build_xtrans_bilinear_lookup(int32_t lookup[6][6][32], const dt_iop_roi_t *const roi_in,
259 const uint8_t (*const xtrans)[6])
260{
261 __OMP_PARALLEL_FOR__(collapse(2))
262 for(int row = 0; row < 6; row++)
263 for(int col = 0; col < 6; col++)
264 {
265 int32_t *ip = &(lookup[row][col][1]);
266 int sum[3] = { 0 };
267 const int f = FCxtrans(row, col, roi_in, xtrans);
268
269 // Loop over the local 3x3 support and keep every weighted contributor of
270 // the missing colors visible in the lookup table.
271 for(int y = -1; y <= 1; y++)
272 for(int x = -1; x <= 1; x++)
273 {
274 // Separable bilinear tent weight: 1<<((y==0)+(x==0)) gives 4 on-axis-both (the centre,
275 // excluded below), 2 for an edge neighbour (one axis aligned), 1 for a diagonal corner --
276 // i.e. the {1,2,1}x{1,2,1} kernel of the same bilinear demosaic used on Bayer above.
277 const int weight = 1 << ((y == 0) + (x == 0));
278 const int color = FCxtrans(row + y, col + x, roi_in, xtrans);
279 if(color == f) continue; // skip the centre's own colour: it is passed through as measured
280 *ip++ = (y << 16) | (x & 0xffffu);
281 *ip++ = weight;
282 *ip++ = color;
283 sum[color] += weight;
284 }
285
286 lookup[row][col][0] = (ip - &(lookup[row][col][0])) / 3;
287 for(int c = 0; c < 3; c++)
288 if(c != f)
289 {
290 *ip++ = c;
291 *ip++ = sum[c];
292 }
293 *ip = f;
294 }
295}
296
298void _interpolate_and_mask_xtrans(const float *const restrict input, float *const restrict interpolated,
299 float *const restrict clipping_mask, const dt_aligned_pixel_t clips,
300 const dt_aligned_pixel_t white_balance, const dt_iop_roi_t *const roi_in,
301 const int32_t lookup[6][6][32], const uint8_t (*const xtrans)[6],
302 const size_t width, const size_t height)
303{
304 // Step 1 (article "The algorithm"), X-Trans twin of _interpolate_and_mask: bilinear demosaic to
305 // [R,G,B,norm] + a binary per-channel validity mask keyed on v > 0.995*c. The 6x6 X-Trans phase
306 // is 3x3-periodic in support geometry, resolved via the precomputed lookup for interior pixels.
307 __OMP_PARALLEL_FOR__(collapse(2))
308 for(size_t i = 0; i < height; i++)
309 for(size_t j = 0; j < width; j++)
310 {
311 const size_t idx = i * width + j;
312 const float center = input[idx];
313
314 dt_aligned_pixel_t RGB = { 0.f };
315 dt_aligned_pixel_t clipped = { 0.f };
316
317 if(i == 0 || j == 0 || i == height - 1 || j == width - 1)
318 {
319 dt_aligned_pixel_t sum = { 0.f };
320 int count[3] = { 0 };
321 int used_clipped[3] = { 0 };
322 const int f = FCxtrans((int)i, (int)j, roi_in, xtrans);
323
324 // Along tile borders we average only the available neighbours because
325 // the full 3x3 support would otherwise leave the current ROI.
326 for(int y = MAX((int)i - 1, 0); y <= MIN((int)i + 1, (int)height - 1); y++)
327 for(int x = MAX((int)j - 1, 0); x <= MIN((int)j + 1, (int)width - 1); x++)
328 {
329 const int color = FCxtrans(y, x, roi_in, xtrans);
330 const float value = input[(size_t)y * width + x];
331 sum[color] += value;
332 count[color]++;
333 used_clipped[color] |= (value > clips[color]);
334 }
335
336 for(int c = 0; c < 3; c++)
337 {
338 const int has_samples = (count[c] > 0);
339 // c==f: the measured centre colour passes through. Otherwise plain average over the
340 // available same-colour neighbours (equal weights on the shrunken border support), with
341 // the clip flag = OR of those neighbours' flags (or the centre's own for c==f).
342 RGB[c] = (c == f || !has_samples) ? center : sum[c] / count[c];
343 clipped[c] = (c == f || !has_samples) ? (center > clips[c]) : used_clipped[c];
344 }
345 }
346 else
347 {
348 const int32_t *ip = &(lookup[i % 6][j % 6][0]);
349 dt_aligned_pixel_t sum = { 0.f };
350 int used_clipped[3] = { 0 };
351 const int neighbours = *ip++;
352
353 // We are looping on every neighbour that contributes to a missing color
354 // so the interpolation follows the X-Trans CFA geometry exactly.
355 for(int k = 0; k < neighbours; k++, ip += 3)
356 {
357 const int32_t offset = ip[0];
358 const int x = (int16_t)(offset & 0xffffu);
359 const int y = (int16_t)(offset >> 16);
360 const size_t neighbour = ((size_t)((int)i + y) * width + (size_t)((int)j + x));
361 const int color = ip[2];
362 const float value = input[neighbour];
363 sum[color] += value * ip[1];
364 used_clipped[color] |= (value > clips[color]);
365 }
366
367 // Normalize the two missing colors from the accumulated weights, then
368 // restore the measured center color unchanged.
369 // RGB[color] = (sum of weight*value) / (sum of weights) = weighted bilinear mean.
370 for(int k = 0; k < 2; k++, ip += 2)
371 {
372 const int color = ip[0];
373 const int total = ip[1];
374 RGB[color] = (total > 0) ? sum[color] / total : center; // weighted mean, else fall back
375 clipped[color] = used_clipped[color]; // OR of the contributors' flags
376 }
377
378 const int f = *ip;
379 RGB[f] = center; // centre colour: measured raw value passes through
380 clipped[f] = (center > clips[f]); // clip flag: raw > 0.995*c
381 }
382
383 // ALPHA slot = Euclidean magnitude norm sqrt(R^2+G^2+B^2); opacity = OR of the per-channel flags.
384 // NOTE (article cross-reference): this is the interpolated buffer's shared "norm" channel, and it
385 // is NOT the harmonic method's magnitude L_sum. The 2021 guided-laplacian mode consumes it (its
386 // a-trous ratio/norm split, see wavelets_process LAST_SCALE); the harmonic path only carries it and
387 // never reads it as a magnitude -- forcing it to R+G+B leaves all six ground-truth scenes
388 // bit-identical (verified). The article's L_sum = R+G+B is computed separately in the all-clip core
389 // (lum_accum in _region_guided_filter / the hl_lsb_hole kernel), which already matches the article.
390 RGB[ALPHA] = sqrtf(sqf(RGB[RED]) + sqf(RGB[GREEN]) + sqf(RGB[BLUE]));
391 clipped[ALPHA] = (clipped[RED] || clipped[GREEN] || clipped[BLUE]);
392
393 for_each_channel(k, aligned(RGB, interpolated, clipping_mask, clipped, white_balance))
394 {
395 const size_t index = idx * 4 + k;
396 // Local channel normalization: divide by white_balance[k] = tile-average of that colour;
397 // clamp >= 0. Same crude local white balance as the Bayer path above.
398 interpolated[index] = fmaxf(RGB[k] / white_balance[k], 0.f);
399 clipping_mask[index] = clipped[k]; // binary flag, no feathering (masks stay hard)
400 }
401 }
402}
403
405void _remosaic_and_replace(const float *const restrict input, const float *const restrict input_raw,
406 const float *const restrict interpolated, const float *const restrict clipping_mask,
407 float *const restrict output, const dt_aligned_pixel_t white_balance,
408 const dt_aligned_pixel_t clips, const int clip_is_floor, const uint32_t filters,
409 const size_t width, const size_t height)
410{
411 // Remosaic + composite (article "The algorithm", step "remosaic + composite").
412 // Compositing rule: out = opacity*rec + (1 - opacity)*base.
413 // Refinement 2 (clipped raw is a FLOOR): with clip_is_floor set, for a clipped photosite
414 // base = max(raw, rec) instead of raw -- under sensor rolloff the raw reading of a just-detected
415 // photosite sits at the detection threshold, below the true signal, so it is a lower bound, not a
416 // measurement. Feathering the reconstruction toward it printed a V-shaped dip at every contour
417 // down to the biased reading. The 2021 mode keeps the historical blend (flag 0).
418 __OMP_PARALLEL_FOR__(collapse(2))
419 for(size_t i = 0; i < height; i++)
420 for(size_t j = 0; j < width; j++)
421 {
422 const size_t c = FC(i, j, filters);
423 const size_t idx = i * width + j;
424 const size_t index = idx * 4;
425 const float opacity = clipping_mask[index + ALPHA]; // any-clip mask -> blend weight (0 or 1)
426 // Undo the local channel normalization: multiply the reconstructed channel back by its
427 // tile-average white_balance[c] to return to raw scale, clamp >= 0.
428 const float reconstructed = fmaxf(interpolated[index + c] * white_balance[c], 0.f);
429 float base = input[idx];
430 if(clip_is_floor && input_raw[idx] >= clips[c]) base = fmaxf(base, reconstructed); // floor
431 output[idx] = opacity * reconstructed + (1.f - opacity) * base; // out = a*rec + (1-a)*base
432 }
433}
434
436void _remosaic_and_replace_xtrans(const float *const restrict input, const float *const restrict input_raw,
437 const float *const restrict interpolated,
438 const float *const restrict clipping_mask, float *const restrict output,
439 const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips,
440 const int clip_is_floor, const dt_iop_roi_t *const roi_in,
441 const uint8_t (*const xtrans)[6], const size_t width, const size_t height)
442{
443 // see _remosaic_and_replace for the clip_is_floor semantics and the compositing rule
444 // out = opacity*rec + (1 - opacity)*base, base = max(raw, rec) on a clipped floor.
445 __OMP_PARALLEL_FOR__(collapse(2))
446 for(size_t i = 0; i < height; i++)
447 for(size_t j = 0; j < width; j++)
448 {
449 const size_t idx = i * width + j;
450 const size_t index = idx * 4;
451 const int c = FCxtrans((int)i, (int)j, roi_in, xtrans);
452 const float opacity = clipping_mask[index + ALPHA]; // any-clip mask -> blend weight (0 or 1)
453 // undo local channel normalization (x tile-average white_balance[c]), clamp >= 0
454 const float reconstructed = fmaxf(interpolated[index + c] * white_balance[c], 0.f);
455 float base = input[idx];
456 if(clip_is_floor && input_raw[idx] >= clips[c]) base = fmaxf(base, reconstructed); // floor
457 output[idx] = opacity * reconstructed + (1.f - opacity) * base; // out = a*rec + (1-a)*base
458 }
459}
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static float lookup(read_only image2d_t lut, const float x)
#define B(y, x)
const dt_aligned_pixel_t f
static const int row
static dt_aligned_pixel_t RGB
#define for_each_channel(_var,...)
Definition darktable.h:684
#define __DT_CLONE_TARGETS__
Definition darktable.h:379
#define for_four_channels(_var,...)
Definition darktable.h:686
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
static const dt_aligned_pixel_simd_t value
Definition darktable.h:599
#define BLUE
#define RED
#define GREEN
static int FCxtrans(const int row, const int col, global const unsigned char(*const xtrans)[6])
static int FC(const int row, const int col, const unsigned int filters)
#define ALPHA
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:30
__DT_CLONE_TARGETS__ void _compute_laplacian_normalization(const float *const restrict input, const dt_iop_roi_t *const roi_in, const uint32_t filters, const uint8_t(*const xtrans)[6], dt_aligned_pixel_t normalization)
Definition gather.c:222
__DT_CLONE_TARGETS__ void _remosaic_and_replace_xtrans(const float *const restrict input, const float *const restrict input_raw, const float *const restrict interpolated, const float *const restrict clipping_mask, float *const restrict output, const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips, const int clip_is_floor, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const size_t width, const size_t height)
Definition gather.c:436
__DT_CLONE_TARGETS__ void _interpolate_and_mask(const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_aligned_pixel_t clips_in, const dt_aligned_pixel_t det_scale, const dt_aligned_pixel_t white_balance, const uint32_t filters, const size_t width, const size_t height)
Definition gather.c:66
__DT_CLONE_TARGETS__ void _remosaic_and_replace(const float *const restrict input, const float *const restrict input_raw, const float *const restrict interpolated, const float *const restrict clipping_mask, float *const restrict output, const dt_aligned_pixel_t white_balance, const dt_aligned_pixel_t clips, const int clip_is_floor, const uint32_t filters, const size_t width, const size_t height)
Definition gather.c:405
__DT_CLONE_TARGETS__ void _interpolate_and_mask_xtrans(const float *const restrict input, float *const restrict interpolated, float *const restrict clipping_mask, const dt_aligned_pixel_t clips, const dt_aligned_pixel_t white_balance, const dt_iop_roi_t *const roi_in, const int32_t lookup[6][6][32], const uint8_t(*const xtrans)[6], const size_t width, const size_t height)
Definition gather.c:298
__DT_CLONE_TARGETS__ void _build_xtrans_bilinear_lookup(int32_t lookup[6][6][32], const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6])
Definition gather.c:258
static const float x
float *const restrict const size_t k
#define R
float dt_aligned_pixel_t[4]
Region of interest passed through the pixelpipe.
Definition imageop.h:72
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29