Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
nlmeans.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011 Bruce Guenter.
4 Copyright (C) 2010-2013, 2016 johannes hanika.
5 Copyright (C) 2011 Henrik Andersson.
6 Copyright (C) 2011 Kanstantsin Shautsou.
7 Copyright (C) 2011 Pascal de Bruijn.
8 Copyright (C) 2011 Robert Bieber.
9 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
10 Copyright (C) 2011-2014, 2016-2017 Ulrich Pegelow.
11 Copyright (C) 2012 Richard Wonka.
12 Copyright (C) 2013 Edouard Gomez.
13 Copyright (C) 2014-2016 Roman Lebedev.
14 Copyright (C) 2015 Pedro Côrte-Real.
15 Copyright (C) 2017 Heiko Bauke.
16 Copyright (C) 2018, 2020, 2023, 2025-2026 Aurélien PIERRE.
17 Copyright (C) 2018 Edgardo Hoszowski.
18 Copyright (C) 2018 Maurizio Paglia.
19 Copyright (C) 2018, 2020, 2022 Pascal Obry.
20 Copyright (C) 2018-2019 rawfiner.
21 Copyright (C) 2019 Andreas Schneider.
22 Copyright (C) 2019 Diederik ter Rahe.
23 Copyright (C) 2020 Aldric Renaudin.
24 Copyright (C) 2020, 2022 Diederik Ter Rahe.
25 Copyright (C) 2020 Hubert Kowalski.
26 Copyright (C) 2020-2021 Ralf Brown.
27 Copyright (C) 2022 Hanno Schwalm.
28 Copyright (C) 2022 Martin Bařinka.
29 Copyright (C) 2022 Philipp Lutz.
30 Copyright (C) 2026 Guillaume Stutin.
31
32 darktable is free software: you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation, either version 3 of the License, or
35 (at your option) any later version.
36
37 darktable is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details.
41
42 You should have received a copy of the GNU General Public License
43 along with darktable. If not, see <http://www.gnu.org/licenses/>.
44*/
45#ifdef HAVE_CONFIG_H
46#include "system/macros.h"
47#include "system/mem_alloc.h"
49#include "common/logging.h"
50#include "system/simd.h"
51#include "config.h"
52#endif
53#include "widgets/bauhaus.h"
54#include "pixel/nlmeans_core.h"
55#include "common/opencl.h"
56#include "develop/imageop.h"
58#include "develop/imageop_gui.h"
59#include "develop/tiling.h"
60
61#include "iop/iop_api.h"
62#include <gtk/gtk.h>
63#include <stdlib.h>
64
65// which version of the non-local means code should be used? 0=old (this file), 1=new (src/common/nlmeans_core.c)
66#define USE_NEW_IMPL_CL 0
67
68// number of intermediate buffers used by OpenCL code path. Needs to match value in src/common/nlmeans_core.c
69// to correctly compute tiling
70#define NUM_BUCKETS 4
71
72// this is the version of the modules parameters,
73// and includes version information about compile-time dt
75
81
83{
84 // these are stored in db.
85 float radius; // $MIN: 0.0 $MAX: 10.0 $DEFAULT: 2.0 $DESCRIPTION: "patch size"
86 float strength; // $MIN: 0.0 $MAX: 100000.0 $DEFAULT: 50.0
87 float luma; // $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.5
88 float chroma; // $MIN: 0.0 $MAX: 1.0 $DEFAULT: 1.0
90
98
100
110
111
112const char *name()
113{
114 return _("astrophoto denoise");
115}
116
117const char *aliases()
118{
119 return _("denoise (non-local means)");
120}
121
122const char **description(struct dt_iop_module_t *self)
123{
124 return dt_iop_set_description(self, _("apply a poisson noise removal best suited for astrophotography"),
125 _("corrective"),
126 _("non-linear, Lab, display-referred"),
127 _("non-linear, Lab"),
128 _("non-linear, Lab, display-referred"));
129}
130
135
136int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
137 void *new_params, const int new_version)
138{
139 if(old_version == 1 && new_version == 2)
140 {
143 n->luma = o->luma;
144 n->chroma = o->chroma;
145 n->strength = 100.0f;
146 n->radius = 3;
147 return 0;
148 }
149 return 1;
150}
151
153{
154 return IOP_GROUP_REPAIR;
155}
156
161
162#if defined(HAVE_OPENCL) && !USE_NEW_IMPL_CL
163static int bucket_next(unsigned int *state, unsigned int max)
164{
165 unsigned int current = *state;
166 unsigned int next = (current >= max - 1 ? 0 : current + 1);
167
168 *state = next;
169
170 return next;
171}
172
173int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
174{
175 const dt_iop_roi_t *const roi_in = &piece->roi_in;
178#if USE_NEW_IMPL_CL
179 const int width = roi_in->width;
180 const int height = roi_in->height;
181
182 const float scale = fminf(roi_in->scale, 2.0f);
183 const int P = ceilf(d->radius * scale); // pixel filter size
184 const int K = ceilf(7 * scale); // nbhood
185 const float sharpness = 3000.0f / (1.0f + d->strength);
186
187 // adjust to Lab, make L more important
188 const float max_L = 120.0f, max_C = 512.0f;
189 const float nL = 1.0f / max_L, nC = 1.0f / max_C;
190 const float norm2[4] = { nL, nC }; //luma and chroma scaling factors
191
192 // allocate a buffer to receive the denoised image
193 const int devid = pipe->devid;
194 cl_mem dev_U2 = dt_opencl_alloc_device_buffer(devid, sizeof(float) * 4 * width * height);
195 if(IS_NULL_PTR(dev_U2))
196 {
197 dt_print(DT_DEBUG_OPENCL, "[opencl_nlmeans] couldn't allocate GPU buffer\n");
198 return FALSE;
199 }
200
202 {
203 .scattering = 0,
204 .scale = scale,
205 .luma = d->luma,
206 .chroma = d->chroma,
207 .center_weight = -1,
208 .sharpness = sharpness,
209 .patch_radius = P,
210 .search_radius = K,
211 .decimate = 0,
212 .norm = norm2,
213 .pipe = pipe,
214 .kernel_init = gd->kernel_nlmeans_init,
215 .kernel_dist = gd->kernel_nlmeans_dist,
216 .kernel_horiz = gd->kernel_nlmeans_horiz,
217 .kernel_vert = gd->kernel_nlmeans_vert,
218 .kernel_accu = gd->kernel_nlmeans_accu
219 };
220 cl_int err = nlmeans_denoise_cl(&params, devid, dev_in, dev_U2, roi_in);
221 if (err == CL_SUCCESS)
222 {
223 // normalize and blend
224 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
225 const float weight[4] = { d->luma, d->chroma, d->chroma, 1.0f };
226 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 0, sizeof(cl_mem), (void *)&dev_in);
227 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 1, sizeof(cl_mem), (void *)&dev_U2);
228 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 2, sizeof(cl_mem), (void *)&dev_out);
229 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 3, sizeof(int), (void *)&width);
230 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 4, sizeof(int), (void *)&height);
231 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 5, 4 * sizeof(float), (void *)&weight);
232 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_nlmeans_finish, sizes);
233 }
234 // clean up and check whether all kernels ran successfully
236 if (err == CL_SUCCESS)
237 return TRUE;
238 dt_print(DT_DEBUG_OPENCL, "[opencl_nlmeans] couldn't enqueue kernel! %d\n", err);
239 return FALSE;
240
241#else // old code
242 const int width = roi_in->width;
243 const int height = roi_in->height;
244
245 cl_int err = -999;
246
247 const float scale = fminf(roi_in->scale, 2.0f);
248 const int P = ceilf(d->radius * scale); // pixel filter size
249 const int K = ceilf(7 * scale); // nbhood
250 const float sharpness = 3000.0f / (1.0f + d->strength);
251
252 // adjust to Lab, make L more important
253 const float max_L = 120.0f, max_C = 512.0f;
254 const float nL = 1.0f / max_L, nC = 1.0f / max_C;
255 const float nL2 = nL * nL, nC2 = nC * nC;
256 const dt_aligned_pixel_t weight = { d->luma, d->chroma, d->chroma, 1.0f };
257
258 const int devid = pipe->devid;
259 cl_mem dev_U2 = dt_opencl_alloc_device_buffer(devid, sizeof(float) * 4 * width * height);
260 if(IS_NULL_PTR(dev_U2)) goto error;
261
262 cl_mem buckets[NUM_BUCKETS] = { NULL };
263 unsigned int state = 0;
264 for(int k = 0; k < NUM_BUCKETS; k++)
265 {
266 buckets[k] = dt_opencl_alloc_device_buffer(devid, sizeof(float) * width * height);
267 if(buckets[k] == NULL) goto error;
268 }
269
270 int hblocksize;
272 = (dt_opencl_local_buffer_t){ .xoffset = 2 * P, .xfactor = 1, .yoffset = 0, .yfactor = 1,
273 .cellsize = sizeof(float), .overhead = 0,
274 .sizex = 1 << 16, .sizey = 1 };
275
276 if(dt_opencl_local_buffer_opt(devid, gd->kernel_nlmeans_horiz, &hlocopt))
277 hblocksize = hlocopt.sizex;
278 else
279 hblocksize = 1;
280
281 int vblocksize;
283 = (dt_opencl_local_buffer_t){ .xoffset = 1, .xfactor = 1, .yoffset = 2 * P, .yfactor = 1,
284 .cellsize = sizeof(float), .overhead = 0,
285 .sizex = 1, .sizey = 1 << 16 };
286
287 if(dt_opencl_local_buffer_opt(devid, gd->kernel_nlmeans_vert, &vlocopt))
288 vblocksize = vlocopt.sizey;
289 else
290 vblocksize = 1;
291
292
293 size_t sizesl[3];
294 size_t local[3];
295 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
296
297 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_init, 0, sizeof(cl_mem), (void *)&dev_U2);
298 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_init, 1, sizeof(int), (void *)&width);
299 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_init, 2, sizeof(int), (void *)&height);
300 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_nlmeans_init, sizes);
301 if(err != CL_SUCCESS) goto error;
302
303
304 const size_t bwidth = ROUNDUP(width, hblocksize);
305 const size_t bheight = ROUNDUP(height, vblocksize);
306
307 for(int j = -K; j <= 0; j++)
308 for(int i = -K; i <= K; i++)
309 {
310 // The pipe abandoned this run: stop between two patches. The host enqueues the whole run far
311 // ahead of the device, so the killswitch is read once the previous patch has run on it.
312 if((j > -K || i > -K) && dt_opencl_finish(devid) && dt_dev_pixelpipe_has_shutdown(pipe)) goto error;
313
314 int q[2] = { i, j };
315
316 cl_mem dev_U4 = buckets[bucket_next(&state, NUM_BUCKETS)];
317 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 0, sizeof(cl_mem), (void *)&dev_in);
318 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 1, sizeof(cl_mem), (void *)&dev_U4);
319 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 2, sizeof(int), (void *)&width);
320 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 3, sizeof(int), (void *)&height);
321 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 4, 2 * sizeof(int), (void *)&q);
322 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 5, sizeof(float), (void *)&nL2);
323 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_dist, 6, sizeof(float), (void *)&nC2);
324 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_nlmeans_dist, sizes);
325 if(err != CL_SUCCESS) goto error;
326
327 sizesl[0] = bwidth;
328 sizesl[1] = ROUNDUPDHT(height, devid);
329 sizesl[2] = 1;
330 local[0] = hblocksize;
331 local[1] = 1;
332 local[2] = 1;
333 cl_mem dev_U4_t = buckets[bucket_next(&state, NUM_BUCKETS)];
334 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 0, sizeof(cl_mem), (void *)&dev_U4);
335 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 1, sizeof(cl_mem), (void *)&dev_U4_t);
336 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 2, sizeof(int), (void *)&width);
337 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 3, sizeof(int), (void *)&height);
338 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 4, 2 * sizeof(int), (void *)&q);
339 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 5, sizeof(int), (void *)&P);
340 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_horiz, 6, (hblocksize + 2 * P) * sizeof(float), NULL);
341 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_nlmeans_horiz, sizesl, local);
342 if(err != CL_SUCCESS) goto error;
343
344
345 sizesl[0] = ROUNDUPDWD(width, devid);
346 sizesl[1] = bheight;
347 sizesl[2] = 1;
348 local[0] = 1;
349 local[1] = vblocksize;
350 local[2] = 1;
351 cl_mem dev_U4_tt = buckets[bucket_next(&state, NUM_BUCKETS)];
352 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 0, sizeof(cl_mem), (void *)&dev_U4_t);
353 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 1, sizeof(cl_mem), (void *)&dev_U4_tt);
354 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 2, sizeof(int), (void *)&width);
355 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 3, sizeof(int), (void *)&height);
356 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 4, 2 * sizeof(int), (void *)&q);
357 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 5, sizeof(int), (void *)&P);
358 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 6, sizeof(float), (void *)&sharpness);
359 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_vert, 7, (vblocksize + 2 * P) * sizeof(float), NULL);
360 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_nlmeans_vert, sizesl, local);
361 if(err != CL_SUCCESS) goto error;
362
363
364 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 0, sizeof(cl_mem), (void *)&dev_in);
365 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 1, sizeof(cl_mem), (void *)&dev_U2);
366 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 2, sizeof(cl_mem), (void *)&dev_U4_tt);
367 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 3, sizeof(int), (void *)&width);
368 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 4, sizeof(int), (void *)&height);
369 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_accu, 5, 2 * sizeof(int), (void *)&q);
370 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_nlmeans_accu, sizes);
371 if(err != CL_SUCCESS) goto error;
372 }
373
374 // normalize and blend
375 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 0, sizeof(cl_mem), (void *)&dev_in);
376 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 1, sizeof(cl_mem), (void *)&dev_U2);
377 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 2, sizeof(cl_mem), (void *)&dev_out);
378 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 3, sizeof(int), (void *)&width);
379 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 4, sizeof(int), (void *)&height);
380 dt_opencl_set_kernel_arg(devid, gd->kernel_nlmeans_finish, 5, 4 * sizeof(float), (void *)&weight);
381 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_nlmeans_finish, sizes);
382 if(err != CL_SUCCESS) goto error;
383
385 for(int k = 0; k < NUM_BUCKETS; k++)
386 {
388 }
389 return TRUE;
390
391error:
393 for(int k = 0; k < NUM_BUCKETS; k++)
394 {
396 }
397
398 // an abandoned run comes here with the last patch's CL_SUCCESS: there is no error to report
399 if(err != CL_SUCCESS) dt_print(DT_DEBUG_OPENCL, "[opencl_nlmeans] couldn't enqueue kernel! %d\n", err);
400 return FALSE;
401#endif /* USE_NEW_IMPL_CL */
402}
403#endif
404
405
407{
408 const dt_iop_roi_t *const roi_in = &piece->roi_in;
410 const int P = ceilf(d->radius * fmin(roi_in->scale, 2.0f)); // pixel filter size
411 const int K = ceilf(7 * fmin(roi_in->scale, 2.0f)); // nbhood
412
413 tiling->factor = 2.0f + 1.0f + 0.25 * NUM_BUCKETS; // in + out + tmp
414 tiling->maxbuf = 1.0f;
415 tiling->overhead = 0;
416 tiling->overlap = P + K;
417 tiling->xalign = 1;
418 tiling->yalign = 1;
419 return;
420}
421
422static inline __attribute__((always_inline)) int process_cpu(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece,
423 const void *const ivoid,
424 void *const ovoid, const dt_iop_roi_t *const roi_in,
425 const dt_iop_roi_t *const roi_out,
426 int (*denoiser)(const float *const inbuf, float *const outbuf,
427 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
428 const dt_nlmeans_param_t *const params))
429{
430 // this is called for preview and full pipe separately, each with its own pixelpipe piece.
431 // get our data struct:
433
434 // adjust to zoom size:
435 const float scale = fmin(roi_in->scale, 2.0f);
436 const int P = ceilf(d->radius * scale); // pixel filter size
437 const int K = ceilf(7 * scale); // nbhood
438 const float sharpness = 3000.0f / (1.0f + d->strength);
439
440 // adjust to Lab, make L more important
441 float max_L = 120.0f, max_C = 512.0f;
442 float nL = 1.0f / max_L, nC = 1.0f / max_C;
443 const dt_aligned_pixel_t norm2 = { nL * nL, nC * nC, nC * nC, 1.0f };
444
445 // faster but less accurate processing by skipping half the patches on previews and thumbnails
446 const int decimate = (pipe->type == DT_DEV_PIXELPIPE_THUMBNAIL
447 || dt_dev_pixelpipe_has_preview_output(piece->module->dev, pipe, roi_out));
448
449 const dt_nlmeans_param_t params = { .scattering = 0,
450 .scale = scale,
451 .luma = d->luma,
452 .chroma = d->chroma,
453 .center_weight = -1,
454 .sharpness = sharpness,
455 .patch_radius = P,
456 .search_radius = K,
457 .decimate = decimate,
458 .norm = norm2,
459 .pipe = pipe };
460 if(denoiser(ivoid,ovoid,roi_in,roi_out,&params)) return 1;
462 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
463 return 0;
464}
465
466int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
467 void *const ovoid)
468{
469 const dt_iop_roi_t *const roi_in = &piece->roi_in;
470 const dt_iop_roi_t *const roi_out = &piece->roi_out;
471 return process_cpu(pipe, piece, ivoid, ovoid, roi_in, roi_out, nlmeans_denoise);
472}
473
475{
476 const int program = 5; // nlmeans.cl, from programs.conf
479 module->data = gd;
480 gd->kernel_nlmeans_init = dt_opencl_create_kernel(program, "nlmeans_init");
481 gd->kernel_nlmeans_dist = dt_opencl_create_kernel(program, "nlmeans_dist");
482 gd->kernel_nlmeans_horiz = dt_opencl_create_kernel(program, "nlmeans_horiz");
483 gd->kernel_nlmeans_vert = dt_opencl_create_kernel(program, "nlmeans_vert");
484 gd->kernel_nlmeans_accu = dt_opencl_create_kernel(program, "nlmeans_accu");
485 gd->kernel_nlmeans_finish = dt_opencl_create_kernel(program, "nlmeans_finish");
486}
487
499
503{
506 memcpy(d, p, sizeof(*d));
507 d->luma = MAX(0.0001f, p->luma);
508 d->chroma = MAX(0.0001f, p->chroma);
509}
510
516
518{
519 dt_free_align(piece->data);
520 piece->data = NULL;
521}
522
524{
526
527 g->radius = dt_bauhaus_slider_from_params(self, "radius");
528 dt_bauhaus_slider_set_soft_max(g->radius, 4.0f);
530 gtk_widget_set_tooltip_text(g->radius, _("radius of the patches to match"));
531 g->strength = dt_bauhaus_slider_from_params(self, N_("strength"));
532 dt_bauhaus_slider_set_soft_max(g->strength, 100.0f);
533 dt_bauhaus_slider_set_digits(g->strength, 0);
534 dt_bauhaus_slider_set_format(g->strength, "%");
535 gtk_widget_set_tooltip_text(g->strength, _("strength of the effect"));
536 g->luma = dt_bauhaus_slider_from_params(self, N_("luma"));
538 gtk_widget_set_tooltip_text(g->luma, _("how much to smooth brightness"));
539 g->chroma = dt_bauhaus_slider_from_params(self, N_("chroma"));
540 dt_bauhaus_slider_set_format(g->chroma, "%");
541 gtk_widget_set_tooltip_text(g->chroma, _("how much to smooth colors"));
542}
543
544// clang-format off
545// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
546// vim: shiftwidth=2 expandtab tabstop=2 cindent
547// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
548// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3346
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
Definition bauhaus.c:1474
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3410
@ IOP_CS_LAB
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const float max
#define P(V, params)
void dt_iop_params_t
Definition dev_history.h:43
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:405
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:29
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:1909
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_GROUP_REPAIR
Definition imageop.h:159
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
Definition layers.h:50
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
@ DT_DEBUG_OPENCL
Definition logging.h:57
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define o
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
static int bucket_next(unsigned int *state, unsigned int max)
Definition nlmeans.c:163
#define NUM_BUCKETS
Definition nlmeans.c:70
const char ** description(struct dt_iop_module_t *self)
Definition nlmeans.c:122
int default_group()
Definition nlmeans.c:152
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition nlmeans.c:501
const char * aliases()
Definition nlmeans.c:117
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition nlmeans.c:511
const char * name()
Definition nlmeans.c:112
void gui_init(dt_iop_module_t *self)
Definition nlmeans.c:523
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition nlmeans.c:406
void cleanup_global(dt_iop_module_so_t *module)
Definition nlmeans.c:488
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition nlmeans.c:131
int flags()
Definition nlmeans.c:157
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition nlmeans.c:466
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition nlmeans.c:517
void init_global(dt_iop_module_so_t *module)
Definition nlmeans.c:474
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition nlmeans.c:173
dt_iop_nlmeans_params_t dt_iop_nlmeans_data_t
Definition nlmeans.c:99
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition nlmeans.c:136
__DT_CLONE_TARGETS__ int nlmeans_denoise(const float *const inbuf, float *const outbuf, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_nlmeans_param_t *const params)
int nlmeans_denoise_cl(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3786
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2612
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:3028
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2506
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2549
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2603
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1712
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
Definition opencl.c:2618
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2863
#define ROUNDUP(a, n)
Definition opencl.h:82
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
@ DT_DEV_PIXELPIPE_THUMBNAIL
Definition pixelpipe.h:45
static gboolean dt_dev_pixelpipe_has_shutdown(const dt_dev_pixelpipe_t *pipe)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
const float uint32_t state[4]
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
dt_iop_global_data_t * data
Definition imageop.h:238
dt_iop_global_data_t * global_data
Definition imageop.h:337
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
#define MAX(a, b)
Definition thinplate.c:29