Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 174 additions & 110 deletions src/iop/diffuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,39 @@ typedef struct dt_iop_diffuse_params_t
// global parameters
int iterations; // $MIN: 0 $MAX: 500 $DEFAULT: 1 $DESCRIPTION: "iterations"
float sharpness; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "sharpness"
int radius; // $MIN: 0 $MAX: 2048 $DEFAULT: 8 $DESCRIPTION: "radius span"
float regularization; // $MIN: 0. $MAX: 4. $DEFAULT: 0. $DESCRIPTION: "edge sensitivity"
float variance_threshold; // $MIN: -2. $MAX: 2. $DEFAULT: 0. $DESCRIPTION: "edge threshold"

float anisotropy_first; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "1st order anisotropy"
float anisotropy_second; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "2nd order anisotropy"
float anisotropy_third; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "3rd order anisotropy"
float anisotropy_fourth; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "4th order anisotropy"

float threshold; // $MIN: 0. $MAX: 8. $DEFAULT: 0. $DESCRIPTION: "luminance masking threshold"

float first; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "1st order speed"
float second; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "2nd order speed"
float third; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "3rd order speed"
float fourth; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "4th order speed"
int radius; // $MIN: 0 $MAX: 2048 $DEFAULT: 8 $DESCRIPTION: "effect radius"
float regularization; // $MIN: 0. $MAX: 4. $DEFAULT: 0. $DESCRIPTION: "edge protection"
float variance_threshold; // $MIN: -2. $MAX: 2. $DEFAULT: 0. $DESCRIPTION: "surface protection"
// add the proper unicode character for the double ended arrows in the description
float anisotropy_first; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "edge avoidance"
float anisotropy_second; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "edge avoidance (coarse)"
float anisotropy_third; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "edge avoidance"
float anisotropy_fourth; // $MIN: -10. $MAX: 10. $DEFAULT: 0. $DESCRIPTION: "edge avoidance (fine)"

float threshold; // $MIN: 0. $MAX: 8. $DEFAULT: 0. $DESCRIPTION: "luminance threshold"

// replace the makeshift double ended arrows with the proper unicode character
float first; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "sharpen ↔ diffuse"
float second; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "sharpen ↔ diffuse (coarse)"
float third; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "sharpen ↔ diffuse"
float fourth; // $MIN: -1. $MAX: 1. $DEFAULT: 0. $DESCRIPTION: "sharpen ↔ diffuse (fine)"

// v2
int radius_center; // $MIN: 0 $MAX: 1024 $DEFAULT: 0 $DESCRIPTION: "central radius"
int radius_center; // $MIN: 0 $MAX: 1024 $DEFAULT: 0 $DESCRIPTION: "effect scale"

// new versions add params mandatorily at the end, so we can memcpy old parameters at the beginning

} dt_iop_diffuse_params_t;


typedef struct dt_iop_diffuse_gui_data_t
{
GtkWidget *iterations, *fourth, *third, *second, *radius, *radius_center, *sharpness, *threshold, *regularization, *first,
*anisotropy_first, *anisotropy_second, *anisotropy_third, *anisotropy_fourth, *regularization_first, *variance_threshold;
GtkWidget *iterations, *third, *first, *radius, *radius_center, *threshold,
*anisotropy_first, *anisotropy_third, *regularization_first;
GtkWidget *secondary_sharpen_diffuse_box;
GtkWidget *effect_corrections_box;
dt_gui_collapsible_section_t secondary_sharpen_diffuse_section;
dt_gui_collapsible_section_t effect_corrections_section;
dt_gui_collapsible_section_t highlight_inpainting_section;
} dt_iop_diffuse_gui_data_t;

typedef struct dt_iop_diffuse_global_data_t
Expand Down Expand Up @@ -1755,15 +1760,148 @@ void cleanup_global(dt_iop_module_so_t *self)
}
#endif

static void _add_secondary_sharpen_diffuse_sliders(dt_iop_module_t *section)
{
// Reuse the slider variable for all sliders
GtkWidget *slider = NULL;

slider = dt_bauhaus_slider_from_params(section, "second");
dt_bauhaus_slider_set_digits(slider, 4);
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider, _("diffusion speed of low-frequency wavelet layers\n"
"in the direction of 2nd order anisotropy (set below).\n\n"
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));

