80#define DT_IOP_RAWDENOISE_INSET DT_PIXEL_APPLY_DPI(5)
81#define DT_IOP_RAWDENOISE_RES 64
82#define DT_IOP_RAWDENOISE_BANDS 5
131 const int new_version)
133 if(old_version == 1 && new_version == 2)
162 return _(
"raw denoise");
169 _(
"linear, raw, scene-referred"),
171 _(
"linear, raw, scene-referred"));
204 static const float noise_all[] = { 0.8002, 0.2735, 0.1202, 0.0585, 0.0291, 0.0152, 0.0080, 0.0044 };
209 float chan_threshold_exp_4;
222 chan_threshold_exp_4 *= chan_threshold_exp_4;
223 chan_threshold_exp_4 *= chan_threshold_exp_4;
226 all_threshold_exp_4 *= all_threshold_exp_4;
227 all_threshold_exp_4 *= all_threshold_exp_4;
228 noise[
i] = noise_all[
i] * all_threshold_exp_4 * chan_threshold_exp_4 * 16.0f * 16.0f;
239 const size_t size = (size_t)(roi->
width / 2 + 1) * (roi->
height / 2 + 1);
245 for(
int c = 0; c < nc; c++)
247 const int color =
FC(c % 2, c / 2, filters);
252 const int halfwidth = roi->
width / 2 + (roi->
width & (~(c >> 1)) & 1);
253 const int halfheight = roi->
height / 2 + (roi->
height & (~c) & 1);
260 float *
const restrict fimgp = fimg + (size_t)
row / 2 * halfwidth;
261 const int offset = (c & 2) >> 1;
262 const float *
const restrict inp = in + (size_t)
row * roi->
width + offset;
263 const int senselwidth = (roi->
width-offset+1)/2;
264 for(
int col = 0; col < senselwidth; col++)
265 fimgp[col] = sqrtf(
MAX(0.0f, inp[2*col]));
280 const float *
const restrict fimgp = fimg + (size_t)
row / 2 * halfwidth;
281 const int offset = (c & 2) >> 1;
282 float *
const restrict outp =
out + (size_t)
row * roi->
width + offset;
283 const int senselwidth = (roi->
width-offset+1)/2;
284 for(
int col = 0; col < senselwidth; col++)
286 float d = fimgp[col];
299 if (filters &&
colors == 3)
307 mul[
row] = 0.125 * pre_mul[
FC(
row+1,0) | 1] / pre_mul[
FC(
row,0) | 1];
310 for (
i=0;
i < 4;
i++)
314 while (wlast <
row+1)
316 for (wlast++,
i=0;
i < 4;
i++)
318 for (col =
FC(wlast,1) & 1; col <
width; col+=2)
319 window[2][col] = BAYER(wlast,col);
321 for (col = (
FC(
row,0) & 1)+1; col <
width-1; col+=2)
326 avg = avg > 0 ? sqrtf(avg) : 0;
327 float diff = sqrtf(BAYER(
row,col)) - avg;
328 if (diff < -thold) diff += thold;
329 else if (diff > thold) diff -= thold;
331 BAYER(
row,col) =
SQR(avg+diff);
350 const int width = roi->width;
351 const int height = roi->height;
359 memcpy(
out, in,
sizeof(
float) *
size);
362 float *
const fimg = img +
width;
364 for(
int c = 0; c < 3; c++)
372 for (
size_t col = 0; col <
width; col++)
378 const size_t chunksize = (
height + nthreads - 1) / nthreads;
380 for(
size_t chunk = 0; chunk < nthreads; chunk++)
382 const size_t start = chunk * chunksize;
383 const size_t pastend =
MIN(start + chunksize,
height);
384 for(
size_t row = start;
row < pastend;
row++)
386 const float *
const restrict inp = in +
row *
width;
387 float *
const restrict fimgp = fimg +
row *
width;
395 for(
size_t col = (c != 1); col <
width-1; col++)
408 fimgp[col+1] = fimgp[col+
width] =
d;
418 fimgp[col-1] = fimgp[col+1] =
d;
459 const float *
const restrict inp = in + pastend *
width;
460 float *
const restrict fimgp = fimg + pastend *
width;
461 for (
size_t col = 0; col <
width-1; col++)
463 if (
FCxtrans(pastend, col, roi, xtrans) == c)
468 if (
FCxtrans(pastend, col+1, roi, xtrans) != c)
469 fimgp[col] = fimgp[col+1] =
d;
475 if (col > 0) fimgp[col-
width-1] =
d;
479 if (c != 1 && pastend+1 <
height &&
FCxtrans(pastend+1, col, roi, xtrans) == c)
482 fimgp[col] = fimgp[col+1] =
d;
483 if (col > 0) fimgp[col-1] =
d;
501 const float *
const restrict fimgp = fimg + (size_t)
row *
width;
502 float *
const restrict outp =
out + (size_t)
row *
width;
503 for(
int col = 0; col <
width; col++)
506 float d = fimgp[col];
522 if(!(
d->threshold > 0.0f))
529 const uint8_t(*
const xtrans)[6] = (
const uint8_t(*
const)[6])piece->
dsc_in.
xtrans;
563 const dt_image_t *
const img = &
module->dev->image_storage;
564 module->hide_enable_button = !_rawdenoise_supported(img);
565 dt_iop_fmt_log(module,
"reload_defaults: class=%s needs_demosaic=%d -> hide_enable=%d",
571 module->default_enabled = 0;
579 const gboolean
state = current_state && active;
580 dt_iop_fmt_log(self,
"force_enable: class=%s supported=%d current=%d -> %d",
582 active, current_state,
state);
592 d->threshold =
p->threshold;
614 piece->
data = (
void *)
d;
644 gtk_widget_queue_draw(self->
gui->
widget);
648 const double mouse_y,
const float rad)
652 const float f = expf(-(mouse_x -
p->x[
ch][
k]) * (mouse_x -
p->x[
ch][
k]) / (rad * rad));
653 p->y[
ch][
k] = (1 -
f) *
p->y[
ch][
k] +
f * mouse_y;
663 int ch = (int)c->channel;
671 GtkAllocation allocation;
672 gtk_widget_get_allocation(widget, &allocation);
673 int width = allocation.width,
height = allocation.height;
675 cairo_t *cr = cairo_create(cst);
676 cairo_set_source_rgb(cr, .2, .2, .2);
680 cairo_translate(cr, inset, inset);
685 cairo_set_source_rgb(cr, .1, .1, .1);
689 cairo_set_source_rgb(cr, .3, .3, .3);
695 cairo_set_source_rgb(cr, .1, .1, .1);
698 if(c->mouse_y > 0 || c->dragging)
722 cairo_translate(cr, 0,
height);
724 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
736 cairo_set_source_rgba(cr, .7, .7, .7, alpha);
739 cairo_set_source_rgba(cr, .7, .1, .1, alpha);
742 cairo_set_source_rgba(cr, .1, .7, .1, alpha);
745 cairo_set_source_rgba(cr, .1, .1, .7, alpha);
764 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
775 if(c->mouse_y > 0 || c->dragging)
778 cairo_set_source_rgba(cr, .7, .7, .7, .6);
779 cairo_move_to(cr, 0, -
height * c->draw_min_ys[0]);
784 cairo_close_path(cr);
787 cairo_set_source_rgba(cr, .9, .9, .9, .5);
790 const float f =
k - pos;
792 float ht = -
height * (
f * c->draw_ys[
k] + (1 -
f) * c->draw_ys[
k + 1]);
793 cairo_arc(cr, c->mouse_x *
width, ht, c->mouse_radius *
width, 0, 2. *
M_PI);
799 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
804 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
805 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
806 pango_font_description_set_absolute_size(desc, (.08 *
height) * PANGO_SCALE);
807 layout = pango_cairo_create_layout(cr);
808 pango_layout_set_font_description(layout, desc);
809 cairo_set_source_rgb(cr, .1, .1, .1);
811 pango_layout_set_text(layout, _(
"coarse"), -1);
812 pango_layout_get_pixel_extents(layout, &ink, NULL);
813 cairo_move_to(cr, .02 *
width - ink.y, .5 * (
height + ink.width));
815 cairo_rotate(cr, -
M_PI * .5f);
816 pango_cairo_show_layout(cr, layout);
819 pango_layout_set_text(layout, _(
"fine"), -1);
820 pango_layout_get_pixel_extents(layout, &ink, NULL);
821 cairo_move_to(cr, .98 *
width - ink.height, .5 * (
height + ink.width));
823 cairo_rotate(cr, -
M_PI * .5f);
824 pango_cairo_show_layout(cr, layout);
828 pango_layout_set_text(layout, _(
"smooth"), -1);
829 pango_layout_get_pixel_extents(layout, &ink, NULL);
830 cairo_move_to(cr, .5 * (
width - ink.width), .08 *
height - ink.height);
831 pango_cairo_show_layout(cr, layout);
833 pango_layout_set_text(layout, _(
"noisy"), -1);
834 pango_layout_get_pixel_extents(layout, &ink, NULL);
835 cairo_move_to(cr, .5 * (
width - ink.width), .97 *
height - ink.height);
836 pango_cairo_show_layout(cr, layout);
838 pango_font_description_free(desc);
839 g_object_unref(layout);
841 cairo_set_source_surface(crf, cst, 0, 0);
843 cairo_surface_destroy(cst);
853 GtkAllocation allocation;
854 gtk_widget_get_allocation(widget, &allocation);
855 int height = allocation.height - 2 * inset,
width = allocation.width - 2 * inset;
856 if(!c->dragging) c->mouse_x = CLAMP(event->x - inset, 0,
width) / (float)
width;
857 c->mouse_y = 1.0 - CLAMP(event->y - inset, 0,
height) / (float)
height;
865 gtk_widget_queue_draw(widget);
871 gtk_widget_queue_draw(widget);
880 const int ch = c->channel;
881 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
892 gtk_widget_queue_draw(self->
gui->
widget);
894 else if(event->button == 1)
898 GtkAllocation allocation;
899 gtk_widget_get_allocation(widget, &allocation);
900 int height = allocation.height - 2 * inset,
width = allocation.width - 2 * inset;
903 c->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0,
height) / (float)
height;
912 if(event->button == 1)
926 if(!c->dragging) c->mouse_y = -1.0;
927 gtk_widget_queue_draw(widget);
940 gtk_widget_queue_draw(widget);
952 gtk_widget_queue_draw(self->
gui->
widget);
960 c->channel =
dt_conf_get_int(
"plugins/darkroom/rawdenoise/gui_channel");
961 c->channel_tabs = GTK_NOTEBOOK(gtk_notebook_new());
968 gtk_widget_show(gtk_notebook_get_nth_page(c->channel_tabs, c->channel));
969 gtk_notebook_set_current_page(c->channel_tabs, c->channel);
972 const int ch = (int)c->channel;
980 c->mouse_x = c->mouse_y = c->mouse_pick = -1.0;
988 c->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
989 gtk_widget_set_hexpand(GTK_WIDGET(c->area),
TRUE);
990 g_object_set_data(G_OBJECT(c->area),
"iop-instance", self);
992 gtk_box_pack_start(GTK_BOX(box_raw), GTK_WIDGET(c->channel_tabs),
FALSE,
FALSE, 0);
993 gtk_box_pack_start(GTK_BOX(box_raw),
995 "plugins/darkroom/rawdenoise/graphheight", 280, 100),
999 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1000 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1001 g_signal_connect(G_OBJECT(c->area),
"draw", G_CALLBACK(
rawdenoise_draw), self);
1006 g_signal_connect(G_OBJECT(c->area),
"scroll-event", G_CALLBACK(
rawdenoise_scrolled), self);
1018 gtk_stack_add_named(GTK_STACK(self->
gui->
widget), label_non_raw,
"non_raw");
1019 gtk_stack_add_named(GTK_STACK(self->
gui->
widget), box_raw,
"raw");
1025 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)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
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)
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
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]
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_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
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_ui_label_new(const gchar *str)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
#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)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
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_iop_module_gui_t * gui
struct dt_develop_t * dev
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.
#define __DT_CLONE_TARGETS__