diff --git a/src/iop/diffuse.c b/src/iop/diffuse.c index 27885e7b966a..8b91974ac996 100644 --- a/src/iop/diffuse.c +++ b/src/iop/diffuse.c @@ -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 @@ -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" @@ -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" @@ -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" @@ -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); @@ -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); @@ -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, "%"); @@ -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