[gegl] recursive-transform: add new operation to workshop
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] recursive-transform: add new operation to workshop
- Date: Wed, 28 Feb 2018 23:49:12 +0000 (UTC)
commit faa21840b255e268f384fc0b28a974946a008dee
Author: Ell <ell_se yahoo com>
Date: Wed Feb 28 18:38:24 2018 -0500
recursive-transform: add new operation to workshop
gegl:recursive-transform applies a transformation matrix
recursilvely to an image, pasting the results on top of, or below,
each other. This can be used to create an arbitrarily-deep image-
within-image effect.
The op additionally takes brightness/contrast parameters, which are
applied recursively as well, allowing to attenuate the colors of
deeper iterations.
operations/workshop/Makefile.am | 1 +
operations/workshop/recursive-transform.c | 248 +++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 250 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index d88437d..10784f1 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -23,5 +23,6 @@ op_LTLIBRARIES = \
integral-image.la \
linear-sinusoid.la \
rawbayer-load.la \
+ recursive-transform.la \
segment-kmeans.la \
spherize.la
diff --git a/operations/workshop/recursive-transform.c b/operations/workshop/recursive-transform.c
new file mode 100644
index 0000000..f60eca3
--- /dev/null
+++ b/operations/workshop/recursive-transform.c
@@ -0,0 +1,248 @@
+/* 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 EPSILON 1e-6
+
+#ifdef GEGL_PROPERTIES
+
+property_string (transform, _("Transform"), "")
+ description (_("Transformation matrix, using SVG syntax"))
+
+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_double (contrast, _("Contrast"), 1.0)
+ description (_("Contrast scaling of each transformed image"))
+ value_range (-5.0, 5.0)
+ ui_range (0.5, 1.5)
+
+property_double (brightness, _("Brightness"), 0.0)
+ description (_("Brightness offset of each transformed image"))
+ value_range (-3.0, 3.0)
+ ui_range (-0.5, 0.5)
+
+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
+#define GEGL_OP_C_SOURCE recursive-transform.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+typedef struct
+{
+ GeglNode *transform_node;
+ GeglNode *brightness_contrast_node;
+ GeglNode *over_node;
+} 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;
+ GeglMatrix3 transform;
+ gint i;
+
+ 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++)
+ {
+ gegl_node_disconnect (iters[i].transform_node, "input");
+ gegl_node_disconnect (iters[i].brightness_contrast_node, "input");
+ gegl_node_disconnect (iters[i].over_node, "input");
+ gegl_node_disconnect (iters[i].over_node, "aux");
+ }
+
+ if (o->first_iteration == 0 && o->iterations == 0)
+ return;
+
+ gegl_matrix3_parse_string (&transform, o->transform);
+
+ for (i = o->iterations; i >= 0; i--)
+ {
+ GeglNode *source_node = iters[i].transform_node;
+ GeglMatrix3 matrix;
+ gchar *matrix_str;
+ gint n = o->first_iteration + i;
+ gint j;
+
+ 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_node,
+ "transform", matrix_str,
+ "sampler", o->sampler_type,
+ NULL);
+
+ g_free (matrix_str);
+
+ gegl_node_link (input, iters[i].transform_node);
+
+ if (n > 0 && (fabs (o->brightness - 0.0) > EPSILON ||
+ fabs (o->contrast - 1.0) > EPSILON))
+ {
+ gdouble b = o->brightness;
+ gdouble c = o->contrast;
+
+ if (fabs (c - 1.0) > EPSILON)
+ b *= (pow (c, n) - 1.0) / (c - 1.0);
+ else
+ b *= n;
+
+ c = pow (c, n);
+
+ gegl_node_set (iters[i].brightness_contrast_node,
+ "brightness", b,
+ "contrast", c,
+ NULL);
+
+ gegl_node_link (source_node, iters[i].brightness_contrast_node);
+
+ source_node = iters[i].brightness_contrast_node;
+ }
+
+ gegl_node_connect_to (source_node, "output",
+ iters[i].over_node, ! o->paste_below ? "input" :
+ "aux");
+
+ if (i == 0)
+ {
+ gegl_node_link (iters[i].over_node, output);
+ }
+ else
+ {
+ gegl_node_connect_to (iters[i].over_node, "output",
+ iters[i - 1].over_node, ! o->paste_below ? "aux" :
+ "input");
+ }
+ }
+}
+
+static void
+attach (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Iteration *iters = o->user_data;
+ GeglNode *node = operation->node;
+ gint i;
+
+ if (! iters)
+ iters = o->user_data = g_new (Iteration, MAX_ITERATIONS + 1);
+
+ for (i = 0; i <= MAX_ITERATIONS; i++)
+ {
+ iters[i].transform_node =
+ gegl_node_new_child (node,
+ "operation", "gegl:transform",
+ NULL);
+
+ iters[i].brightness_contrast_node =
+ gegl_node_new_child (node,
+ "operation", "gegl:brightness-contrast",
+ NULL);
+
+ iters[i].over_node =
+ gegl_node_new_child (node,
+ "operation", "gegl:over",
+ NULL);
+
+ gegl_operation_meta_watch_nodes (operation,
+ iters[i].transform_node,
+ iters[i].brightness_contrast_node,
+ iters[i].over_node,
+ NULL);
+ }
+
+ 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",
+ "title", _("Recursive Transform"),
+ "categories", "map",
+ "description", _("Apply a transformation recursively."),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5686468..3b2bf53 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -255,5 +255,6 @@ operations/workshop/hstack.c
operations/workshop/integral-image.c
operations/workshop/linear-sinusoid.c
operations/workshop/rawbayer-load.c
+operations/workshop/recursive-transform.c
operations/workshop/segment-kmeans.c
operations/workshop/spherize.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]