slider = dt_bauhaus_slider_from_params(section, "anisotropy_second");
dt_bauhaus_slider_set_digits(slider, 4);
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider,_("direction of 2nd order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

slider = dt_bauhaus_slider_from_params(section, "fourth");
dt_bauhaus_slider_set_digits(slider, 4);
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider, _("diffusion speed of high-frequency wavelet layers\n"
"in the direction of 4th order anisotropy (set below).\n\n"
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));

slider = dt_bauhaus_slider_from_params(section, "anisotropy_fourth");
dt_bauhaus_slider_set_digits(slider, 4);
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider,_("direction of 4th order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));
}

static void _add_secondary_sharpen_diffuse_box(dt_iop_module_t *self,
dt_iop_diffuse_gui_data_t *g)
{
GtkWidget *secondary_sharpen_diffuse_box = dt_gui_vbox();

gchar *section_name = NC_("section", "auxiliary sharpen/diffuse");
dt_gui_new_collapsible_section(&g->secondary_sharpen_diffuse_section,
"plugins/darkroom/diffuse/expand_secondary_sharpen_diffuse_params", Q_(section_name),
GTK_BOX(secondary_sharpen_diffuse_box), DT_ACTION(self));
_add_secondary_sharpen_diffuse_sliders(DT_IOP_SECTION_FOR_PARAMS(self, section_name, g->secondary_sharpen_diffuse_section.container));

dt_gui_box_add(self->widget, secondary_sharpen_diffuse_box);
}

static void _add_effect_corrections_sliders(dt_iop_module_t *section)
{
// Reuse the slider variable for all sliders
GtkWidget *slider = NULL;

slider = dt_bauhaus_slider_from_params(section, "sharpness");
dt_bauhaus_slider_set_digits(slider, 3);
dt_bauhaus_slider_set_soft_range(slider, -0.25, 0.25);
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider,
_("increase or decrease the sharpness of the highest frequencies.\n"
"can be used to keep details after blooming,\n"
"for standalone sharpening set speed to negative values."));

slider = dt_bauhaus_slider_from_params(section, "regularization");
gtk_widget_set_tooltip_text
(slider,
_("define the sensitivity of the variance penalty for edges.\n"
"increase to exclude more edges from diffusion,\n"
"if fringes or halos appear."));

slider = dt_bauhaus_slider_from_params(section, "variance_threshold");
dt_bauhaus_slider_set_soft_range(slider, -0.5, 0.5);
gtk_widget_set_tooltip_text
(slider,
_("define the variance threshold between edge amplification and penalty.\n"
"decrease if you want pixels on smooth surfaces get a boost,\n"
"increase if you see noise appear on smooth surfaces or\n"
"if dark areas seem oversharpened compared to bright areas."));
}

static void _add_effect_corrections_box(dt_iop_module_t *self,
dt_iop_diffuse_gui_data_t *g)
{
GtkWidget *effect_corrections_box = dt_gui_vbox();

gchar *section_name = NC_("section", "fine-tuning");
dt_gui_new_collapsible_section(&g->effect_corrections_section,
"plugins/darkroom/diffuse/expand_effect_corrections_params", Q_(section_name),
GTK_BOX(effect_corrections_box), DT_ACTION(self));
_add_effect_corrections_sliders(DT_IOP_SECTION_FOR_PARAMS(self, section_name, g->effect_corrections_section.container));

dt_gui_box_add(self->widget, effect_corrections_box);
}

static void _add_highlight_inpainting_sliders(dt_iop_module_t *section)
{
// Reuse the slider variable for all sliders
GtkWidget *slider = NULL;

slider = dt_bauhaus_slider_from_params(section, "threshold");
dt_bauhaus_slider_set_format(slider, "%");
gtk_widget_set_tooltip_text
(slider,
_("luminance threshold for the mask.\n"
"0. disables the luminance masking and applies the module on the whole image.\n"
"any higher value excludes pixels with luminance lower than the threshold.\n"
"this can be used to inpaint highlights."));
}

