71#define DT_IOP_RAWDENOISE_INSET DT_PIXEL_APPLY_DPI(5)
72#define DT_IOP_RAWDENOISE_RES 64
73#define DT_IOP_RAWDENOISE_BANDS 5
122 const int new_version)
124 if(old_version == 1 && new_version == 2)
153 return _(
"raw denoise");
160 _(
"linear, raw, scene-referred"),
162 _(
"linear, raw, scene-referred"));
195 static const float noise_all[] = { 0.8002, 0.2735, 0.1202, 0.0585, 0.0291, 0.0152, 0.0080, 0.0044 };
200 float chan_threshold_exp_4;
213 chan_threshold_exp_4 *= chan_threshold_exp_4;
214 chan_threshold_exp_4 *= chan_threshold_exp_4;
217 all_threshold_exp_4 *= all_threshold_exp_4;
218 all_threshold_exp_4 *= all_threshold_exp_4;
219 noise[
i] = noise_all[
i] * all_threshold_exp_4 * chan_threshold_exp_4 * 16.0f * 16.0f;
230 const size_t size = (size_t)(roi->
width / 2 + 1) * (roi->
height / 2 + 1);
236 for(
int c = 0; c < nc; c++)
238 const int color =
FC(c % 2, c / 2, filters);
243 const int halfwidth = roi->
width / 2 + (roi->
width & (~(c >> 1)) & 1);
244 const int halfheight = roi->
height / 2 + (roi->
height & (~c) & 1);
251 float *
const restrict fimgp = fimg + (size_t)
row / 2 * halfwidth;
252 const int offset = (c & 2) >> 1;
253 const float *
const restrict inp = in + (size_t)
row * roi->
width + offset;
254 const int senselwidth = (roi->
width-offset+1)/2;
255 for(
int col = 0; col < senselwidth; col++)
256 fimgp[col] = sqrtf(
MAX(0.0f, inp[2*col]));
271 const float *
const restrict fimgp = fimg + (size_t)
row / 2 * halfwidth;
272 const int offset = (c & 2) >> 1;
273 float *
const restrict outp =
out + (size_t)
row * roi->
width + offset;
274 const int senselwidth = (roi->
width-offset+1)/2;
275 for(
int col = 0; col < senselwidth; col++)
277 float d = fimgp[col];
290 if (filters &&
colors == 3)
298 mul[
row] = 0.125 * pre_mul[
FC(
row+1,0) | 1] / pre_mul[
FC(
row,0) | 1];
301 for (
i=0;
i < 4;
i++)
305 while (wlast <
row+1)
307 for (wlast++,
i=0;
i < 4;
i++)
308 window[(
i+3) & 3] = window[
i];
309 for (col =
FC(wlast,1) & 1; col <
width; col+=2)
310 window[2][col] = BAYER(wlast,col);
312 for (col = (
FC(
row,0) & 1)+1; col <
width-1; col+=2)
314 float avg = ( window[0][col-1] + window[0][col+1] +
315 window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 )
316 * mul[
row & 1] + (window[1][col] + blk[
row & 1]) * 0.5;
317 avg = avg > 0 ? sqrtf(avg) : 0;
318 float diff = sqrtf(BAYER(
row,col)) - avg;
319 if (diff < -thold) diff += thold;
320 else if (diff > thold) diff -= thold;
322 BAYER(
row,col) =
SQR(avg+diff);
341 const int width = roi->width;
342 const int height = roi->height;
350 memcpy(
out, in,
sizeof(
float) *
size);
353 float *
const fimg = img +
width;
355 for(
int c = 0; c < 3; c++)
363 for (
size_t col = 0; col <
width; col++)
369 const size_t chunksize = (
height + nthreads - 1) / nthreads;
371 for(
size_t chunk = 0; chunk < nthreads; chunk++)
373 const size_t start = chunk * chunksize;
374 const size_t pastend =
MIN(start + chunksize,
height);
375 for(
size_t row = start;
row < pastend;
row++)
377 const float *
const restrict inp = in +
row *
width;
378 float *
const restrict fimgp = fimg +
row *
width;
386 for(
size_t col = (c != 1); col <
width-1; col++)
399 fimgp[col+1] = fimgp[col+
width] =
d;
409 fimgp[col-1] = fimgp[col+1] =
d;
450 const float *
const restrict inp = in + pastend *
width;
451 float *
const restrict fimgp = fimg + pastend *
width;
452 for (
size_t col = 0; col <
width-1; col++)
454 if (
FCxtrans(pastend, col, roi, xtrans) == c)
459 if (
FCxtrans(pastend, col+1, roi, xtrans) != c)
460 fimgp[col] = fimgp[col+1] =
d;
466 if (col > 0) fimgp[col-
width-1] =
d;
470 if (c != 1 && pastend+1 <
height &&
FCxtrans(pastend+1, col, roi, xtrans) == c)
473 fimgp[col] = fimgp[col+1] =
d;
474 if (col > 0) fimgp[col-1] =
d;
492 const float *
const restrict fimgp = fimg + (size_t)
row *
width;
493 float *
const restrict outp =
out + (size_t)
row *
width;
494 for(
int col = 0; col <
width; col++)
497 float d = fimgp[col];
513 if(!(
d->threshold > 0.0f))
520 const uint8_t(*
const xtrans)[6] = (
const uint8_t(*
const)[6])piece->
dsc_in.
xtrans;
554 const dt_image_t *
const img = &
module->dev->image_storage;
555 module->hide_enable_button = !_rawdenoise_supported(img);
556 dt_iop_fmt_log(module,
"reload_defaults: class=%s needs_demosaic=%d -> hide_enable=%d",
565 module->default_enabled = 0;
573 const gboolean
state = current_state && active;
574 dt_iop_fmt_log(self,
"force_enable: class=%s supported=%d current=%d -> %d",
576 active, current_state,
state);
586 d->threshold =
p->threshold;
608 piece->
data = (
void *)
d;
629 gtk_widget_queue_draw(self->
widget);
633 const double mouse_y,
const float rad)
637 const float f = expf(-(mouse_x -
p->x[
ch][
k]) * (mouse_x -
p->x[
ch][
k]) / (rad * rad));
638 p->y[
ch][
k] = (1 -
f) *
p->y[
ch][
k] +
f * mouse_y;
648 int ch = (int)c->channel;
656 GtkAllocation allocation;
657 gtk_widget_get_allocation(widget, &allocation);
658 int width = allocation.width,
height = allocation.height;
660 cairo_t *cr = cairo_create(cst);
661 cairo_set_source_rgb(cr, .2, .2, .2);
665 cairo_translate(cr, inset, inset);
670 cairo_set_source_rgb(cr, .1, .1, .1);
674 cairo_set_source_rgb(cr, .3, .3, .3);
680 cairo_set_source_rgb(cr, .1, .1, .1);
683 if(c->mouse_y > 0 || c->dragging)
707 cairo_translate(cr, 0,
height);
709 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
721 cairo_set_source_rgba(cr, .7, .7, .7, alpha);
724 cairo_set_source_rgba(cr, .7, .1, .1, alpha);
727 cairo_set_source_rgba(cr, .1, .7, .1, alpha);
730 cairo_set_source_rgba(cr, .1, .1, .7, alpha);
749 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
760 if(c->mouse_y > 0 || c->dragging)
763 cairo_set_source_rgba(cr, .7, .7, .7, .6);
764 cairo_move_to(cr, 0, -
height * c->draw_min_ys[0]);
769 cairo_close_path(cr);
772 cairo_set_source_rgba(cr, .9, .9, .9, .5);
775 const float f =
k - pos;
777 float ht = -
height * (
f * c->draw_ys[
k] + (1 -
f) * c->draw_ys[
k + 1]);
778 cairo_arc(cr, c->mouse_x *
width, ht, c->mouse_radius *
width, 0, 2. *
M_PI);
784 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
790 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
791 pango_font_description_set_absolute_size(desc, (.08 *
height) * PANGO_SCALE);
792 layout = pango_cairo_create_layout(cr);
793 pango_layout_set_font_description(layout, desc);
794 cairo_set_source_rgb(cr, .1, .1, .1);
796 pango_layout_set_text(layout, _(
"coarse"), -1);
797 pango_layout_get_pixel_extents(layout, &ink, NULL);
798 cairo_move_to(cr, .02 *
width - ink.y, .5 * (
height + ink.width));
800 cairo_rotate(cr, -
M_PI * .5f);
801 pango_cairo_show_layout(cr, layout);
804 pango_layout_set_text(layout, _(
"fine"), -1);
805 pango_layout_get_pixel_extents(layout, &ink, NULL);
806 cairo_move_to(cr, .98 *
width - ink.height, .5 * (
height + ink.width));
808 cairo_rotate(cr, -
M_PI * .5f);
809 pango_cairo_show_layout(cr, layout);
813 pango_layout_set_text(layout, _(
"smooth"), -1);
814 pango_layout_get_pixel_extents(layout, &ink, NULL);
815 cairo_move_to(cr, .5 * (
width - ink.width), .08 *
height - ink.height);
816 pango_cairo_show_layout(cr, layout);
818 pango_layout_set_text(layout, _(
"noisy"), -1);
819 pango_layout_get_pixel_extents(layout, &ink, NULL);
820 cairo_move_to(cr, .5 * (
width - ink.width), .97 *
height - ink.height);
821 pango_cairo_show_layout(cr, layout);
823 pango_font_description_free(desc);
824 g_object_unref(layout);
826 cairo_set_source_surface(crf, cst, 0, 0);
828 cairo_surface_destroy(cst);
838 GtkAllocation allocation;
839 gtk_widget_get_allocation(widget, &allocation);
840 int height = allocation.height - 2 * inset,
width = allocation.width - 2 * inset;
841 if(!c->dragging) c->mouse_x = CLAMP(event->x - inset, 0,
width) / (float)
width;
842 c->mouse_y = 1.0 - CLAMP(event->y - inset, 0,
height) / (float)
height;
850 gtk_widget_queue_draw(widget);
856 gtk_widget_queue_draw(widget);
865 const int ch = c->channel;
866 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
877 gtk_widget_queue_draw(self->
widget);
879 else if(event->button == 1)
883 GtkAllocation allocation;
884 gtk_widget_get_allocation(widget, &allocation);
885 int height = allocation.height - 2 * inset,
width = allocation.width - 2 * inset;
888 c->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0,
height) / (float)
height;
897 if(event->button == 1)
911 if(!c->dragging) c->mouse_y = -1.0;
912 gtk_widget_queue_draw(widget);
925 gtk_widget_queue_draw(widget);
937 gtk_widget_queue_draw(self->
widget);
945 c->channel =
dt_conf_get_int(
"plugins/darkroom/rawdenoise/gui_channel");
946 c->channel_tabs = GTK_NOTEBOOK(gtk_notebook_new());
953 gtk_widget_show(gtk_notebook_get_nth_page(c->channel_tabs, c->channel));
954 gtk_notebook_set_current_page(c->channel_tabs, c->channel);
957 const int ch = (int)c->channel;
965 c->mouse_x = c->mouse_y = c->mouse_pick = -1.0;
973 c->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
974 gtk_widget_set_hexpand(GTK_WIDGET(c->area),
TRUE);
975 g_object_set_data(G_OBJECT(c->area),
"iop-instance", self);
977 gtk_box_pack_start(GTK_BOX(box_raw), GTK_WIDGET(c->channel_tabs),
FALSE,
FALSE, 0);
978 gtk_box_pack_start(GTK_BOX(box_raw),
980 "plugins/darkroom/rawdenoise/graphheight", 280, 100),
984 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
985 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
986 g_signal_connect(G_OBJECT(c->area),
"draw", G_CALLBACK(
rawdenoise_draw), self);
991 g_signal_connect(G_OBJECT(c->area),
"scroll-event", G_CALLBACK(
rawdenoise_scrolled), self);
998 self->
widget = gtk_stack_new();
999 gtk_stack_set_homogeneous(GTK_STACK(self->
widget),
FALSE);
1003 gtk_stack_add_named(GTK_STACK(self->
widget), label_non_raw,
"non_raw");
1004 gtk_stack_add_named(GTK_STACK(self->
widget), box_raw,
"raw");
1010 dt_conf_set_int(
"plugins/darkroom/rawdenoise/gui_channel", c->channel);
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
gboolean dt_image_needs_demosaic(const dt_image_t *img)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#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 __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static int FCxtrans(const int row, const int col, global const unsigned char(*const xtrans)[6])
static int FC(const int row, const int col, const unsigned int filters)
#define dt_dev_add_history_item(dev, module, enable, redraw)
static void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
static float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
__DT_CLONE_TARGETS__ int dwt_denoise(float *const img, const int width, const int height, const int bands, const float *const noise)
const dt_collection_filter_flag_t colors[6]
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
static GtkWidget * dt_ui_label_new(const gchar *str)
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_queue(gpointer source, dt_gui_throttle_callback_t callback, gpointer user_data)
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)
void dt_iop_throttled_history_update(gpointer data)
void dt_iop_default_init(dt_iop_module_t *module)
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)
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
@ 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 *const restrict const size_t const size_t ch
#define DT_IOP_RAWDENOISE_RES
void init(dt_iop_module_t *module)
static void rawdenoise_tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
const char ** description(struct dt_iop_module_t *self)
static gboolean rawdenoise_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static __DT_CLONE_TARGETS__ void compute_channel_noise(float *const noise, int color, const dt_iop_rawdenoise_data_t *const data)
void reload_defaults(dt_iop_module_t *module)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean rawdenoise_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
#define DT_IOP_RAWDENOISE_INSET
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean _rawdenoise_supported(const dt_image_t *img)
void gui_init(dt_iop_module_t *self)
void gui_cleanup(dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ int wavelet_denoise(const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const roi, const dt_iop_rawdenoise_data_t *const data, const uint32_t filters)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
static __DT_CLONE_TARGETS__ int wavelet_denoise_xtrans(const float *const restrict in, float *const restrict out, const dt_iop_roi_t *const restrict roi, const dt_iop_rawdenoise_data_t *const data, const uint8_t(*const xtrans)[6])
#define DT_IOP_RAWDENOISE_BANDS
static gboolean rawdenoise_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
static gboolean rawdenoise_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
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)
gboolean force_enable(struct dt_iop_module_t *self, const gboolean current_state)
static float vstransform(const float value)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean rawdenoise_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static void dt_iop_rawdenoise_get_params(dt_iop_rawdenoise_params_t *p, const int ch, const double mouse_x, const double mouse_y, const float rad)
dt_iop_rawdenoise_channel_t
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
int32_t num_openmp_threads
struct dt_gui_gtk_t * gui
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
PangoFontDescription * pango_font_desc
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_develop_t * dev
int32_t hide_enable_button
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
float force[DT_RAWDENOISE_NONE][5]
dt_draw_curve_t * curve[DT_RAWDENOISE_NONE]
dt_iop_rawdenoise_channel_t channel
dt_iop_rawdenoise_channel_t channel
dt_iop_rawdenoise_params_t drag_params
dt_draw_curve_t * transition_curve
GtkNotebook * channel_tabs
float x[DT_RAWDENOISE_NONE][5]
float y[DT_RAWDENOISE_NONE][5]
Region of interest passed through the pixelpipe.