105 return C_(
"modulename",
"sharpen");
125 return dt_iop_set_description(self, _(
"sharpen the details in the image using a standard UnSharp Mask (USM)"),
127 _(
"linear or non-linear, Lab, display or scene-referred"),
128 _(
"frequential, Lab"),
129 _(
"quasi-linear, Lab, display or scene-referred"));
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;
163 cl_mem dev_tmp = NULL;
166 const int devid = pipe->
devid;
170 const int wd = 2 * rad + 1;
175 size_t origin[] = { 0, 0, 0 };
178 if(err != CL_SUCCESS)
goto error;
186 size_t origin[] = { 0, 0, 0 };
189 if(err != CL_SUCCESS)
goto error;
193 const float sigma2 = (1.0f / (2.5 * 2.5)) * (
d->radius * roi_in->
scale)
194 * (
d->radius * roi_in->
scale);
201 .cellsize =
sizeof(float), .overhead = 0,
202 .sizex = 1 << 16, .sizey = 1 };
205 hblocksize = hlocopt.
sizex;
212 .cellsize =
sizeof(float), .overhead = 0,
213 .sizex = 1, .sizey = 1 << 16 };
216 vblocksize = vlocopt.
sizey;
237 local[0] = hblocksize;
249 if(err != CL_SUCCESS)
goto error;
256 local[1] = vblocksize;
267 if(err != CL_SUCCESS)
goto error;
281 if(err != CL_SUCCESS)
goto error;
325 (roi_out->
width < 2 * rad + 1 || roi_out->
height < 2 * rad + 1))
341 const int wd = 2 * rad + 1;
342 const int wd4 = (wd & 3) ? (wd >> 2) + 1 : wd >> 2;
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)
355 const float *
const restrict in = (
float*)ivoid;
358 for(
int j = 0; j < roi_out->
height; j++)
362 if (j < rad || j >= roi_out->
height - rad)
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);
373 const size_t start_row = j-rad;
374 const size_t end_row = j+rad;
379 for(
int k = start_row;
k <= end_row;
k++)
381 const int k_adj =
k - (j-rad);
383 sum[c] += mat[k_adj] * in[4*(
k*
width+
i+c)];
385 float *
const vblurred = temp_buf +
i;
387 vblurred[c] = sum[c];
393 for(
int k = start_row;
k <= end_row;
k++)
395 const int k_adj =
k - (j-rad);
396 sum += mat[k_adj] * in[4*(
k*
width+
i)];
403 float *
const restrict row_out = ((
float*)
ovoid) + (size_t)4 * j *
width;
404 for(
int i = 0;
i < rad;
i++)
407 const float amount = data->
amount;
408 for(
int i = rad;
i < roi_out->
width - rad;
i++)
411 for(
int k =
i-rad;
k <=
i+rad;
k++)
413 const int k_adj =
k - (
i-rad);
414 sum += mat[k_adj] * temp_buf[
k];
417 const size_t index = 4 * (j *
width +
i);
418 const float diff = in[index] - sum;
419 const float absdiff = fabs(diff);
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];
444 d->radius = 2.5f *
p->radius;
445 d->amount =
p->amount;
446 d->threshold =
p->threshold;
463 const int program = 7;
489 gtk_widget_set_tooltip_text(
g->radius, _(
"spatial extent of the unblurring"));
493 gtk_widget_set_tooltip_text(
g->amount, _(
"strength of the sharpen"));
497 gtk_widget_set_tooltip_text(
g->threshold, _(
"threshold to activate sharpen"));
static void error(char *msg)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
@ DEVELOP_BLEND_CS_RGB_DISPLAY
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
static void copy_pixel(float *const __restrict__ out, const float *const __restrict__ in)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define dt_pixelpipe_cache_free_align(mem)
#define __DT_CLONE_TARGETS__
#define dt_get_perthread(buf, padsize)
#define for_four_channels(_var,...)
#define __OMP_PARALLEL_FOR__(...)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
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)
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,...)
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)
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)
#define DT_IMGSZ_PERTHREAD
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)
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
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)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
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)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
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)
const char ** description(struct dt_iop_module_t *self)
__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)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void gui_init(struct dt_iop_module_t *self)
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)
void cleanup_global(dt_iop_module_so_t *module)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void init_presets(dt_iop_module_so_t *self)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void init_global(dt_iop_module_so_t *module)
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)
static __DT_CLONE_TARGETS__ float *const init_gaussian_kernel(const int rad, const size_t mat_size, const float sigma2)
struct _GtkWidget GtkWidget
struct dt_iop_module_t *void * data
GModule *dt_dev_operation_t op
dt_iop_global_data_t * data
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.