static void _add_highlight_inpainting_box(dt_iop_module_t *self,
dt_iop_diffuse_gui_data_t *g)
{
GtkWidget *highlight_inpainting_box = dt_gui_vbox();

gchar *section_name = NC_("section", "highlight inpainting");
dt_gui_new_collapsible_section(&g->highlight_inpainting_section,
"plugins/darkroom/diffuse/expand_highlight_inpainting_params", Q_(section_name),
GTK_BOX(highlight_inpainting_box), DT_ACTION(self));
_add_highlight_inpainting_sliders(DT_IOP_SECTION_FOR_PARAMS(self, section_name, g->highlight_inpainting_section.container));

dt_gui_box_add(self->widget, highlight_inpainting_box);
}


void gui_init(dt_iop_module_t *self)
{
dt_iop_diffuse_gui_data_t *g = IOP_GUI_ALLOC(diffuse);

self->widget = dt_gui_vbox(dt_ui_section_label_new(C_("section", "properties")));
// self->widget = dt_gui_vbox(dt_ui_section_label_new(C_("section", "properties")));

g->iterations = dt_bauhaus_slider_from_params(self, "iterations");
dt_bauhaus_slider_set_soft_range(g->iterations, 1., 128);
dt_bauhaus_slider_set_soft_range(g->iterations, 1., 16.);
gtk_widget_set_tooltip_text
(g->iterations,
_("more iterations make the effect stronger but the module slower.\n"
Expand All @@ -1772,7 +1910,7 @@ void gui_init(dt_iop_module_t *self)
"more iterations help reconstruction."));

g->radius_center = dt_bauhaus_slider_from_params(self, "radius_center");
dt_bauhaus_slider_set_soft_range(g->radius_center, 0., 512.);
dt_bauhaus_slider_set_soft_range(g->radius_center, 0., 64.);
dt_bauhaus_slider_set_format(g->radius_center, _(" px"));
gtk_widget_set_tooltip_text(
g->radius_center, _("main scale of the diffusion.\n"
Expand All @@ -1782,7 +1920,7 @@ void gui_init(dt_iop_module_t *self)
"increase to act on local contrast instead."));

g->radius = dt_bauhaus_slider_from_params(self, "radius");
dt_bauhaus_slider_set_soft_range(g->radius, 1., 512.);
dt_bauhaus_slider_set_soft_range(g->radius, 1., 64.);
dt_bauhaus_slider_set_format(g->radius, _(" px"));
gtk_widget_set_tooltip_text(
g->radius, _("width of the diffusion around the central radius.\n"
Expand All @@ -1791,7 +1929,7 @@ void gui_init(dt_iop_module_t *self)
"if you plan on deblurring, \n"
"the radius should be around the width of your lens blur."));

dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "speed (sharpen ↔ diffuse)")));
dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "coarse")));

g->first = dt_bauhaus_slider_from_params(self, "first");
dt_bauhaus_slider_set_digits(g->first, 4);
Expand All @@ -1802,16 +1940,16 @@ void gui_init(dt_iop_module_t *self)
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));

g->second = dt_bauhaus_slider_from_params(self, "second");
dt_bauhaus_slider_set_digits(g->second, 4);
dt_bauhaus_slider_set_format(g->second, "%");
g->anisotropy_first = dt_bauhaus_slider_from_params(self, "anisotropy_first");
dt_bauhaus_slider_set_digits(g->anisotropy_first, 4);
dt_bauhaus_slider_set_format(g->anisotropy_first, "%");
gtk_widget_set_tooltip_text
(g->second, _("diffusion speed of low-frequency wavelet layers\n"
"in the direction of 2nd order anisotropy (set below).\n\n"
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));
(g->anisotropy_first, _("direction of 1st order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "fine")));

g->third = dt_bauhaus_slider_from_params(self, "third");
dt_bauhaus_slider_set_digits(g->third, 4);
Expand All @@ -1822,37 +1960,6 @@ void gui_init(dt_iop_module_t *self)
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));

