Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageop_math.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2016-2017 Dan Torop.
4 Copyright (C) 2016 Roman Lebedev.
5 Copyright (C) 2016 Tobias Ellinghaus.
6 Copyright (C) 2019 Andreas Schneider.
7 Copyright (C) 2019, 2024 Aurélien PIERRE.
8 Copyright (C) 2019-2021 Pascal Obry.
9 Copyright (C) 2021 Hanno Schwalm.
10 Copyright (C) 2021 Ralf Brown.
11 Copyright (C) 2022 Martin Bařinka.
12
13 darktable is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 darktable is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with darktable. If not, see <http://www.gnu.org/licenses/>.
25*/
26
28#include <assert.h> // for assert
29#include <glib.h> // for MIN, MAX, CLAMP, inline
30#include <math.h> // for round, floorf, fmaxf
31#include "common/darktable.h" // for darktable, darktable_t, dt_code...
32#include "common/imageio.h" // for FILTERS_ARE_4BAYER
33#include "common/interpolation.h" // for dt_interpolation_new, dt_interp...
34#include "develop/imageop.h" // for dt_iop_roi_t
35
36void dt_iop_flip_and_zoom_8(const uint8_t *in, int32_t iw, int32_t ih, uint8_t *out, int32_t ow, int32_t oh,
37 const dt_image_orientation_t orientation, uint32_t *width, uint32_t *height)
38{
39 // init strides:
40 const uint32_t iwd = (orientation & ORIENTATION_SWAP_XY) ? ih : iw;
41 const uint32_t iht = (orientation & ORIENTATION_SWAP_XY) ? iw : ih;
42 // DO NOT UPSCALE !!!
43 const float scale = fmaxf(1.0, fmaxf(iwd / (float)ow, iht / (float)oh));
44 const uint32_t wd = *width = MIN(ow, iwd / scale);
45 const uint32_t ht = *height = MIN(oh, iht / scale);
46 const int bpp = 4; // bytes per pixel
47 int32_t ii = 0, jj = 0;
48 int32_t si = 1, sj = iw;
49 if(orientation & ORIENTATION_FLIP_Y)
50 {
51 jj = ih - jj - 1;
52 sj = -sj;
53 }
54 if(orientation & ORIENTATION_FLIP_X)
55 {
56 ii = iw - ii - 1;
57 si = -si;
58 }
59 if(orientation & ORIENTATION_SWAP_XY)
60 {
61 int t = sj;
62 sj = si;
63 si = t;
64 }
65 const int32_t half_pixel = .5f * scale;
66 const int32_t offm = half_pixel * bpp * MIN(MIN(0, si), MIN(sj, si + sj));
67 const int32_t offM = half_pixel * bpp * MAX(MAX(0, si), MAX(sj, si + sj));
69 for(uint32_t j = 0; j < ht; j++)
70 {
71 uint8_t *out2 = out + bpp * wd * j;
72 const uint8_t *in2 = in + bpp * (iw * jj + ii + sj * (int32_t)(scale * j));
73 float stepi = 0.0f;
74 for(uint32_t i = 0; i < wd; i++)
75 {
76 const uint8_t *in3 = in2 + ((int32_t)stepi) * si * bpp;
77 // this should always be within the bounds of in[], due to the way
78 // wd/ht are constructed by always just rounding down. half_pixel should never
79 // add up to one pixel difference.
80 // we have this check with the hope the branch predictor will get rid of it:
81 if(in3 + offm >= in && in3 + offM < in + bpp * iw * ih)
82 {
83 for(int k = 0; k < 3; k++)
84 out2[k] = // in3[k];
85 CLAMP(((int32_t)in3[bpp * half_pixel * sj + k]
86 + (int32_t)in3[bpp * half_pixel * (si + sj) + k]
87 + (int32_t)in3[bpp * half_pixel * si + k]
88 + (int32_t)in3[k]) / 4,
89 0, 255);
90 }
91 out2 += bpp;
92 stepi += scale;
93 }
94 }
95}
96
97void dt_iop_clip_and_zoom_8(const uint8_t *i, int32_t ix, int32_t iy, int32_t iw, int32_t ih, int32_t ibw,
98 int32_t ibh, uint8_t *o, int32_t ox, int32_t oy, int32_t ow, int32_t oh,
99 int32_t obw, int32_t obh)
100{
101 const float scalex = iw / (float)ow;
102 const float scaley = ih / (float)oh;
103 const int32_t ix2 = MAX(ix, 0);
104 const int32_t iy2 = MAX(iy, 0);
105 const int32_t ox2 = MAX(ox, 0);
106 const int32_t oy2 = MAX(oy, 0);
107 const int32_t oh2 = MIN(MIN(oh, (ibh - iy2) / scaley), obh - oy2);
108 const int32_t ow2 = MIN(MIN(ow, (ibw - ix2) / scalex), obw - ox2);
109 assert((int)(ix2 + ow2 * scalex) <= ibw);
110 assert((int)(iy2 + oh2 * scaley) <= ibh);
111 assert(ox2 + ow2 <= obw);
112 assert(oy2 + oh2 <= obh);
113 assert(ix2 >= 0 && iy2 >= 0 && ox2 >= 0 && oy2 >= 0);
114 float x = ix2, y = iy2;
115 for(int s = 0; s < oh2; s++)
116 {
117 int idx = ox2 + obw * (oy2 + s);
118 for(int t = 0; t < ow2; t++)
119 {
120 for(int k = 0; k < 3; k++)
121 o[4 * idx + k] = // i[3*(ibw* (int)y + (int)x ) + k)];
122 CLAMP(((int32_t)i[(4 * (ibw * (int32_t)y + (int32_t)(x + .5f * scalex)) + k)]
123 + (int32_t)i[(4 * (ibw * (int32_t)(y + .5f * scaley) + (int32_t)(x + .5f * scalex)) + k)]
124 + (int32_t)i[(4 * (ibw * (int32_t)(y + .5f * scaley) + (int32_t)(x)) + k)]
125 + (int32_t)i[(4 * (ibw * (int32_t)y + (int32_t)(x)) + k)])
126 / 4,
127 0, 255);
128 x += scalex;
129 idx++;
130 }
131 y += scaley;
132 x = ix2;
133 }
134}
135
136// apply clip and zoom on parts of a supplied full image.
137// roi_in and roi_out define which part to work on.
138void dt_iop_clip_and_zoom(float *out, const float *const in, const dt_iop_roi_t *const roi_out,
139 const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride)
140{
142 dt_interpolation_resample(itor, out, roi_out, in, roi_in);
143}
144
145// apply clip and zoom on the image region supplied in the input buffer.
146// roi_in and roi_out describe which part of the full image this relates to.
147void dt_iop_clip_and_zoom_roi(float *out, const float *const in, const dt_iop_roi_t *const roi_out,
148 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
149 const int32_t in_stride)
150{
152 dt_interpolation_resample_roi(itor, out, roi_out, in, roi_in);
153}
154
155#ifdef HAVE_OPENCL
156// apply clip and zoom on parts of a supplied full image.
157// roi_in and roi_out define which part to work on.
158int dt_iop_clip_and_zoom_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out,
159 const dt_iop_roi_t *const roi_in)
160{
162 return dt_interpolation_resample_cl(itor, devid, dev_out, roi_out, dev_in, roi_in);
163}
164
165// apply clip and zoom on the image region supplied in the input buffer.
166// roi_in and roi_out describe which part of the full image this relates to.
167int dt_iop_clip_and_zoom_roi_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out,
168 const dt_iop_roi_t *const roi_in)
169{
171 return dt_interpolation_resample_roi_cl(itor, devid, dev_out, roi_out, dev_in, roi_in);
172}
173
174#endif
175
176void dt_iop_clip_and_zoom_mosaic_half_size(uint16_t *const out, const uint16_t *const in,
177 const dt_iop_roi_t *const roi_out,
178 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
179 const int32_t in_stride, const uint32_t filters)
180{
181 // adjust to pixel region and don't sample more than scale/2 nbs!
182 // pixel footprint on input buffer, radius:
183 const float px_footprint = 1.f / roi_out->scale;
184
185 // move to origin point 01 of a 2x2 CFA block
186 // (RGGB=0112 or CYGM=0132)
187 int trggbx = 0, trggby = 0;
188 if(FC(trggby, trggbx + 1, filters) != 1) trggbx++;
189 if(FC(trggby, trggbx, filters) != 0)
190 {
191 trggbx = (trggbx + 1) & 1;
192 trggby++;
193 }
194 const int rggbx = trggbx, rggby = trggby;
195
196 // Create a reverse lookup of FC(): for each CFA color, a list of
197 // offsets from start of a 2x2 block at which to find that
198 // color. First index is color, second is to the list of offsets,
199 // preceded by the number of offsets.
200 int clut[4][3] = {{0}};
201 for(int y = 0; y < 2; ++y)
202 for(int x = 0; x < 2; ++x)
203 {
204 const int c = FC(y + rggby, x + rggbx, filters);
205 assert(clut[c][0] < 2);
206 clut[c][++clut[c][0]] = x + y * in_stride;
207 }
209 for(int y = 0; y < roi_out->height; y++)
210 {
211 uint16_t *outc = out + out_stride * y;
212
213 const float fy = (y + roi_out->y) * px_footprint;
214 const int miny = (CLAMPS((int)floorf(fy - px_footprint), 0, roi_in->height-3) & ~1u) + rggby;
215 const int maxy = MIN(roi_in->height-1, (int)ceilf(fy + px_footprint));
216
217 float fx = roi_out->x * px_footprint;
218 for(int x = 0; x < roi_out->width; x++, fx += px_footprint, outc++)
219 {
220 const int minx = (CLAMPS((int)floorf(fx - px_footprint), 0, roi_in->width-3) & ~1u) + rggbx;
221 const int maxx = MIN(roi_in->width-1, (int)ceilf(fx + px_footprint));
222
223 const int c = FC(y, x, filters);
224 int num = 0;
225 uint32_t col = 0;
226
227 for(int yy = miny; yy < maxy; yy += 2)
228 for(int xx = minx; xx < maxx; xx += 2)
229 {
230 col += in[clut[c][1] + xx + in_stride * yy];
231 num++;
232 if (clut[c][0] == 2)
233 { // G in RGGB CFA
234 col += in[clut[c][2] + xx + in_stride * yy];
235 num++;
236 }
237 }
238 if(num) *outc = col / num;
239 }
240 }
241}
242
243void dt_iop_clip_and_zoom_mosaic_half_size_f(float *const out, const float *const in,
244 const dt_iop_roi_t *const roi_out,
245 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
246 const int32_t in_stride, const uint32_t filters)
247{
248 // adjust to pixel region and don't sample more than scale/2 nbs!
249 // pixel footprint on input buffer, radius:
250 const float px_footprint = 1.f / roi_out->scale;
251 // how many 2x2 blocks can be sampled inside that area
252 const int samples = round(px_footprint / 2);
253
254 // move p to point to an rggb block:
255 int trggbx = 0, trggby = 0;
256 if(FC(trggby, trggbx + 1, filters) != 1) trggbx++;
257 if(FC(trggby, trggbx, filters) != 0)
258 {
259 trggbx = (trggbx + 1) & 1;
260 trggby++;
261 }
262 const int rggbx = trggbx, rggby = trggby;
264 for(int y = 0; y < roi_out->height; y++)
265 {
266 float *outc = out + out_stride * y;
267
268 const float fy = (y + roi_out->y) * px_footprint;
269 int py = (int)fy & ~1;
270 const float dy = (fy - py) / 2;
271 py = MIN(((roi_in->height - 6) & ~1u), py) + rggby;
272
273 int maxj = MIN(((roi_in->height - 5) & ~1u) + rggby, py + 2 * samples);
274
275 for(int x = 0; x < roi_out->width; x++)
276 {
277 dt_aligned_pixel_t col = { 0, 0, 0, 0 };
278
279 const float fx = (x + roi_out->x) * px_footprint;
280 int px = (int)fx & ~1;
281 const float dx = (fx - px) / 2;
282 px = MIN(((roi_in->width - 6) & ~1u), px) + rggbx;
283
284 const int maxi = MIN(((roi_in->width - 5) & ~1u) + rggbx, px + 2 * samples);
285
287 float num = 0;
288
289 // upper left 2x2 block of sampling region
290 p[0] = in[px + in_stride * py];
291 p[1] = in[px + 1 + in_stride * py];
292 p[2] = in[px + in_stride * (py + 1)];
293 p[3] = in[px + 1 + in_stride * (py + 1)];
294 for(int c = 0; c < 4; c++) col[c] += ((1 - dx) * (1 - dy)) * p[c];
295
296 // left 2x2 block border of sampling region
297 for(int j = py + 2; j <= maxj; j += 2)
298 {
299 p[0] = in[px + in_stride * j];
300 p[1] = in[px + 1 + in_stride * j];
301 p[2] = in[px + in_stride * (j + 1)];
302 p[3] = in[px + 1 + in_stride * (j + 1)];
303 for(int c = 0; c < 4; c++) col[c] += (1 - dx) * p[c];
304 }
305
306 // upper 2x2 block border of sampling region
307 for(int i = px + 2; i <= maxi; i += 2)
308 {
309 p[0] = in[i + in_stride * py];
310 p[1] = in[i + 1 + in_stride * py];
311 p[2] = in[i + in_stride * (py + 1)];
312 p[3] = in[i + 1 + in_stride * (py + 1)];
313 for(int c = 0; c < 4; c++) col[c] += (1 - dy) * p[c];
314 }
315
316 // 2x2 blocks in the middle of sampling region
317 for(int j = py + 2; j <= maxj; j += 2)
318 for(int i = px + 2; i <= maxi; i += 2)
319 {
320 p[0] = in[i + in_stride * j];
321 p[1] = in[i + 1 + in_stride * j];
322 p[2] = in[i + in_stride * (j + 1)];
323 p[3] = in[i + 1 + in_stride * (j + 1)];
324 for(int c = 0; c < 4; c++) col[c] += p[c];
325 }
326
327 if(maxi == px + 2 * samples && maxj == py + 2 * samples)
328 {
329 // right border
330 for(int j = py + 2; j <= maxj; j += 2)
331 {
332 p[0] = in[maxi + 2 + in_stride * j];
333 p[1] = in[maxi + 3 + in_stride * j];
334 p[2] = in[maxi + 2 + in_stride * (j + 1)];
335 p[3] = in[maxi + 3 + in_stride * (j + 1)];
336 for(int c = 0; c < 4; c++) col[c] += dx * p[c];
337 }
338
339 // upper right
340 p[0] = in[maxi + 2 + in_stride * py];
341 p[1] = in[maxi + 3 + in_stride * py];
342 p[2] = in[maxi + 2 + in_stride * (py + 1)];
343 p[3] = in[maxi + 3 + in_stride * (py + 1)];
344 for(int c = 0; c < 4; c++) col[c] += (dx * (1 - dy)) * p[c];
345
346 // lower border
347 for(int i = px + 2; i <= maxi; i += 2)
348 {
349 p[0] = in[i + in_stride * (maxj + 2)];
350 p[1] = in[i + 1 + in_stride * (maxj + 2)];
351 p[2] = in[i + in_stride * (maxj + 3)];
352 p[3] = in[i + 1 + in_stride * (maxj + 3)];
353 for(int c = 0; c < 4; c++) col[c] += dy * p[c];
354 }
355
356 // lower left 2x2 block
357 p[0] = in[px + in_stride * (maxj + 2)];
358 p[1] = in[px + 1 + in_stride * (maxj + 2)];
359 p[2] = in[px + in_stride * (maxj + 3)];
360 p[3] = in[px + 1 + in_stride * (maxj + 3)];
361 for(int c = 0; c < 4; c++) col[c] += ((1 - dx) * dy) * p[c];
362
363 // lower right 2x2 block
364 p[0] = in[maxi + 2 + in_stride * (maxj + 2)];
365 p[1] = in[maxi + 3 + in_stride * (maxj + 2)];
366 p[2] = in[maxi + 2 + in_stride * (maxj + 3)];
367 p[3] = in[maxi + 3 + in_stride * (maxj + 3)];
368 for(int c = 0; c < 4; c++) col[c] += (dx * dy) * p[c];
369
370 num = (samples + 1) * (samples + 1);
371 }
372 else if(maxi == px + 2 * samples)
373 {
374 // right border
375 for(int j = py + 2; j <= maxj; j += 2)
376 {
377 p[0] = in[maxi + 2 + in_stride * j];
378 p[1] = in[maxi + 3 + in_stride * j];
379 p[2] = in[maxi + 2 + in_stride * (j + 1)];
380 p[3] = in[maxi + 3 + in_stride * (j + 1)];
381 for(int c = 0; c < 4; c++) col[c] += dx * p[c];
382 }
383
384 // upper right
385 p[0] = in[maxi + 2 + in_stride * py];
386 p[1] = in[maxi + 3 + in_stride * py];
387 p[2] = in[maxi + 2 + in_stride * (py + 1)];
388 p[3] = in[maxi + 3 + in_stride * (py + 1)];
389 for(int c = 0; c < 4; c++) col[c] += (dx * (1 - dy)) * p[c];
390
391 num = ((maxj - py) / 2 + 1 - dy) * (samples + 1);
392 }
393 else if(maxj == py + 2 * samples)
394 {
395 // lower border
396 for(int i = px + 2; i <= maxi; i += 2)
397 {
398 p[0] = in[i + in_stride * (maxj + 2)];
399 p[1] = in[i + 1 + in_stride * (maxj + 2)];
400 p[2] = in[i + in_stride * (maxj + 3)];
401 p[3] = in[i + 1 + in_stride * (maxj + 3)];
402 for(int c = 0; c < 4; c++) col[c] += dy * p[c];
403 }
404
405 // lower left 2x2 block
406 p[0] = in[px + in_stride * (maxj + 2)];
407 p[1] = in[px + 1 + in_stride * (maxj + 2)];
408 p[2] = in[px + in_stride * (maxj + 3)];
409 p[3] = in[px + 1 + in_stride * (maxj + 3)];
410 for(int c = 0; c < 4; c++) col[c] += ((1 - dx) * dy) * p[c];
411
412 num = ((maxi - px) / 2 + 1 - dx) * (samples + 1);
413 }
414 else
415 {
416 num = ((maxi - px) / 2 + 1 - dx) * ((maxj - py) / 2 + 1 - dy);
417 }
418
419 const int c = (2 * ((y + rggby) % 2) + ((x + rggbx) % 2));
420 if(num) *outc = col[c] / num;
421 outc++;
422 }
423 }
424}
425
430void dt_iop_clip_and_zoom_mosaic_third_size_xtrans(uint16_t *const out, const uint16_t *const in,
431 const dt_iop_roi_t *const roi_out,
432 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
433 const int32_t in_stride, const uint8_t (*const xtrans)[6])
434{
435 const float px_footprint = 1.f / roi_out->scale;
436 // Use box filter of width px_footprint*2+1 centered on the current
437 // sample (rounded to nearest input pixel) to anti-alias. Higher MP
438 // images need larger filters to avoid artifacts.
440 for(int y = 0; y < roi_out->height; y++)
441 {
442 uint16_t *outc = out + out_stride * y;
443
444 const float fy = (y + roi_out->y) * px_footprint;
445 const int miny = MAX(0, (int)roundf(fy - px_footprint));
446 const int maxy = MIN(roi_in->height-1, (int)roundf(fy + px_footprint));
447
448 float fx = roi_out->x * px_footprint;
449 for(int x = 0; x < roi_out->width; x++, fx += px_footprint, outc++)
450 {
451 const int minx = MAX(0, (int)roundf(fx - px_footprint));
452 const int maxx = MIN(roi_in->width-1, (int)roundf(fx + px_footprint));
453
454 const int c = FCxtrans(y, x, roi_out, xtrans);
455 int num = 0;
456 uint32_t col = 0;
457
458 for(int yy = miny; yy <= maxy; ++yy)
459 for(int xx = minx; xx <= maxx; ++xx)
460 if(FCxtrans(yy, xx, roi_in, xtrans) == c)
461 {
462 col += in[xx + in_stride * yy];
463 num++;
464 }
465 *outc = col / num;
466 }
467 }
468}
469
470void dt_iop_clip_and_zoom_mosaic_third_size_xtrans_f(float *const out, const float *const in,
471 const dt_iop_roi_t *const roi_out,
472 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
473 const int32_t in_stride, const uint8_t (*const xtrans)[6])
474{
475 const float px_footprint = 1.f / roi_out->scale;
477 for(int y = 0; y < roi_out->height; y++)
478 {
479 float *outc = out + out_stride * y;
480
481 const float fy = (y + roi_out->y) * px_footprint;
482 const int miny = MAX(0, (int)roundf(fy - px_footprint));
483 const int maxy = MIN(roi_in->height-1, (int)roundf(fy + px_footprint));
484
485 float fx = roi_out->x * px_footprint;
486 for(int x = 0; x < roi_out->width; x++, fx += px_footprint, outc++)
487 {
488 const int minx = MAX(0, (int)roundf(fx - px_footprint));
489 const int maxx = MIN(roi_in->width-1, (int)roundf(fx + px_footprint));
490
491 const int c = FCxtrans(y, x, roi_out, xtrans);
492 int num = 0;
493 float col = 0.f;
494
495 for(int yy = miny; yy <= maxy; ++yy)
496 for(int xx = minx; xx <= maxx; ++xx)
497 if(FCxtrans(yy, xx, roi_in, xtrans) == c)
498 {
499 col += in[xx + in_stride * yy];
500 num++;
501 }
502 *outc = col / (float)num;
503 }
504 }
505}
506
508 const dt_iop_roi_t *const roi_out,
509 const dt_iop_roi_t *const roi_in,
510 const int32_t out_stride,
511 const int32_t in_stride)
512{
513 // adjust to pixel region and don't sample more than scale/2 nbs!
514 // pixel footprint on input buffer, radius:
515 const float px_footprint = 1.f / roi_out->scale;
516 // how many pixels can be sampled inside that area
517 const int samples = round(px_footprint);
519 for(int y = 0; y < roi_out->height; y++)
520 {
521 float *outc = out + 4 * (out_stride * y);
522
523 const float fy = (y + roi_out->y) * px_footprint;
524 int py = (int)fy;
525 const float dy = fy - py;
526 py = MIN(((roi_in->height - 3)), py);
527
528 const int maxj = MIN(((roi_in->height - 2)), py + samples);
529
530 for(int x = 0; x < roi_out->width; x++)
531 {
532 float col = 0.0f;
533
534 const float fx = (x + roi_out->x) * px_footprint;
535 int px = (int)fx;
536 const float dx = fx - px;
537 px = MIN(((roi_in->width - 3)), px);
538
539 const int maxi = MIN(((roi_in->width - 2)), px + samples);
540
541 float p;
542 float num = 0;
543
544 // upper left pixel of sampling region
545 p = in[px + in_stride * py];
546 col += ((1 - dx) * (1 - dy)) * p;
547
548 // left pixel border of sampling region
549 for(int j = py + 1; j <= maxj; j++)
550 {
551 p = in[px + in_stride * j];
552 col += (1 - dx) * p;
553 }
554
555 // upper pixel border of sampling region
556 for(int i = px + 1; i <= maxi; i++)
557 {
558 p = in[i + in_stride * py];
559 col += (1 - dy) * p;
560 }
561
562 // pixels in the middle of sampling region
563 for(int j = py + 1; j <= maxj; j++)
564 for(int i = px + 1; i <= maxi; i++)
565 {
566 p = in[i + in_stride * j];
567 col += p;
568 }
569
570 if(maxi == px + samples && maxj == py + samples)
571 {
572 // right border
573 for(int j = py + 1; j <= maxj; j++)
574 {
575 p = in[maxi + 1 + in_stride * j];
576 col += dx * p;
577 }
578
579 // upper right
580 p = in[maxi + 1 + in_stride * py];
581 col += (dx * (1 - dy)) * p;
582
583 // lower border
584 for(int i = px + 1; i <= maxi; i++)
585 {
586 p = in[i + in_stride * (maxj + 1)];
587 col += dy * p;
588 }
589
590 // lower left pixel
591 p = in[px + in_stride * (maxj + 1)];
592 col += ((1 - dx) * dy) * p;
593
594 // lower right pixel
595 p = in[maxi + 1 + in_stride * (maxj + 1)];
596 col += (dx * dy) * p;
597
598 num = (samples + 1) * (samples + 1);
599 }
600 else if(maxi == px + samples)
601 {
602 // right border
603 for(int j = py + 1; j <= maxj; j++)
604 {
605 p = in[maxi + 1 + in_stride * j];
606 col += dx * p;
607 }
608
609 // upper right
610 p = in[maxi + 1 + in_stride * py];
611 col += (dx * (1 - dy)) * p;
612
613 num = ((maxj - py) / 2 + 1 - dy) * (samples + 1);
614 }
615 else if(maxj == py + samples)
616 {
617 // lower border
618 for(int i = px + 1; i <= maxi; i++)
619 {
620 p = in[i + in_stride * (maxj + 1)];
621 col += dy * p;
622 }
623
624 // lower left pixel
625 p = in[px + in_stride * (maxj + 1)];
626 col += ((1 - dx) * dy) * p;
627
628 num = ((maxi - px) / 2 + 1 - dx) * (samples + 1);
629 }
630 else
631 {
632 num = ((maxi - px) / 2 + 1 - dx) * ((maxj - py) / 2 + 1 - dy);
633 }
634
635 const float pix = (num) ? col / num : 0.0f;
636 outc[0] = pix;
637 outc[1] = pix;
638 outc[2] = pix;
639 outc[3] = 0.0f;
640 outc += 4;
641 }
642 }
643}
644
645void dt_iop_clip_and_zoom_demosaic_half_size_f(float *out, const float *const in,
646 const dt_iop_roi_t *const roi_out,
647 const dt_iop_roi_t *const roi_in, const int32_t out_stride,
648 const int32_t in_stride, const uint32_t filters)
649{
650 // adjust to pixel region and don't sample more than scale/2 nbs!
651 // pixel footprint on input buffer, radius:
652 const float px_footprint = 1.f / roi_out->scale;
653 // how many 2x2 blocks can be sampled inside that area
654 const int samples = round(px_footprint / 2);
655
656 // move p to point to an rggb block:
657 int trggbx = 0, trggby = 0;
658 if(FC(trggby, trggbx + 1, filters) != 1) trggbx++;
659 if(FC(trggby, trggbx, filters) != 0)
660 {
661 trggbx = (trggbx + 1) & 1;
662 trggby++;
663 }
664 const int rggbx = trggbx, rggby = trggby;
666 for(int y = 0; y < roi_out->height; y++)
667 {
668 float *outc = out + 4 * (out_stride * y);
669
670 const float fy = (y + roi_out->y) * px_footprint;
671 int py = (int)fy & ~1;
672 const float dy = (fy - py) / 2;
673 py = MIN(((roi_in->height - 6) & ~1u), py) + rggby;
674
675 const int maxj = MIN(((roi_in->height - 5) & ~1u) + rggby, py + 2 * samples);
676
677 for(int x = 0; x < roi_out->width; x++)
678 {
679 dt_aligned_pixel_t col = { 0, 0, 0, 0 };
680
681 const float fx = (x + roi_out->x) * px_footprint;
682 int px = (int)fx & ~1;
683 const float dx = (fx - px) / 2;
684 px = MIN(((roi_in->width - 6) & ~1u), px) + rggbx;
685
686 const int maxi = MIN(((roi_in->width - 5) & ~1u) + rggbx, px + 2 * samples);
687
689 float num = 0;
690
691 // upper left 2x2 block of sampling region
692 p[0] = in[px + in_stride * py];
693 p[1] = in[px + 1 + in_stride * py] + in[px + in_stride * (py + 1)];
694 p[2] = in[px + 1 + in_stride * (py + 1)];
695 for(int c = 0; c < 3; c++) col[c] += ((1 - dx) * (1 - dy)) * p[c];
696
697 // left 2x2 block border of sampling region
698 for(int j = py + 2; j <= maxj; j += 2)
699 {
700 p[0] = in[px + in_stride * j];
701 p[1] = in[px + 1 + in_stride * j] + in[px + in_stride * (j + 1)];
702 p[2] = in[px + 1 + in_stride * (j + 1)];
703 for(int c = 0; c < 3; c++) col[c] += (1 - dx) * p[c];
704 }
705
706 // upper 2x2 block border of sampling region
707 for(int i = px + 2; i <= maxi; i += 2)
708 {
709 p[0] = in[i + in_stride * py];
710 p[1] = in[i + 1 + in_stride * py] + in[i + in_stride * (py + 1)];
711 p[2] = in[i + 1 + in_stride * (py + 1)];
712 for(int c = 0; c < 3; c++) col[c] += (1 - dy) * p[c];
713 }
714
715 // 2x2 blocks in the middle of sampling region
716 for(int j = py + 2; j <= maxj; j += 2)
717 for(int i = px + 2; i <= maxi; i += 2)
718 {
719 p[0] = in[i + in_stride * j];
720 p[1] = in[i + 1 + in_stride * j] + in[i + in_stride * (j + 1)];
721 p[2] = in[i + 1 + in_stride * (j + 1)];
722 for(int c = 0; c < 3; c++) col[c] += p[c];
723 }
724
725 if(maxi == px + 2 * samples && maxj == py + 2 * samples)
726 {
727 // right border
728 for(int j = py + 2; j <= maxj; j += 2)
729 {
730 p[0] = in[maxi + 2 + in_stride * j];
731 p[1] = in[maxi + 3 + in_stride * j] + in[maxi + 2 + in_stride * (j + 1)];
732 p[2] = in[maxi + 3 + in_stride * (j + 1)];
733 for(int c = 0; c < 3; c++) col[c] += dx * p[c];
734 }
735
736 // upper right
737 p[0] = in[maxi + 2 + in_stride * py];
738 p[1] = in[maxi + 3 + in_stride * py] + in[maxi + 2 + in_stride * (py + 1)];
739 p[2] = in[maxi + 3 + in_stride * (py + 1)];
740 for(int c = 0; c < 3; c++) col[c] += (dx * (1 - dy)) * p[c];
741
742 // lower border
743 for(int i = px + 2; i <= maxi; i += 2)
744 {
745 p[0] = in[i + in_stride * (maxj + 2)];
746 p[1] = in[i + 1 + in_stride * (maxj + 2)] + in[i + in_stride * (maxj + 3)];
747 p[2] = in[i + 1 + in_stride * (maxj + 3)];
748 for(int c = 0; c < 3; c++) col[c] += dy * p[c];
749 }
750
751 // lower left 2x2 block
752 p[0] = in[px + in_stride * (maxj + 2)];
753 p[1] = in[px + 1 + in_stride * (maxj + 2)] + in[px + in_stride * (maxj + 3)];
754 p[2] = in[px + 1 + in_stride * (maxj + 3)];
755 for(int c = 0; c < 3; c++) col[c] += ((1 - dx) * dy) * p[c];
756
757 // lower right 2x2 block
758 p[0] = in[maxi + 2 + in_stride * (maxj + 2)];
759 p[1] = in[maxi + 3 + in_stride * (maxj + 2)] + in[maxi + 2 + in_stride * (maxj + 3)];
760 p[2] = in[maxi + 3 + in_stride * (maxj + 3)];
761 for(int c = 0; c < 3; c++) col[c] += (dx * dy) * p[c];
762
763 num = (samples + 1) * (samples + 1);
764 }
765 else if(maxi == px + 2 * samples)
766 {
767 // right border
768 for(int j = py + 2; j <= maxj; j += 2)
769 {
770 p[0] = in[maxi + 2 + in_stride * j];
771 p[1] = in[maxi + 3 + in_stride * j] + in[maxi + 2 + in_stride * (j + 1)];
772 p[2] = in[maxi + 3 + in_stride * (j + 1)];
773 for(int c = 0; c < 3; c++) col[c] += dx * p[c];
774 }
775
776 // upper right
777 p[0] = in[maxi + 2 + in_stride * py];
778 p[1] = in[maxi + 3 + in_stride * py] + in[maxi + 2 + in_stride * (py + 1)];
779 p[2] = in[maxi + 3 + in_stride * (py + 1)];
780 for(int c = 0; c < 3; c++) col[c] += (dx * (1 - dy)) * p[c];
781
782 num = ((maxj - py) / 2 + 1 - dy) * (samples + 1);
783 }
784 else if(maxj == py + 2 * samples)
785 {
786 // lower border
787 for(int i = px + 2; i <= maxi; i += 2)
788 {
789 p[0] = in[i + in_stride * (maxj + 2)];
790 p[1] = in[i + 1 + in_stride * (maxj + 2)] + in[i + in_stride * (maxj + 3)];
791 p[2] = in[i + 1 + in_stride * (maxj + 3)];
792 for(int c = 0; c < 3; c++) col[c] += dy * p[c];
793 }
794
795 // lower left 2x2 block
796 p[0] = in[px + in_stride * (maxj + 2)];
797 p[1] = in[px + 1 + in_stride * (maxj + 2)] + in[px + in_stride * (maxj + 3)];
798 p[2] = in[px + 1 + in_stride * (maxj + 3)];
799 for(int c = 0; c < 3; c++) col[c] += ((1 - dx) * dy) * p[c];
800
801 num = ((maxi - px) / 2 + 1 - dx) * (samples + 1);
802 }
803 else
804 {
805 num = ((maxi - px) / 2 + 1 - dx) * ((maxj - py) / 2 + 1 - dy);
806 }
807
808 outc[0] = col[0] / num;
809 outc[1] = (col[1] / num) / 2.0f;
810 outc[2] = col[2] / num;
811 outc[3] = 0.0f;
812 outc += 4;
813 }
814 }
815}
816
817
819 const dt_iop_roi_t *const roi_out,
820 const dt_iop_roi_t *const roi_in,
821 const int32_t out_stride, const int32_t in_stride,
822 const uint8_t (*const xtrans)[6])
823{
824 const float px_footprint = 1.f / roi_out->scale;
825 const int samples = MAX(1, (int)floorf(px_footprint / 3));
826
827 // A slightly different algorithm than
828 // dt_iop_clip_and_zoom_demosaic_half_size_f() which aligns to 2x2
829 // Bayer grid and hence most pull additional data from all edges
830 // which don't align with CFA. Instead align to a 3x3 pattern (which
831 // is semi-regular in X-Trans CFA). This code doesn't worry about
832 // fractional pixel offset of top/left of pattern nor oversampling
833 // by non-integer number of samples.
835 for(int y = 0; y < roi_out->height; y++)
836 {
837 float *outc = out + 4 * (out_stride * y);
838 const int py = CLAMPS((int)round((y + roi_out->y - 0.5f) * px_footprint), 0, roi_in->height - 3);
839 const int ymax = MIN(roi_in->height - 3, py + 3 * samples);
840
841 for(int x = 0; x < roi_out->width; x++, outc += 4)
842 {
843 dt_aligned_pixel_t col = { 0.0f };
844 int num = 0;
845 const int px = CLAMPS((int)round((x + roi_out->x - 0.5f) * px_footprint), 0, roi_in->width - 3);
846 const int xmax = MIN(roi_in->width - 3, px + 3 * samples);
847 for(int yy = py; yy <= ymax; yy += 3)
848 for(int xx = px; xx <= xmax; xx += 3)
849 {
850 for(int j = 0; j < 3; ++j)
851 for(int i = 0; i < 3; ++i)
852 col[FCxtrans(yy + j, xx + i, roi_in, xtrans)] += in[xx + i + in_stride * (yy + j)];
853 num++;
854 }
855
856 // X-Trans RGB weighting averages to 2:5:2 for each 3x3 cell
857 outc[0] = col[0] / (num * 2);
858 outc[1] = col[1] / (num * 5);
859 outc[2] = col[2] / (num * 2);
860 }
861 }
862}
863
865{
866 yuv[0] = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2];
867 yuv[1] = -0.147 * rgb[0] - 0.289 * rgb[1] + 0.437 * rgb[2];
868 yuv[2] = 0.615 * rgb[0] - 0.515 * rgb[1] - 0.100 * rgb[2];
869}
870
872{
873 rgb[0] = yuv[0] + 1.140 * yuv[2];
874 rgb[1] = yuv[0] - 0.394 * yuv[1] - 0.581 * yuv[2];
875 rgb[2] = yuv[0] + 2.028 * yuv[1];
876}
877
878static inline void mat4inv(const float X[][4], float R[][4])
879{
880 const float det = X[0][3] * X[1][2] * X[2][1] * X[3][0] - X[0][2] * X[1][3] * X[2][1] * X[3][0]
881 - X[0][3] * X[1][1] * X[2][2] * X[3][0] + X[0][1] * X[1][3] * X[2][2] * X[3][0]
882 + X[0][2] * X[1][1] * X[2][3] * X[3][0] - X[0][1] * X[1][2] * X[2][3] * X[3][0]
883 - X[0][3] * X[1][2] * X[2][0] * X[3][1] + X[0][2] * X[1][3] * X[2][0] * X[3][1]
884 + X[0][3] * X[1][0] * X[2][2] * X[3][1] - X[0][0] * X[1][3] * X[2][2] * X[3][1]
885 - X[0][2] * X[1][0] * X[2][3] * X[3][1] + X[0][0] * X[1][2] * X[2][3] * X[3][1]
886 + X[0][3] * X[1][1] * X[2][0] * X[3][2] - X[0][1] * X[1][3] * X[2][0] * X[3][2]
887 - X[0][3] * X[1][0] * X[2][1] * X[3][2] + X[0][0] * X[1][3] * X[2][1] * X[3][2]
888 + X[0][1] * X[1][0] * X[2][3] * X[3][2] - X[0][0] * X[1][1] * X[2][3] * X[3][2]
889 - X[0][2] * X[1][1] * X[2][0] * X[3][3] + X[0][1] * X[1][2] * X[2][0] * X[3][3]
890 + X[0][2] * X[1][0] * X[2][1] * X[3][3] - X[0][0] * X[1][2] * X[2][1] * X[3][3]
891 - X[0][1] * X[1][0] * X[2][2] * X[3][3] + X[0][0] * X[1][1] * X[2][2] * X[3][3];
892 R[0][0] = (X[1][2] * X[2][3] * X[3][1] - X[1][3] * X[2][2] * X[3][1] + X[1][3] * X[2][1] * X[3][2]
893 - X[1][1] * X[2][3] * X[3][2] - X[1][2] * X[2][1] * X[3][3] + X[1][1] * X[2][2] * X[3][3])
894 / det;
895 R[1][0] = (X[1][3] * X[2][2] * X[3][0] - X[1][2] * X[2][3] * X[3][0] - X[1][3] * X[2][0] * X[3][2]
896 + X[1][0] * X[2][3] * X[3][2] + X[1][2] * X[2][0] * X[3][3] - X[1][0] * X[2][2] * X[3][3])
897 / det;
898 R[2][0] = (X[1][1] * X[2][3] * X[3][0] - X[1][3] * X[2][1] * X[3][0] + X[1][3] * X[2][0] * X[3][1]
899 - X[1][0] * X[2][3] * X[3][1] - X[1][1] * X[2][0] * X[3][3] + X[1][0] * X[2][1] * X[3][3])
900 / det;
901 R[3][0] = (X[1][2] * X[2][1] * X[3][0] - X[1][1] * X[2][2] * X[3][0] - X[1][2] * X[2][0] * X[3][1]
902 + X[1][0] * X[2][2] * X[3][1] + X[1][1] * X[2][0] * X[3][2] - X[1][0] * X[2][1] * X[3][2])
903 / det;
904
905 R[0][1] = (X[0][3] * X[2][2] * X[3][1] - X[0][2] * X[2][3] * X[3][1] - X[0][3] * X[2][1] * X[3][2]
906 + X[0][1] * X[2][3] * X[3][2] + X[0][2] * X[2][1] * X[3][3] - X[0][1] * X[2][2] * X[3][3])
907 / det;
908 R[1][1] = (X[0][2] * X[2][3] * X[3][0] - X[0][3] * X[2][2] * X[3][0] + X[0][3] * X[2][0] * X[3][2]
909 - X[0][0] * X[2][3] * X[3][2] - X[0][2] * X[2][0] * X[3][3] + X[0][0] * X[2][2] * X[3][3])
910 / det;
911 R[2][1] = (X[0][3] * X[2][1] * X[3][0] - X[0][1] * X[2][3] * X[3][0] - X[0][3] * X[2][0] * X[3][1]
912 + X[0][0] * X[2][3] * X[3][1] + X[0][1] * X[2][0] * X[3][3] - X[0][0] * X[2][1] * X[3][3])
913 / det;
914 R[3][1] = (X[0][1] * X[2][2] * X[3][0] - X[0][2] * X[2][1] * X[3][0] + X[0][2] * X[2][0] * X[3][1]
915 - X[0][0] * X[2][2] * X[3][1] - X[0][1] * X[2][0] * X[3][2] + X[0][0] * X[2][1] * X[3][2])
916 / det;
917
918 R[0][2] = (X[0][2] * X[1][3] * X[3][1] - X[0][3] * X[1][2] * X[3][1] + X[0][3] * X[1][1] * X[3][2]
919 - X[0][1] * X[1][3] * X[3][2] - X[0][2] * X[1][1] * X[3][3] + X[0][1] * X[1][2] * X[3][3])
920 / det;
921 R[1][2] = (X[0][3] * X[1][2] * X[3][0] - X[0][2] * X[1][3] * X[3][0] - X[0][3] * X[1][0] * X[3][2]
922 + X[0][0] * X[1][3] * X[3][2] + X[0][2] * X[1][0] * X[3][3] - X[0][0] * X[1][2] * X[3][3])
923 / det;
924 R[2][2] = (X[0][1] * X[1][3] * X[3][0] - X[0][3] * X[1][1] * X[3][0] + X[0][3] * X[1][0] * X[3][1]
925 - X[0][0] * X[1][3] * X[3][1] - X[0][1] * X[1][0] * X[3][3] + X[0][0] * X[1][1] * X[3][3])
926 / det;
927 R[3][2] = (X[0][2] * X[1][1] * X[3][0] - X[0][1] * X[1][2] * X[3][0] - X[0][2] * X[1][0] * X[3][1]
928 + X[0][0] * X[1][2] * X[3][1] + X[0][1] * X[1][0] * X[3][2] - X[0][0] * X[1][1] * X[3][2])
929 / det;
930
931 R[0][3] = (X[0][3] * X[1][2] * X[2][1] - X[0][2] * X[1][3] * X[2][1] - X[0][3] * X[1][1] * X[2][2]
932 + X[0][1] * X[1][3] * X[2][2] + X[0][2] * X[1][1] * X[2][3] - X[0][1] * X[1][2] * X[2][3])
933 / det;
934 R[1][3] = (X[0][2] * X[1][3] * X[2][0] - X[0][3] * X[1][2] * X[2][0] + X[0][3] * X[1][0] * X[2][2]
935 - X[0][0] * X[1][3] * X[2][2] - X[0][2] * X[1][0] * X[2][3] + X[0][0] * X[1][2] * X[2][3])
936 / det;
937 R[2][3] = (X[0][3] * X[1][1] * X[2][0] - X[0][1] * X[1][3] * X[2][0] - X[0][3] * X[1][0] * X[2][1]
938 + X[0][0] * X[1][3] * X[2][1] + X[0][1] * X[1][0] * X[2][3] - X[0][0] * X[1][1] * X[2][3])
939 / det;
940 R[3][3] = (X[0][1] * X[1][2] * X[2][0] - X[0][2] * X[1][1] * X[2][0] + X[0][2] * X[1][0] * X[2][1]
941 - X[0][0] * X[1][2] * X[2][1] - X[0][1] * X[1][0] * X[2][2] + X[0][0] * X[1][1] * X[2][2])
942 / det;
943}
944
945static void mat4mulv(float dst[4], const float mat[4][4], const float v[4])
946{
947 for(int k = 0; k < 4; k++)
948 {
949 float x = 0.0f;
950 for(int i = 0; i < 4; i++) x += mat[k][i] * v[i];
951 dst[k] = x;
952 }
953}
954
955void dt_iop_estimate_cubic(const float x[4], const float y[4], float a[4])
956{
957 // we want to fit a spline
958 // [y] [x^3 x^2 x^1 1] [a^3]
959 // |y| = |x^3 x^2 x^1 1| |a^2|
960 // |y| |x^3 x^2 x^1 1| |a^1|
961 // [y] [x^3 x^2 x^1 1] [ 1 ]
962 // and do that by inverting the matrix X:
963
964 const float X[4][4] = { { x[0] * x[0] * x[0], x[0] * x[0], x[0], 1.0f },
965 { x[1] * x[1] * x[1], x[1] * x[1], x[1], 1.0f },
966 { x[2] * x[2] * x[2], x[2] * x[2], x[2], 1.0f },
967 { x[3] * x[3] * x[3], x[3] * x[3], x[3], 1.0f } };
968 float X_inv[4][4];
969 mat4inv(X, X_inv);
970 mat4mulv(a, X_inv, y);
971}
972
973// clang-format off
974// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
975// vim: shiftwidth=2 expandtab tabstop=2 cindent
976// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
977// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static dt_aligned_pixel_t rgb
const dt_colormatrix_t dt_aligned_pixel_t out
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
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)
dt_image_orientation_t
Definition image.h:203
@ ORIENTATION_SWAP_XY
Definition image.h:208
@ ORIENTATION_FLIP_Y
Definition image.h:206
@ ORIENTATION_FLIP_X
Definition image.h:207
int bpp
void dt_iop_clip_and_zoom_8(const uint8_t *i, int32_t ix, int32_t iy, int32_t iw, int32_t ih, int32_t ibw, int32_t ibh, uint8_t *o, int32_t ox, int32_t oy, int32_t ow, int32_t oh, int32_t obw, int32_t obh)
void dt_iop_clip_and_zoom_roi(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride)
void dt_iop_clip_and_zoom_demosaic_passthrough_monochrome_f(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride)
void dt_iop_clip_and_zoom_mosaic_half_size_f(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint32_t filters)
void dt_iop_clip_and_zoom(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride)
int dt_iop_clip_and_zoom_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
void dt_iop_YCbCr_to_RGB(const dt_aligned_pixel_t yuv, dt_aligned_pixel_t rgb)
void dt_iop_RGB_to_YCbCr(const dt_aligned_pixel_t rgb, dt_aligned_pixel_t yuv)
void dt_iop_clip_and_zoom_demosaic_half_size_f(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint32_t filters)
void dt_iop_flip_and_zoom_8(const uint8_t *in, int32_t iw, int32_t ih, uint8_t *out, int32_t ow, int32_t oh, const dt_image_orientation_t orientation, uint32_t *width, uint32_t *height)
void dt_iop_clip_and_zoom_mosaic_half_size(uint16_t *const out, const uint16_t *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint32_t filters)
void dt_iop_clip_and_zoom_demosaic_third_size_xtrans_f(float *out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint8_t(*const xtrans)[6])
void dt_iop_estimate_cubic(const float x[4], const float y[4], float a[4])
void dt_iop_clip_and_zoom_mosaic_third_size_xtrans(uint16_t *const out, const uint16_t *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint8_t(*const xtrans)[6])
int dt_iop_clip_and_zoom_roi_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
static void mat4mulv(float dst[4], const float mat[4][4], const float v[4])
static void mat4inv(const float X[][4], float R[][4])
void dt_iop_clip_and_zoom_mosaic_third_size_xtrans_f(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const int32_t out_stride, const int32_t in_stride, const uint8_t(*const xtrans)[6])
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
void dt_interpolation_resample_roi(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
void dt_interpolation_resample(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
int dt_interpolation_resample_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
int dt_interpolation_resample_roi_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
@ DT_INTERPOLATION_USERPREF
static const float x
const int t
const float v
float *const restrict const size_t k
#define R
#define CLAMPS(A, L, H)
Definition math.h:76
float dt_aligned_pixel_t[4]
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29