97 return _(
"chromatic aberrations");
104 _(
"linear or non-linear, Lab, display-referred"),
105 _(
"non-linear, Lab"),
106 _(
"non-linear, Lab, display-referred"));
122 return _(
"this module is deprecated. please use the chromatic aberration module instead.");
156static const float fib[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 };
159static inline void fib_latt(
int *
const x,
int *
const y,
float radius,
int step,
int idx)
162 if(idx >=
sizeof(
fib) /
sizeof(
float) - 1 || idx < 1)
166 fprintf(stderr,
"Fibonacci lattice index wrong/out of bounds in: defringe module\n");
169 float px = step /
fib[idx], py = step * (
fib[idx + 1] /
fib[idx]);
171 float dx = px * radius, dy = py * radius;
172 *
x = round(dx - radius / 2.0);
173 *y = round(dy - radius / 2.0);
176#define MAGIC_THRESHOLD_COEFF 33.0
215 const float sigma = fmax(0.1f, fabs(
d->radius)) * roi_in->
scale;
216 const float Labmax[] = { 100.0f, 128.0f, 128.0f, 1.0f };
217 const float Labmin[] = { 0.0f, -128.0f, -128.0f, 0.0f };
219 const int radius = ceil(2.0 * ceilf(
sigma));
223 int *xy_small = NULL;
225 if(roi_out->
width < 2 * radius + 1 || roi_out->
height < 2 * radius + 1)
goto ERROR_EXIT;
227 float avg_edge_chroma = 0.0;
229 const float *
const restrict in = (
float *
const)
i;
230 float *
const restrict
out = (
float *
const)o;
238 fprintf(stderr,
"Error allocating memory for gaussian blur in: defringe module\n");
245 const int samples_wish = radius * radius;
248 if(samples_wish > 89)
252 else if(samples_wish > 55)
256 else if(samples_wish > 34)
260 else if(samples_wish > 21)
264 else if(samples_wish > 13)
272 const int sampleidx_small = sampleidx_avg - 1;
274 const int small_radius =
MAX(radius, 3);
275 const int avg_radius = 24 + radius * 4;
277 const int samples_small =
fib[sampleidx_small];
278 const int samples_avg =
fib[sampleidx_avg];
282 xy_avg = malloc(
sizeof(
int) * 2 * samples_avg);
283 xy_small = malloc(
sizeof(
int) * 2 * samples_small);
286 fprintf(stderr,
"Error allocating memory for fibonacci lattice in: defringe module\n");
292 for(
int u = 0; u < samples_avg; u++)
295 fib_latt(&dx, &dy, avg_radius, u, sampleidx_avg);
299 for(
int u = 0; u < samples_small; u++)
302 fib_latt(&dx, &dy, small_radius, u, sampleidx_small);
304 xy_small[2*u+1] = dy;
309 for(
size_t j = 0; j < (size_t)
height *
width * 4; j += 4)
313 const float a = in[j + 1] -
out[j + 1];
314 const float b = in[j + 2] -
out[j + 2];
315 const float edge = (a * a + b * b);
320 avg_edge_chroma += edge * use_global_average;
324 if(use_global_average)
326 avg_edge_chroma = avg_edge_chroma / (
width *
height) + 10.0 * FLT_EPSILON;
333 thresh = fmax(0.1f,
d->thresh);
339#pragma omp parallel for default(firstprivate) \
344 const size_t row_above = (size_t)
MAX(0, (
v-1)) *
width *
ch;
345 const size_t curr_row = (size_t)
v *
width *
ch;
349 const size_t index =
ch * ((size_t)
v *
width +
t);
350 float local_thresh = thresh;
354 float local_avg = 0.0;
356 for(
int u = 0; u < samples_avg; u++)
358 const int dx = xy_avg[2*u];
359 const int dy = xy_avg[2*u+1];
360 const int x = CLAMP(
t + dx, 0,
width - 1);
361 const int y = CLAMP(
v + dy, 0,
height - 1);
362 local_avg +=
out[((size_t)y *
width +
x) *
ch + 3];
364 avg_edge_chroma = fmax(0.01f, (
float)local_avg / samples_avg);
368 if(
out[index + 3] > local_thresh
370 ||
out[row_above +
MAX(0, (
t - 1)) *
ch + 3] > local_thresh
371 ||
out[row_above +
t *
ch + 3] > local_thresh
372 ||
out[row_above +
MIN(
width - 1, (
t + 1)) *
ch + 3] > local_thresh
373 ||
out[curr_row +
MAX(0, (
t - 1)) *
ch + 3] > local_thresh
374 ||
out[curr_row +
MIN(
width - 1, (
t + 1)) *
ch + 3] > local_thresh
375 ||
out[row_below +
MAX(0, (
t - 1)) *
ch + 3] > local_thresh
376 ||
out[row_below +
t *
ch + 3] > local_thresh
377 ||
out[row_below +
MIN(
width - 1, (
t + 1)) *
ch + 3] > local_thresh)
379 float atot = 0, btot = 0;
389 for(
int u = 0; u < samples_small; u++)
391 const int dx = xy_small[2*u];
392 const int dy = xy_small[2*u+1];
393 const int x = CLAMP(
t + dx, 0,
width - 1);
394 const int y = CLAMP(
v + dy, 0,
height - 1);
395 const size_t idx =
ch * ((size_t)y *
width +
x);
398 weight = 1.0 / (
out[idx + 3] + avg_edge_chroma);
399 atot +=
weight * in[idx + 1];
400 btot +=
weight * in[idx + 2];
408 double a = (atot / norm);
409 double b = (btot / norm);
410 out[index] = in[index];
418 for(
int c = 0; c < 3; c++)
420 out[index+c] = in[index+c];
427 dt_iop_alpha_copy(
i, o, roi_out->
width, roi_out->
height);
445 gtk_widget_set_tooltip_text(
g->mode_select,
446 _(
"method for color protection:\n - global average: fast, might show slightly wrong previews in high "
447 "magnification; might sometimes protect saturation too much or too low in comparison to local "
448 "average\n - local average: slower, might protect saturation better than global average by using "
449 "near pixels as color reference, so it can still allow for more desaturation where required\n - "
450 "static: fast, only uses the threshold as a static limit"));
453 gtk_widget_set_tooltip_text(
g->radius_scale, _(
"radius for detecting fringe"));
456 gtk_widget_set_tooltip_text(
g->thresh_scale, _(
"threshold for defringe, higher values mean less defringing"));
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define __OMP_SIMD__(...)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR_SIMD__(...)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
const char ** description(struct dt_iop_module_t *self)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *module, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
static void fib_latt(int *const x, int *const y, float radius, int step, int idx)
void gui_update(dt_iop_module_t *module)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
dt_iop_defringe_params_t dt_iop_defringe_data_t
void gui_init(dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
const char * deprecated_msg()
#define MAGIC_THRESHOLD_COEFF
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
void dt_gaussian_free(dt_gaussian_t *g)
void dt_gaussian_blur_4c(dt_gaussian_t *g, const float *const in, float *const out)
dt_gaussian_t * dt_gaussian_init(const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
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)
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)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
float *const restrict const size_t const size_t ch
struct _GtkWidget GtkWidget
struct dt_iop_module_t *void * data
dt_iop_defringe_mode_t op_mode
dt_iop_gui_data_t * gui_data
Region of interest passed through the pixelpipe.