[gegl] workshop: add shadows-highlights operation
- From: Thomas Manni <tmanni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] workshop: add shadows-highlights operation
- Date: Thu, 2 Feb 2017 20:47:20 +0000 (UTC)
commit 46f525ad7d761effd5c9662a72ef5d684e3be45c
Author: Thomas Manni <thomas manni free fr>
Date: Sun Jan 22 06:22:16 2017 +0100
workshop: add shadows-highlights operation
operations/workshop/Makefile.am | 2 +
.../workshop/shadows-highlights-correction.c | 250 ++++++++++++++++++++
operations/workshop/shadows-highlights.c | 112 +++++++++
po/POTFILES.in | 2 +
4 files changed, 366 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index cd45023..182df3b 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -25,5 +25,7 @@ op_LTLIBRARIES = \
median-blur.la \
rawbayer-load.la \
segment-kmeans.la \
+ shadows-highlights.la \
+ shadows-highlights-correction.la \
unpremul.la \
vhsfix.la
diff --git a/operations/workshop/shadows-highlights-correction.c
b/operations/workshop/shadows-highlights-correction.c
new file mode 100644
index 0000000..ce19b9b
--- /dev/null
+++ b/operations/workshop/shadows-highlights-correction.c
@@ -0,0 +1,250 @@
+/* This file is an image processing operation for GEGL
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_double (s_amount, _("shadows amount"), 0.2)
+ value_range (0.0, 1.0)
+
+property_double (s_tonalwidth, _("shadows tonal width"), 0.1)
+ value_range (0.001, 1.0)
+
+property_double (h_amount, _("highlights amount"), 0.2)
+ value_range (0.0, 1.0)
+
+property_double (h_tonalwidth, _("highlights tonal width"), 0.1)
+ value_range (0.001, 1.0)
+
+#else
+
+#define GEGL_OP_POINT_COMPOSER3
+#define GEGL_OP_NAME shadows_highlights_correction
+#define GEGL_OP_C_SOURCE shadows-highlights-correction.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+#define LUT_SIZE 2048
+
+typedef struct
+{
+ gdouble shadows[LUT_SIZE];
+ gdouble highlights[LUT_SIZE];
+} Luts;
+
+static void
+initialize_luts (GeglProperties *o)
+{
+ gint i, scale = LUT_SIZE - 1;
+ Luts *luts = (Luts *) o->user_data;
+ gdouble s_scaled = o->s_tonalwidth * scale;
+ gdouble h_scaled = (1.0 - o->h_tonalwidth) * scale;
+
+ for (i = 0; i < LUT_SIZE; i++)
+ {
+ /* shadows */
+ if (i < s_scaled)
+ {
+ luts->shadows[i] = 1.0 - pow((i / s_scaled), 2.0);
+ }
+ else
+ {
+ luts->shadows[i] = 0.0;
+ }
+
+ /* highlights */
+ if (i > h_scaled)
+ {
+ luts->highlights[i] = 1.0 - pow((scale - i) / (scale - h_scaled), 2.0);
+ }
+ else
+ {
+ luts->highlights[i] = 0.0;
+ }
+ }
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *rgba_f = babl_format ("R'G'B'A float");
+ const Babl *y_f = babl_format ("Y' float");
+
+ if (o->user_data == NULL)
+ o->user_data = g_slice_new0 (Luts);
+
+ initialize_luts (o);
+
+ gegl_operation_set_format (operation, "input", rgba_f);
+ gegl_operation_set_format (operation, "aux", y_f);
+ gegl_operation_set_format (operation, "aux2", y_f);
+ gegl_operation_set_format (operation, "output", rgba_f);
+}
+
+static void
+finalize (GObject *object)
+{
+ GeglProperties *o = GEGL_PROPERTIES (object);
+
+ if (o->user_data)
+ {
+ g_slice_free (Luts, o->user_data);
+ o->user_data = NULL;
+ }
+
+ G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+}
+
+static gboolean
+process (GeglOperation *operation,
+ void *in_buf,
+ void *aux_buf,
+ void *aux2_buf,
+ void *out_buf,
+ glong n_pixels,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Luts *luts = (Luts *) o->user_data;
+
+ gfloat *src = in_buf;
+ gfloat *dst = out_buf;
+ gfloat *aux = aux_buf;
+ gfloat *aux2 = aux2_buf;
+
+ if (!aux || !aux2)
+ {
+ memcpy (out_buf, in_buf, sizeof (gfloat) * 4 * n_pixels);
+ return TRUE;
+ }
+
+ while (n_pixels--)
+ {
+ gfloat *src_pix = src;
+ gfloat shadows_estimation = *aux;
+ gfloat highlights_estimation = *aux2;
+
+ gdouble correction;
+ gdouble lut_value;
+ gint b;
+
+ /* shadows correction */
+
+ if (o->s_amount)
+ {
+ lut_value = luts->shadows[(gint) (shadows_estimation * (LUT_SIZE - 1))];
+
+ if (lut_value > 0.0)
+ {
+ correction = o->s_amount * lut_value;
+
+ for (b = 0; b < 3; b++)
+ {
+ gfloat new_shadow = 1.0 - shadows_estimation;
+
+ if (src_pix[b] < 0.5)
+ new_shadow = 2.0 * src_pix[b] * new_shadow;
+ else
+ new_shadow = 1.0 - 2.0 * (1.0 - src_pix[b]) * (1.0 - new_shadow);
+
+ src_pix[b] = correction * new_shadow + (1.0 - correction) * src_pix[b];
+ }
+ }
+ }
+
+ /* highlights correction */
+
+ if (o->h_amount)
+ {
+ lut_value = luts->highlights[(gint) (highlights_estimation * (LUT_SIZE - 1))];
+
+ if (lut_value > 0.0)
+ {
+ correction = o->h_amount * lut_value;
+
+ for (b = 0; b < 3; b++)
+ {
+ gfloat new_highlight = 1.0 - highlights_estimation;
+
+ if (src_pix[b] < 0.5)
+ new_highlight = 2.0 * src_pix[b] * new_highlight;
+ else
+ new_highlight = 1.0 - 2.0 * (1.0 - src_pix[b]) * (1.0 - new_highlight);
+
+ src_pix[b] = correction * new_highlight + (1.0 - correction) * src_pix[b];
+ }
+ }
+ }
+
+ dst[0] = src_pix[0];
+ dst[1] = src_pix[1];
+ dst[2] = src_pix[2];
+ dst[3] = src[3];
+
+ src += 4;
+ dst += 4;
+ aux += 1;
+ aux2 += 1;
+ }
+
+ return TRUE;
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *self)
+{
+ GeglRectangle result = { 0, 0, 0, 0 };
+ GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (self, "input");
+
+ if (! in_rect)
+ return result;
+
+ return *in_rect;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GObjectClass *object_class;
+ GeglOperationClass *operation_class;
+ GeglOperationPointComposer3Class *point_composer3_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ operation_class->prepare = prepare;
+ operation_class->get_bounding_box = get_bounding_box;
+ operation_class->opencl_support = FALSE;
+
+ point_composer3_class->process = process;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:shadows-highlights-correction",
+ "categories", "hidden",
+ "description", _("Lighten shadows and darken highlights"),
+ NULL);
+}
+
+#endif
diff --git a/operations/workshop/shadows-highlights.c b/operations/workshop/shadows-highlights.c
new file mode 100644
index 0000000..5e88bf8
--- /dev/null
+++ b/operations/workshop/shadows-highlights.c
@@ -0,0 +1,112 @@
+/* This file is an image processing operation for GEGL
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_double (s_amount, _("shadows amount"), 0.2)
+ value_range (0.0, 1.0)
+
+property_double (s_tonalwidth, _("shadows tonal width"), 0.1)
+ value_range (0.001, 1.0)
+
+property_double (s_radius, _("shadows radius"), 5.0)
+ value_range (0.0, 100.0)
+
+property_double (h_amount, _("highlights amount"), 0.2)
+ value_range (0.0, 1.0)
+
+property_double (h_tonalwidth, _("highlights tonal width"), 0.1)
+ value_range (0.001, 1.0)
+
+property_double (h_radius, _("highlights radius"), 5.0)
+ value_range (0.0, 100.0)
+
+#else
+
+#define GEGL_OP_META
+#define GEGL_OP_NAME shadows_highlights
+#define GEGL_OP_C_SOURCE shadows-highlights.c
+
+#include "gegl-op.h"
+
+static void
+attach (GeglOperation *operation)
+{
+ GeglNode *gegl;
+ GeglNode *input;
+ GeglNode *output;
+ GeglNode *s_blur;
+ GeglNode *h_blur;
+ GeglNode *shprocess;
+
+ gegl = operation->node;
+ input = gegl_node_get_input_proxy (gegl, "input");
+ output = gegl_node_get_output_proxy (gegl, "output");
+
+ s_blur = gegl_node_new_child (gegl,
+ "operation", "gegl:gaussian-blur",
+ "abyss-policy", 1,
+ NULL);
+
+ h_blur = gegl_node_new_child (gegl,
+ "operation", "gegl:gaussian-blur",
+ "abyss-policy", 1,
+ NULL);
+
+ shprocess = gegl_node_new_child (gegl,
+ "operation", "gegl:shadows-highlights-correction",
+ NULL);
+
+ gegl_node_link (input, s_blur);
+ gegl_node_link (input, h_blur);
+ gegl_node_link_many (input, shprocess, output, NULL);
+
+ gegl_node_connect_to (s_blur, "output", shprocess, "aux");
+ gegl_node_connect_to (h_blur, "output", shprocess, "aux2");
+
+ gegl_operation_meta_redirect (operation, "s-amount", shprocess, "s-amount");
+ gegl_operation_meta_redirect (operation, "s-tonalwidth", shprocess, "s-tonalwidth");
+ gegl_operation_meta_redirect (operation, "s-radius", s_blur, "std-dev-x");
+ gegl_operation_meta_redirect (operation, "s-radius", s_blur, "std-dev-y");
+ gegl_operation_meta_redirect (operation, "h-amount", shprocess, "h-amount");
+ gegl_operation_meta_redirect (operation, "h-tonalwidth", shprocess, "h-tonalwidth");
+ gegl_operation_meta_redirect (operation, "h-radius", h_blur, "std-dev-x");
+ gegl_operation_meta_redirect (operation, "h-radius", h_blur, "std-dev-y");
+
+ gegl_operation_meta_watch_nodes (operation, s_blur, h_blur, shprocess, NULL);
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GeglOperationClass *operation_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+
+ operation_class->attach = attach;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:shadows-highlights",
+ "title", _("Shadows Highlights"),
+ "categories", "light",
+ "description", _("Performs shadows and highlights correction"),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f5f7913..368d327 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -249,4 +249,6 @@ operations/workshop/mandelbrot.c
operations/workshop/median-blur.c
operations/workshop/rawbayer-load.c
operations/workshop/segment-kmeans.c
+operations/workshop/shadows-highlights.c
+operations/workshop/shadows-highlights-correction.c
operations/workshop/vhsfix.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]