g->fourth = dt_bauhaus_slider_from_params(self, "fourth");
dt_bauhaus_slider_set_digits(g->fourth, 4);
dt_bauhaus_slider_set_format(g->fourth, "%");
gtk_widget_set_tooltip_text
(g->fourth, _("diffusion speed of high-frequency wavelet layers\n"
"in the direction of 4th order anisotropy (set below).\n\n"
"negative values sharpen, \n"
"positive values diffuse and blur, \n"
"zero does nothing."));

dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "direction")));

g->anisotropy_first = dt_bauhaus_slider_from_params(self, "anisotropy_first");
dt_bauhaus_slider_set_digits(g->anisotropy_first, 4);
dt_bauhaus_slider_set_format(g->anisotropy_first, "%");
gtk_widget_set_tooltip_text
(g->anisotropy_first, _("direction of 1st order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

g->anisotropy_second = dt_bauhaus_slider_from_params(self, "anisotropy_second");
dt_bauhaus_slider_set_digits(g->anisotropy_second, 4);
dt_bauhaus_slider_set_format(g->anisotropy_second, "%");
gtk_widget_set_tooltip_text
(g->anisotropy_second,_("direction of 2nd order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

g->anisotropy_third = dt_bauhaus_slider_from_params(self, "anisotropy_third");
dt_bauhaus_slider_set_digits(g->anisotropy_third, 4);
dt_bauhaus_slider_set_format(g->anisotropy_third, "%");
Expand All @@ -1862,52 +1969,9 @@ void gui_init(dt_iop_module_t *self)
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

g->anisotropy_fourth = dt_bauhaus_slider_from_params(self, "anisotropy_fourth");
dt_bauhaus_slider_set_digits(g->anisotropy_fourth, 4);
dt_bauhaus_slider_set_format(g->anisotropy_fourth, "%");
gtk_widget_set_tooltip_text
(g->anisotropy_fourth,_("direction of 4th order speed (set above).\n\n"
"negative values follow gradients more closely, \n"
"positive values rather avoid edges (isophotes), \n"
"zero affects both equally (isotropic)."));

dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "edge management")));

g->sharpness = dt_bauhaus_slider_from_params(self, "sharpness");
dt_bauhaus_slider_set_digits(g->sharpness, 3);
dt_bauhaus_slider_set_soft_range(g->sharpness, -0.25, 0.25);
dt_bauhaus_slider_set_format(g->sharpness, "%");
gtk_widget_set_tooltip_text
(g->sharpness,
_("increase or decrease the sharpness of the highest frequencies.\n"
"can be used to keep details after blooming,\n"
"for standalone sharpening set speed to negative values."));

g->regularization = dt_bauhaus_slider_from_params(self, "regularization");
gtk_widget_set_tooltip_text
(g->regularization,
_("define the sensitivity of the variance penalty for edges.\n"
"increase to exclude more edges from diffusion,\n"
"if fringes or halos appear."));

g->variance_threshold = dt_bauhaus_slider_from_params(self, "variance_threshold");
gtk_widget_set_tooltip_text
(g->variance_threshold,
_("define the variance threshold between edge amplification and penalty.\n"
"decrease if you want pixels on smooth surfaces get a boost,\n"
"increase if you see noise appear on smooth surfaces or\n"
"if dark areas seem oversharpened compared to bright areas."));

dt_gui_box_add(self->widget, dt_ui_section_label_new(C_("section", "diffusion spatiality")));

g->threshold = dt_bauhaus_slider_from_params(self, "threshold");
dt_bauhaus_slider_set_format(g->threshold, "%");
gtk_widget_set_tooltip_text
(g->threshold,
_("luminance threshold for the mask.\n"
"0. disables the luminance masking and applies the module on the whole image.\n"
"any higher value excludes pixels with luminance lower than the threshold.\n"
"this can be used to inpaint highlights."));
_add_effect_corrections_box(self, g);
_add_secondary_sharpen_diffuse_box(self, g);
_add_highlight_inpainting_box(self, g);
}

// clang-format off
Expand Down
Loading