Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
sharpen.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2013, 2016 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2011 Henrik Andersson.
6 Copyright (C) 2010 jan rinze.
7 Copyright (C) 2010-2011 Pascal de Bruijn.
8 Copyright (C) 2011 Antony Dovgal.
9 Copyright (C) 2011 Jérémy Rosen.
10 Copyright (C) 2011 Kanstantsin Shautsou.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011 Robert Bieber.
13 Copyright (C) 2011 Rostyslav Pidgornyi.
14 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
15 Copyright (C) 2011-2012, 2014, 2016-2017 Ulrich Pegelow.
16 Copyright (C) 2012 Richard Wonka.
17 Copyright (C) 2013 Simon Spannagel.
18 Copyright (C) 2014, 2018, 2020, 2022 Pascal Obry.
19 Copyright (C) 2014-2016 Roman Lebedev.
20 Copyright (C) 2015 Edouard Gomez.
21 Copyright (C) 2015 Pedro Côrte-Real.
22 Copyright (C) 2017 Heiko Bauke.
23 Copyright (C) 2018-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
24 Copyright (C) 2018 Edgardo Hoszowski.
25 Copyright (C) 2018 Maurizio Paglia.
26 Copyright (C) 2018 rawfiner.
27 Copyright (C) 2019 Andreas Schneider.
28 Copyright (C) 2020 Aldric Renaudin.
29 Copyright (C) 2020, 2022 Diederik Ter Rahe.
30 Copyright (C) 2020 Hubert Kowalski.
31 Copyright (C) 2020-2021 Ralf Brown.
32 Copyright (C) 2022 Hanno Schwalm.
33 Copyright (C) 2022 Martin Bařinka.
34 Copyright (C) 2022 Philipp Lutz.
35
36 darktable is free software: you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation, either version 3 of the License, or
39 (at your option) any later version.
40
41 darktable is distributed in the hope that it will be useful,
42 but WITHOUT ANY WARRANTY; without even the implied warranty of
43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 GNU General Public License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with darktable. If not, see <http://www.gnu.org/licenses/>.
48*/
49#ifdef HAVE_CONFIG_H
50#include "common/darktable.h"
51#include "config.h"
52#endif
53#include "bauhaus/bauhaus.h"
54#include "common/imagebuf.h"
55#include "common/opencl.h"
56#include "control/control.h"
57#include "develop/develop.h"
58#include "develop/imageop.h"
60#include "develop/imageop_gui.h"
61#include "develop/tiling.h"
62
63#include "gui/gtk.h"
64#include "gui/presets.h"
65#include "iop/iop_api.h"
66#include <assert.h>
67#include <math.h>
68#include <stdlib.h>
69#include <string.h>
70
71#include <gtk/gtk.h>
72#include <inttypes.h>
73
75
76#define MAXR 12
77
79{
80 float radius; // $MIN: 0.0 $MAX: 99.0 $DEFAULT: 2.0
81 float amount; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 0.5
82 float threshold; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 0.5
84
89
94
101
102
103const char *name()
104{
105 return C_("modulename", "sharpen");
106}
107
109{
110 return IOP_GROUP_SHARPNESS;
111}
112
117
119{
120 return IOP_CS_LAB;
121}
122
123const char **description(struct dt_iop_module_t *self)
124{
125 return dt_iop_set_description(self, _("sharpen the details in the image using a standard UnSharp Mask (USM)"),
126 _("corrective"),
127 _("linear or non-linear, Lab, display or scene-referred"),
128 _("frequential, Lab"),
129 _("quasi-linear, Lab, display or scene-referred"));
130}
131
133{
134 dt_iop_sharpen_params_t tmp = (dt_iop_sharpen_params_t){ 2.0, 0.5, 0.5 };
135 // add the preset.
136 dt_gui_presets_add_generic(_("sharpen"), self->op,
137 self->version(), &tmp, sizeof(dt_iop_sharpen_params_t),
139 // restrict to raw images
140 dt_gui_presets_update_ldr(_("sharpen"), self->op,
141 self->version(), FOR_RAW);
142}
143
145static float *const init_gaussian_kernel(const int rad, const size_t mat_size, const float sigma2)
146{
147 float weight = 0.0f;
148 float *const mat = dt_pixelpipe_cache_alloc_align_float_cache(mat_size, 0);
149 if(IS_NULL_PTR(mat)) return NULL;
150 memset(mat, 0, sizeof(float) * mat_size);
151 for(int l = -rad; l <= rad; l++) weight += mat[l + rad] = expf(-l * l / (2.f * sigma2));
152 for(int l = -rad; l <= rad; l++) mat[l + rad] /= weight;
153 return mat;
154}
155
156#ifdef HAVE_OPENCL
157int 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)
158{
159 const dt_iop_roi_t *const roi_in = &piece->roi_in;
162 cl_mem dev_m = NULL;
163 cl_mem dev_tmp = NULL;
164 cl_int err = -999;
165
166 const int devid = pipe->devid;
167 const int width = roi_in->width;
168 const int height = roi_in->height;
169 const int rad = MIN(MAXR, ceilf(d->radius * roi_in->scale));
170 const int wd = 2 * rad + 1;
171 float *mat = NULL;
172
173 if(rad == 0)
174 {
175 size_t origin[] = { 0, 0, 0 };
176 size_t region[] = { width, height, 1 };
177 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
178 if(err != CL_SUCCESS) goto error;
179 return TRUE;
180 }
181
182 // special case handling: very small image with one or two dimensions below 2*rad+1 => no sharpening,
183 // normally not needed for OpenCL but implemented here for identity with CPU code path
184 if(width < 2 * rad + 1 || height < 2 * rad + 1)
185 {
186 size_t origin[] = { 0, 0, 0 };
187 size_t region[] = { width, height, 1 };
188 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, region);
189 if(err != CL_SUCCESS) goto error;
190 return TRUE;
191 }
192
193 const float sigma2 = (1.0f / (2.5 * 2.5)) * (d->radius * roi_in->scale)
194 * (d->radius * roi_in->scale);
195 mat = init_gaussian_kernel(rad, wd, sigma2);
196 if(IS_NULL_PTR(mat)) goto error;
197
198 int hblocksize;
200 = (dt_opencl_local_buffer_t){ .xoffset = 2 * rad, .xfactor = 1, .yoffset = 0, .yfactor = 1,
201 .cellsize = sizeof(float), .overhead = 0,
202 .sizex = 1 << 16, .sizey = 1 };
203
204 if(dt_opencl_local_buffer_opt(devid, gd->kernel_sharpen_hblur, &hlocopt))
205 hblocksize = hlocopt.sizex;
206 else
207 hblocksize = 1;
208
209 int vblocksize;
211 = (dt_opencl_local_buffer_t){ .xoffset = 1, .xfactor = 1, .yoffset = 2 * rad, .yfactor = 1,
212 .cellsize = sizeof(float), .overhead = 0,
213 .sizex = 1, .sizey = 1 << 16 };
214
215 if(dt_opencl_local_buffer_opt(devid, gd->kernel_sharpen_vblur, &vlocopt))
216 vblocksize = vlocopt.sizey;
217 else
218 vblocksize = 1;
219
220
221 const size_t bwidth = ROUNDUP(width, hblocksize);
222 const size_t bheight = ROUNDUP(height, vblocksize);
223
224 size_t sizes[3];
225 size_t local[3];
226
227 dev_tmp = dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
228 if(IS_NULL_PTR(dev_tmp)) goto error;
229
230 dev_m = dt_opencl_copy_host_to_device_constant(devid, sizeof(float) * wd, mat);
231 if(IS_NULL_PTR(dev_m)) goto error;
232
233 /* horizontal blur */
234 sizes[0] = bwidth;
235 sizes[1] = ROUNDUPDHT(height, devid);
236 sizes[2] = 1;
237 local[0] = hblocksize;
238 local[1] = 1;
239 local[2] = 1;
240 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 0, sizeof(cl_mem), (void *)&dev_in);
241 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 1, sizeof(cl_mem), (void *)&dev_out);
242 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 2, sizeof(cl_mem), (void *)&dev_m);
243 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 3, sizeof(int), (void *)&rad);
244 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 4, sizeof(int), (void *)&width);
245 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 5, sizeof(int), (void *)&height);
246 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 6, sizeof(int), (void *)&hblocksize);
247 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_hblur, 7, (hblocksize + 2 * rad) * sizeof(float), NULL);
248 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_sharpen_hblur, sizes, local);
249 if(err != CL_SUCCESS) goto error;
250
251 /* vertical blur */
252 sizes[0] = ROUNDUPDWD(width, devid);
253 sizes[1] = bheight;
254 sizes[2] = 1;
255 local[0] = 1;
256 local[1] = vblocksize;
257 local[2] = 1;
258 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 0, sizeof(cl_mem), (void *)&dev_out);
259 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 1, sizeof(cl_mem), (void *)&dev_tmp);
260 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 2, sizeof(cl_mem), (void *)&dev_m);
261 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 3, sizeof(int), (void *)&rad);
262 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 4, sizeof(int), (void *)&width);
263 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 5, sizeof(int), (void *)&height);
264 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 6, sizeof(int), (void *)&vblocksize);
265 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_vblur, 7, (vblocksize + 2 * rad) * sizeof(float), NULL);
266 err = dt_opencl_enqueue_kernel_2d_with_local(devid, gd->kernel_sharpen_vblur, sizes, local);
267 if(err != CL_SUCCESS) goto error;
268
269 /* mixing tmp and in -> out */
270 sizes[0] = ROUNDUPDWD(width, devid);
271 sizes[1] = ROUNDUPDHT(height, devid);
272 sizes[2] = 1;
273 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 0, sizeof(cl_mem), (void *)&dev_in);
274 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 1, sizeof(cl_mem), (void *)&dev_tmp);
275 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 2, sizeof(cl_mem), (void *)&dev_out);
276 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 3, sizeof(int), (void *)&width);
277 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 4, sizeof(int), (void *)&height);
278 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 5, sizeof(float), (void *)&d->amount);
279 dt_opencl_set_kernel_arg(devid, gd->kernel_sharpen_mix, 6, sizeof(float), (void *)&d->threshold);
280 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_sharpen_mix, sizes);
281 if(err != CL_SUCCESS) goto error;
282
286 return TRUE;
287
288error:
292 dt_print(DT_DEBUG_OPENCL, "[opencl_sharpen] couldn't enqueue kernel! %d\n", err);
293 return FALSE;
294}
295#endif
296
297
298void 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)
299{
300 const dt_iop_roi_t *const roi_in = &piece->roi_in;
302 const int rad = MIN(MAXR, ceilf(d->radius * roi_in->scale));
303
304 tiling->factor = 2.1f; // in + out + tmprow
305 tiling->factor_cl = 3.0f; // in + out + tmp
306 tiling->maxbuf = 1.0f;
307 tiling->overhead = 0;
308 tiling->overlap = rad;
309 tiling->xalign = 1;
310 tiling->yalign = 1;
311 return;
312}
313
315int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
316 void *const ovoid)
317{
318 const dt_iop_roi_t *const roi_in = &piece->roi_in;
319 const dt_iop_roi_t *const roi_out = &piece->roi_out;
320 const dt_iop_sharpen_data_t *const data = (dt_iop_sharpen_data_t *)piece->data;
321 const int rad = MIN(MAXR, ceilf(data->radius * roi_in->scale));
322 // Special case handling: very small image with one or two dimensions below 2*rad+1 treat as no sharpening and just
323 // pass through. This avoids handling of all kinds of border cases below.
324 if(rad == 0 ||
325 (roi_out->width < 2 * rad + 1 || roi_out->height < 2 * rad + 1))
326 {
327 dt_iop_image_copy_by_size(ovoid, ivoid, roi_out->width, roi_out->height, 4);
328 return 0;
329 }
330
331 float *restrict tmp; // one row per thread
332 size_t padded_size;
333 if (dt_iop_alloc_image_buffers(self, roi_in, roi_out,
334 1 | DT_IMGSZ_WIDTH | DT_IMGSZ_PERTHREAD, &tmp, &padded_size,
335 0))
336 {
337 dt_iop_copy_image_roi(ovoid, ivoid, 4, roi_in, roi_out, TRUE);
338 return 1;
339 }
340
341 const int wd = 2 * rad + 1;
342 const int wd4 = (wd & 3) ? (wd >> 2) + 1 : wd >> 2;
343
344 const size_t mat_size = (size_t)4 * wd4;
345 const float sigma2 = (1.0f / (2.5 * 2.5)) * (data->radius * roi_in->scale)
346 * (data->radius * roi_in->scale);
347 float *const mat = init_gaussian_kernel(rad, mat_size, sigma2);
348 if(IS_NULL_PTR(mat))
349 {
351 dt_iop_copy_image_roi(ovoid, ivoid, 4, roi_in, roi_out, TRUE);
352 return 1;
353 }
354
355 const float *const restrict in = (float*)ivoid;
356 const size_t width = roi_out->width;
358 for(int j = 0; j < roi_out->height; j++)
359 {
360 // We skip the top and bottom 'rad' rows because the kernel would extend beyond the edge of the image, resulting
361 // in an incomplete summation.
362 if (j < rad || j >= roi_out->height - rad)
363 {
364 // fill in the top/bottom border with unchanged luma values from the input image.
365 const float *const restrict row_in = in + (size_t)4 * j * width;
366 float *const restrict row_out = ((float*)ovoid) + (size_t)4 * j * width;
367 memcpy(row_out, row_in, 4 * sizeof(float) * width);
368 continue;
369 }
370 // Get a thread-local temporary buffer for processing the current row of the image.
371 float *const restrict temp_buf = dt_get_perthread(tmp, padded_size);
372 // vertically blur the pixels of the current row into the temp buffer
373 const size_t start_row = j-rad;
374 const size_t end_row = j+rad;
375 // do the bulk of the row four at a time
376 for(int i = 0; i < width; i += 4)
377 {
378 dt_aligned_pixel_t sum = { 0.0f };
379 for(int k = start_row; k <= end_row; k++)
380 {
381 const int k_adj = k - (j-rad);
382 for_four_channels(c,aligned(in))
383 sum[c] += mat[k_adj] * in[4*(k*width+i+c)];
384 }
385 float *const vblurred = temp_buf + i;
386 for_four_channels(c,aligned(vblurred))
387 vblurred[c] = sum[c];
388 }
389 // do the leftover 0-3 pixels of the row
390 for(int i = width & ~3; i < width; i++)
391 {
392 float sum = 0.0f;
393 for(int k = start_row; k <= end_row; k++)
394 {
395 const int k_adj = k - (j-rad);
396 sum += mat[k_adj] * in[4*(k*width+i)];
397 }
398 temp_buf[i] = sum;
399 }
400
401 // now horizontally blur the already vertically-blurred pixels from the temp buffer to the final output buffer
402 // we can skip the left-most and right-most pixels for the same reason as we skipped the top and bottom borders.
403 float *const restrict row_out = ((float*)ovoid) + (size_t)4 * j * width;
404 for(int i = 0; i < rad; i++)
405 copy_pixel(row_out + 4*i, in + 4*(j*width+i)); //copy unsharpened border pixel
406 const float threshold = data->threshold;
407 const float amount = data->amount;
408 for(int i = rad; i < roi_out->width - rad; i++)
409 {
410 float sum = 0.0f;
411 for(int k = i-rad; k <= i+rad; k++)
412 {
413 const int k_adj = k - (i-rad);
414 sum += mat[k_adj] * temp_buf[k];
415 }
416 // subtract the blurred pixel's luma from the original input pixel's luma
417 const size_t index = 4 * (j * width + i);
418 const float diff = in[index] - sum;
419 const float absdiff = fabs(diff);
420 const float detail = (absdiff > threshold) ? copysignf(MAX(absdiff - threshold, 0.0f), diff) : 0.0f;
421 row_out[4*i] = in[index] + detail * amount;
422 row_out[4*i + 1] = in[index + 1];
423 row_out[4*i + 2] = in[index + 2];
424 }
425 for(int i = roi_out->width - rad; i < roi_out->width; i++)
426 copy_pixel(row_out + 4*i, in + 4*(j*width+i)); //copy unsharpened border pixel
427 }
428
431
433 dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height);
434 return 0;
435}
436
439{
442
443 // actually need to increase the mask to fit 2.5 sigma inside
444 d->radius = 2.5f * p->radius;
445 d->amount = p->amount;
446 d->threshold = p->threshold;
447}
448
450{
452 piece->data_size = sizeof(dt_iop_sharpen_data_t);
453}
454
456{
457 dt_free_align(piece->data);
458 piece->data = NULL;
459}
460
462{
463 const int program = 7; // sharpen.cl, from programs.conf
466 if(IS_NULL_PTR(gd)) return;
467 module->data = gd;
468 gd->kernel_sharpen_hblur = dt_opencl_create_kernel(program, "sharpen_hblur");
469 gd->kernel_sharpen_vblur = dt_opencl_create_kernel(program, "sharpen_vblur");
470 gd->kernel_sharpen_mix = dt_opencl_create_kernel(program, "sharpen_mix");
471}
472
481
482void gui_init(struct dt_iop_module_t *self)
483{
485
486 g->radius = dt_bauhaus_slider_from_params(self, N_("radius"));
487 dt_bauhaus_slider_set_soft_max(g->radius, 8.0);
489 gtk_widget_set_tooltip_text(g->radius, _("spatial extent of the unblurring"));
490
491 g->amount = dt_bauhaus_slider_from_params(self, N_("amount"));
493 gtk_widget_set_tooltip_text(g->amount, _("strength of the sharpen"));
494
495 g->threshold = dt_bauhaus_slider_from_params(self, N_("threshold"));
496 dt_bauhaus_slider_set_digits(g->threshold, 3);
497 gtk_widget_set_tooltip_text(g->threshold, _("threshold to activate sharpen"));
498}
499
500#undef MAXR
501
502// clang-format off
503// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
504// vim: shiftwidth=2 expandtab tabstop=2 cindent
505// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
506// 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:3534
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
Definition bauhaus.c:1624
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_LAB
const float threshold
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_OPENCL
Definition darktable.h:722
static void copy_pixel(float *const __restrict__ out, const float *const __restrict__ in)
Definition darktable.h:688
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define dt_get_perthread(buf, padsize)
Definition darktable.h:1035
#define for_four_channels(_var,...)
Definition darktable.h:664
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#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 darktable.h:281
void dt_iop_params_t
Definition dev_history.h:41
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:30
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
@ FOR_RAW
Definition gui/presets.h:41
int dt_iop_alloc_image_buffers(struct dt_iop_module_t *const module, const struct dt_iop_roi_t *const roi_in, const struct dt_iop_roi_t *const roi_out,...)
Definition imagebuf.c:31
void dt_iop_copy_image_roi(float *const __restrict__ out, const float *const __restrict__ in, const size_t ch, const dt_iop_roi_t *const __restrict__ roi_in, const dt_iop_roi_t *const __restrict__ roi_out, const int zero_pad)
Definition imagebuf.c:159
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.h:87
#define DT_IMGSZ_WIDTH
Definition imagebuf.h:63
#define DT_IMGSZ_PERTHREAD
Definition imagebuf.h:57
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:3141
@ IOP_FLAGS_DEPRECATED
Definition imageop.h:168
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:167
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_GROUP_SHARPNESS
Definition imageop.h:141
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
void *const ovoid
float *const restrict const size_t k
float dt_aligned_pixel_t[4]
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
Definition opencl.c:3156
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2471
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
Definition opencl.c:2332
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2261
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
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:2127
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:2142
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define ROUNDUP(a, n)
Definition opencl.h:78
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:437
const char ** description(struct dt_iop_module_t *self)
Definition sharpen.c:123
int default_group()
Definition sharpen.c:108
__DT_CLONE_TARGETS__ 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 sharpen.c:315
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:449
const char * name()
Definition sharpen.c:103
void gui_init(struct dt_iop_module_t *self)
Definition sharpen.c:482
#define MAXR
Definition sharpen.c:76
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 sharpen.c:298
void cleanup_global(dt_iop_module_so_t *module)
Definition sharpen.c:473
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:118
int flags()
Definition sharpen.c:113
void init_presets(dt_iop_module_so_t *self)
Definition sharpen.c:132
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition sharpen.c:455
void init_global(dt_iop_module_so_t *module)
Definition sharpen.c:461
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 sharpen.c:157
static __DT_CLONE_TARGETS__ float *const init_gaussian_kernel(const int rad, const size_t mat_size, const float sigma2)
Definition sharpen.c:145
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_iop_module_t *void * data
GModule *dt_dev_operation_t op
Definition imageop.h:230
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_global_data_t * global_data
Definition imageop.h:314
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
GtkWidget * threshold
Definition sharpen.c:87
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29