[gegl] recursive-transform-plus: new operation in workshop
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] recursive-transform-plus: new operation in workshop
- Date: Tue, 5 Jun 2018 08:31:31 +0000 (UTC)
commit 9829bc22e85526d789c4e80c05949d4c6202a207
Author: Ell <ell_se yahoo com>
Date: Tue Jun 5 03:41:19 2018 -0400
recursive-transform-plus: new operation in workshop
gegl:recursive-transform-plus is an extension of
gegl:recursive-transform, allowing multiple transformations to be
applied simultaneously. The transformation matrices are specified
through the "transform" property, as before, separated by
semicolons.
The intent is to eventually merge this back into
gegl:recursive-transform.
operations/workshop/Makefile.am | 1 +
operations/workshop/recursive-transform-plus.c | 392 +++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 394 insertions(+)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 345cc196d..09a78d618 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -24,4 +24,5 @@ op_LTLIBRARIES = \
integral-image.la \
linear-sinusoid.la \
rawbayer-load.la \
+ recursive-transform-plus.la \
segment-kmeans.la
diff --git a/operations/workshop/recursive-transform-plus.c b/operations/workshop/recursive-transform-plus.c
new file mode 100644
index 000000000..9426d09d8
--- /dev/null
+++ b/operations/workshop/recursive-transform-plus.c
@@ -0,0 +1,392 @@
+/* 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/>.
+ *
+ * Copyright 2018 Ell
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#define MAX_ITERATIONS 20
+#define MAX_TRANSFORMS 10
+#define EPSILON 1e-6
+
+#ifdef GEGL_PROPERTIES
+
+property_string (transform, _("Transform"), "matrix (1, 0, 0, 0, 1, 0, 0, 0, 1)")
+ description (_("Transformation matrix, using SVG syntax "
+ "(or multiple matrices, separated by semicolons)"))
+
+property_int (first_iteration, _("First iteration"), 0)
+ description (_("First iteration"))
+ value_range (0, MAX_ITERATIONS)
+
+property_int (iterations, _("Iterations"), 3)
+ description (_("Number of iterations"))
+ value_range (0, MAX_ITERATIONS)
+
+property_color (fade_color, _("Fade color"), "transparent")
+ description (_("Color to fade transformed images towards, "
+ "with a rate depending on its alpha"))
+
+property_double (fade_opacity, _("Fade opacity"), 1.0)
+ description (_("Amount by which to scale the opacity of "
+ "each transformed image"))
+ value_range (0.0, 1.0)
+
+property_boolean (paste_below, _("Paste below"), FALSE)
+ description (_("Paste transformed images below each other"))
+
+property_enum (sampler_type, _("Resampling method"),
+ GeglSamplerType, gegl_sampler_type, GEGL_SAMPLER_LINEAR)
+ description (_("Mathematical method for reconstructing pixel values"))
+
+#else
+
+#define GEGL_OP_META
+#define GEGL_OP_NAME recursive_transform_plus
+#define GEGL_OP_C_SOURCE recursive-transform-plus.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+typedef struct
+{
+ GeglNode *transform_nodes[MAX_TRANSFORMS];
+ GeglNode *color_overlay_node;
+ GeglNode *opacity_node;
+ GeglNode *over_nodes[MAX_TRANSFORMS - 1];
+} Iteration;
+
+static void
+update_graph (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Iteration *iters = o->user_data;
+ GeglNode *node = operation->node;
+ GeglNode *input;
+ GeglNode *output;
+ gchar **matrix_strs;
+ gdouble fade_color[4];
+ gint i;
+ gint j;
+
+ if (! iters)
+ return;
+
+ input = gegl_node_get_input_proxy (node, "input");
+ output = gegl_node_get_output_proxy (node, "output");
+
+ gegl_node_link (input, output);
+
+ for (i = 0; i <= MAX_ITERATIONS; i++)
+ {
+ for (j = 0; j < MAX_TRANSFORMS; j++)
+ gegl_node_disconnect (iters[i].transform_nodes[j], "input");
+
+ gegl_node_disconnect (iters[i].color_overlay_node, "input");
+ gegl_node_disconnect (iters[i].opacity_node, "input");
+
+ for (j = 0; j < MAX_TRANSFORMS - 1; j++)
+ {
+ gegl_node_disconnect (iters[i].over_nodes[j], "input");
+ gegl_node_disconnect (iters[i].over_nodes[j], "aux");
+ }
+ }
+
+ if (o->first_iteration == 0 && o->iterations == 0)
+ return;
+
+ matrix_strs = g_strsplit (o->transform, ";", MAX_TRANSFORMS + 1);
+
+ if (! matrix_strs[0])
+ {
+ g_strfreev (matrix_strs);
+
+ return;
+ }
+
+ gegl_color_get_rgba (o->fade_color,
+ &fade_color[0],
+ &fade_color[1],
+ &fade_color[2],
+ &fade_color[3]);
+
+ if (! matrix_strs[1])
+ {
+ GeglMatrix3 transform;
+
+ gegl_matrix3_parse_string (&transform, matrix_strs[0]);
+
+ for (i = o->iterations; i >= 0; i--)
+ {
+ GeglNode *source_node;
+ GeglMatrix3 matrix;
+ gchar *matrix_str;
+ gint n = o->first_iteration + i;
+
+ gegl_matrix3_identity (&matrix);
+
+ for (j = 0; j < n; j++)
+ gegl_matrix3_multiply (&matrix, &transform, &matrix);
+
+ matrix_str = gegl_matrix3_to_string (&matrix);
+
+ gegl_node_set (iters[i].transform_nodes[0],
+ "transform", matrix_str,
+ "sampler", o->sampler_type,
+ NULL);
+
+ g_free (matrix_str);
+
+ gegl_node_link (input, iters[i].transform_nodes[0]);
+ source_node = iters[i].transform_nodes[0];
+
+ if (n > 0 && fabs (fade_color[3]) > EPSILON)
+ {
+ GeglColor *color = gegl_color_new (NULL);
+ gdouble a = 1.0 - pow (1.0 - fade_color[3], n);
+
+ gegl_color_set_rgba (color,
+ fade_color[0],
+ fade_color[1],
+ fade_color[2],
+ a);
+
+ gegl_node_set (iters[i].color_overlay_node,
+ "value", color,
+ "srgb", TRUE,
+ NULL);
+
+ g_object_unref (color);
+
+ gegl_node_link (source_node, iters[i].color_overlay_node);
+ source_node = iters[i].color_overlay_node;
+ }
+
+ if (n > 0 && fabs (o->fade_opacity - 1.0) > EPSILON)
+ {
+ gegl_node_set (iters[i].opacity_node,
+ "value", pow (o->fade_opacity, n),
+ NULL);
+
+ gegl_node_link (source_node, iters[i].opacity_node);
+ source_node = iters[i].opacity_node;
+ }
+
+ gegl_node_connect_to (source_node, "output",
+ iters[i].over_nodes[0], ! o->paste_below ? "input" :
+ "aux");
+
+ if (i == 0)
+ {
+ gegl_node_link (iters[i].over_nodes[0], output);
+ }
+ else
+ {
+ gegl_node_connect_to (iters[i].over_nodes[0], "output",
+ iters[i - 1].over_nodes[0], ! o->paste_below ? "aux" :
+ "input");
+ }
+ }
+ }
+ else
+ {
+ gint n_iterations = MIN (o->first_iteration + o->iterations, MAX_ITERATIONS);
+ gint n_transforms;
+
+ for (n_transforms = 0;
+ n_transforms < MAX_TRANSFORMS && matrix_strs[n_transforms];
+ n_transforms++);
+
+ for (i = n_iterations; i >= 0; i--)
+ {
+ if (i < n_iterations)
+ {
+ GeglNode *source_node = NULL;
+
+ for (j = 0; j < n_transforms; j++)
+ {
+ gegl_node_set (iters[i].transform_nodes[j],
+ "transform", matrix_strs[j],
+ "sampler", o->sampler_type,
+ NULL);
+
+ gegl_node_link (iters[i + 1].over_nodes[n_transforms - 1],
+ iters[i].transform_nodes[j]);
+
+ if (j == 0)
+ {
+ source_node = iters[i].transform_nodes[j];
+ }
+ else
+ {
+ if (! o->paste_below)
+ {
+ gegl_node_connect_to (source_node, "output",
+ iters[i].over_nodes[j - 1], "input");
+ gegl_node_connect_to (iters[i].transform_nodes[j], "output",
+ iters[i].over_nodes[j - 1], "aux");
+ }
+ else
+ {
+ gegl_node_connect_to (source_node, "output",
+ iters[i].over_nodes[j - 1], "aux");
+ gegl_node_connect_to (iters[i].transform_nodes[j], "output",
+ iters[i].over_nodes[j - 1], "input");
+ }
+
+ source_node = iters[i].over_nodes[j - 1];
+ }
+ }
+
+ if (fabs (fade_color[3]) > EPSILON)
+ {
+ gegl_node_set (iters[i].color_overlay_node,
+ "value", o->fade_color,
+ "srgb", TRUE,
+ NULL);
+
+ gegl_node_link (source_node, iters[i].color_overlay_node);
+ source_node = iters[i].color_overlay_node;
+ }
+
+ if (fabs (o->fade_opacity - 1.0) > EPSILON)
+ {
+ gegl_node_set (iters[i].opacity_node,
+ "value", o->fade_opacity,
+ NULL);
+
+ gegl_node_link (source_node, iters[i].opacity_node);
+ source_node = iters[i].opacity_node;
+ }
+
+ gegl_node_connect_to (source_node, "output",
+ iters[i].over_nodes[n_transforms - 1], ! o->paste_below ? "aux" :
+ "input");
+ }
+
+ if (i >= o->first_iteration)
+ {
+ gegl_node_connect_to (input, "output",
+ iters[i].over_nodes[n_transforms - 1], ! o->paste_below ? "input" :
+ "aux");
+ }
+ }
+
+ gegl_node_link (iters[0].over_nodes[n_transforms - 1], output);
+ }
+
+ g_strfreev (matrix_strs);
+}
+
+static void
+attach (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Iteration *iters = o->user_data;
+ GeglNode *node = operation->node;
+ gint i;
+ gint j;
+
+ if (! iters)
+ iters = o->user_data = g_new (Iteration, MAX_ITERATIONS + 1);
+
+ for (i = 0; i <= MAX_ITERATIONS; i++)
+ {
+ for (j = 0; j < MAX_TRANSFORMS; j++)
+ {
+ iters[i].transform_nodes[j] =
+ gegl_node_new_child (node,
+ "operation", "gegl:transform",
+ NULL);
+
+ gegl_operation_meta_watch_node (operation,
+ iters[i].transform_nodes[j]);
+ }
+
+ iters[i].color_overlay_node =
+ gegl_node_new_child (node,
+ "operation", "gegl:color-overlay",
+ NULL);
+
+ iters[i].opacity_node =
+ gegl_node_new_child (node,
+ "operation", "gegl:opacity",
+ NULL);
+
+ gegl_operation_meta_watch_nodes (operation,
+ iters[i].color_overlay_node,
+ iters[i].opacity_node,
+ NULL);
+
+ for (j = 0; j < MAX_TRANSFORMS - 1; j++)
+ {
+ iters[i].over_nodes[j] =
+ gegl_node_new_child (node,
+ "operation", "gegl:over",
+ NULL);
+
+ gegl_operation_meta_watch_node (operation, iters[i].over_nodes[j]);
+ }
+ }
+
+ update_graph (operation);
+}
+
+static void
+my_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ set_property (object, property_id, value, pspec);
+
+ update_graph (GEGL_OPERATION (object));
+}
+
+static void
+dispose (GObject *object)
+{
+ GeglProperties *o = GEGL_PROPERTIES (object);
+
+ g_clear_pointer (&o->user_data, g_free);
+
+ G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object);
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+ GObjectClass *object_class;
+ GeglOperationClass *operation_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ operation_class = GEGL_OPERATION_CLASS (klass);
+
+ object_class->dispose = dispose;
+ object_class->set_property = my_set_property;
+
+ operation_class->attach = attach;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:recursive-transform-plus",
+ "title", _("Recursive Transform Plus"),
+ "categories", "map",
+ "description", _("Apply a transformation recursively."),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 14d0de01c..b8ecadd80 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -259,4 +259,5 @@ operations/workshop/hstack.c
operations/workshop/integral-image.c
operations/workshop/linear-sinusoid.c
operations/workshop/rawbayer-load.c
+operations/workshop/recursive-transform-plus.c
operations/workshop/segment-kmeans.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]