[gegl] workshop: add color-warp op



commit 542ebe5ff8d22d0089cce46cdd40d756ddcdf3b0
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Dec 4 00:26:50 2014 +0000

    workshop: add color-warp op

 operations/workshop/Makefile.am  |    1 +
 operations/workshop/color-warp.c |  290 ++++++++++++++++++++++++++++++++++++++
 po/POTFILES.in                   |    1 +
 3 files changed, 292 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 8e273ea..3e2c3d2 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -14,6 +14,7 @@ op_LTLIBRARIES =    \
        box-min.la \
        box-percentile.la \
        buffer-cache.la \
+       color-warp.la \
        demosaic-bimedian.la \
        demosaic-simple.la \
        disc-percentile.la \
diff --git a/operations/workshop/color-warp.c b/operations/workshop/color-warp.c
new file mode 100644
index 0000000..4a8c4a8
--- /dev/null
+++ b/operations/workshop/color-warp.c
@@ -0,0 +1,290 @@
+/* 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/>.
+ *
+ * 2014 (c) Øyvind Kolås pippin gimp org
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_color (from_0, _("From 0"), "black")
+property_color (to_0, _("To 0"), "black")
+property_double (weight_0, _("color neighbourhood of influence 0"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_1, _("From 1"), "black")
+property_color (to_1, _("To 1"), "black")
+property_double (weight_1, _("color neighbourhood of influence 1"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_2, _("From 2"), "black")
+property_color (to_2, _("To 2"), "black")
+property_double (weight_2, _("color neighbourhood of influence 2"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_3, _("From 3"), "black")
+property_color (to_3, _("To 3"), "black")
+property_double (weight_3, _("color neighbourhood of influence 3"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_4, _("From 4"), "black")
+property_color (to_4, _("To 4"), "black")
+property_double (weight_4, _("color neighbourhood of influence 4"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_5, _("From 5"), "black")
+property_color (to_5, _("To 5"), "black")
+property_double (weight_5, _("color neighbourhood of influence 5"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_6, _("From 6"), "black")
+property_color (to_6, _("To 6"), "black")
+property_double (weight_6, _("color neighbourhood of influence 6"), 100.0)
+             ui_range (0.0, 220.0)
+property_color (from_7, _("From 7"), "black")
+property_color (to_7, _("To 7"), "black")
+property_double (weight_7, _("color neighbourhood of influence 7"), 100.0)
+             ui_range (0.0, 220.0)
+property_double (weight, _("global weight scale"), 1.0)
+             ui_range (0.0, 1.0)
+
+#else
+
+#define GEGL_OP_POINT_FILTER
+#define GEGL_OP_C_FILE "color-warp.c"
+
+#include "gegl-op.h"
+#include <math.h>
+
+#define MAX_PAIRS 1024
+
+typedef struct CoordPair {
+  float a[3];
+  float b[3];
+  float weight;
+} CoordPair;
+
+typedef struct CoordWarp {
+  CoordPair pair[MAX_PAIRS];
+  int count;
+} CoordWarp;
+
+static CoordWarp *cw_new (void)
+{
+  CoordWarp *cw;
+  cw = calloc (sizeof (CoordWarp), 1);
+  return cw;
+}
+
+static void cw_clear_pairs (CoordWarp   *cw)
+{
+  cw->count = 0;
+}
+
+static void cw_destroy (CoordWarp   *cw)
+{
+  free (cw);
+}
+
+static void cw_add_pair (CoordWarp   *cw,
+                         const float *coord_a,
+                         const float *coord_b,
+                         float        weight)
+{
+  int d;
+  if (cw->count +1 >= MAX_PAIRS)
+    return;
+  for (d = 0; d < 3; d++)
+    cw->pair[cw->count].a[d] = coord_a[d];
+  for (d = 0; d < 3; d++)
+    cw->pair[cw->count].b[d] = coord_b[d];
+  cw->pair[cw->count].weight = weight;
+  cw->count++;
+}
+
+static inline float sq_dist (CoordWarp *cw, const float *coord_a, const float *coord_b)
+{
+  int d;
+  float sq_sum = 0;
+  for (d = 0; d < 3; d++)
+    sq_sum += (coord_b[d] - coord_a[d]) * (coord_b[d] - coord_a[d]);
+  return sq_sum;
+}
+
+static inline float calc_weight (float dist, float lowest_dist, float coord_weight)
+{
+  float influence = coord_weight;
+  return expf (-dist / influence);
+}
+
+static void cw_map (CoordWarp   *cw,
+                    const float *coord_a,
+                    float       *coord_b)
+{
+  int i;
+  int lowest_dist_no = 0;
+  double lowest_dist = 12345678900000.0;
+  double sum_wc = 0.0;
+  float warp[3] = {0,};
+
+  for (i = 0; i < cw->count; i++)
+  {
+    float sqd = sq_dist (cw, coord_a, cw->pair[i].a);
+    if (sqd < lowest_dist)
+    {
+      lowest_dist = sqd;
+      lowest_dist_no = i;
+    }
+  }
+
+  for (i = 0; i < cw->count; i++)
+  {
+    float sqd = sq_dist (cw, coord_a, cw->pair[i].a);
+    sum_wc += lowest_dist / sqd;
+  }
+
+  if (lowest_dist > 0.0)
+  {
+    for (i = 0; i < cw->count; i++)
+    {
+      int d;
+      float sqd = sq_dist (cw, coord_a, cw->pair[i].a);
+      float weight = calc_weight (sqd, lowest_dist, cw->pair[i].weight);
+      weight = weight / sum_wc;
+
+      for (d = 0; d < 3; d++)
+        warp[d] += (cw->pair[i].a[d] - cw->pair[i].b[d]) * weight;
+    }
+  }
+  else
+  {
+    int d;
+    for (d = 0; d < 3; d++)
+      warp[d] = (cw->pair[lowest_dist_no].a[d] - cw->pair[lowest_dist_no].b[d]);
+  }
+
+  {
+    int d;
+    for (d = 0; d < 3; d++)
+      coord_b[d] = coord_a[d] - warp[d];
+  }
+}
+
+static void maybe_add_pair (CoordWarp *cw,
+                            GeglColor *colorA,
+                            GeglColor *colorB,
+                            float      weight)
+{
+  gfloat from[4];
+  gfloat to[4];
+  const Babl *colorformat = babl_format("CIE Lab float");
+  gegl_color_get_pixel (colorA, colorformat, from);
+  gegl_color_get_pixel (colorB, colorformat, to);
+  if (from[0] == 0.0 &&
+      from[1] == 0.0 &&
+      from[2] == 0.0 &&
+      to[0] == 0.0 &&
+      to[1] == 0.0 &&
+      to[2] == 0.0)
+  {
+  }
+  else
+  {
+    cw_add_pair (cw, from, to, weight);
+  }
+}
+
+static void prepare (GeglOperation *operation)
+{
+  CoordWarp *cw;
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+  const Babl *format = babl_format ("CIE Lab float");
+  gegl_operation_set_format (operation, "input", format);
+  gegl_operation_set_format (operation, "output", format);
+
+  if (o->user_data == NULL)
+    o->user_data = cw_new ();
+  cw = o->user_data;
+
+  cw_clear_pairs (cw);
+  maybe_add_pair (cw, o->from_0, o->to_0, o->weight * o->weight_0);
+  maybe_add_pair (cw, o->from_1, o->to_1, o->weight * o->weight_1);
+  maybe_add_pair (cw, o->from_2, o->to_2, o->weight * o->weight_2);
+  maybe_add_pair (cw, o->from_3, o->to_3, o->weight * o->weight_3);
+  maybe_add_pair (cw, o->from_4, o->to_4, o->weight * o->weight_4);
+  maybe_add_pair (cw, o->from_5, o->to_5, o->weight * o->weight_5);
+  maybe_add_pair (cw, o->from_6, o->to_6, o->weight * o->weight_6);
+  maybe_add_pair (cw, o->from_7, o->to_7, o->weight * o->weight_7);
+}
+
+static void
+finalize (GObject *object)
+{
+  GeglProperties *o = GEGL_PROPERTIES (object);
+
+  if (o->user_data)
+    {
+      cw_destroy (o->user_data);
+      o->user_data = NULL;
+    }
+
+  G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+}
+
+static gboolean
+process (GeglOperation       *op,
+         void                *in_buf,
+         void                *out_buf,
+         glong                n_pixels,
+         const GeglRectangle *roi,
+         gint                 level)
+{
+  GeglProperties *o         = GEGL_PROPERTIES (op);
+  gfloat         *in_pixel  = in_buf;
+  gfloat         *out_pixel = out_buf;
+  CoordWarp      *cw        = o->user_data;
+
+  in_pixel  = in_buf;
+  out_pixel = out_buf;
+
+  while (n_pixels--)
+    {
+      cw_map (cw, in_pixel, out_pixel);
+      in_pixel  += 3;
+      out_pixel += 3;
+    }
+
+  return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+  GObjectClass                  *object_class;
+  GeglOperationClass            *operation_class;
+  GeglOperationPointFilterClass *point_filter_class;
+
+  object_class       = G_OBJECT_CLASS (klass);
+  operation_class    = GEGL_OPERATION_CLASS (klass);
+  point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
+  object_class->finalize      = finalize;
+  operation_class->prepare    = prepare;
+  point_filter_class->process = process;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name",        "gegl:color-warp",
+    "title",       _("Color warp"),
+    "categories",  "color",
+    "description", _("Warps the colors of an image between colors with weighted distortion factors."),
+    NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8c740f9..63497cb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -199,6 +199,7 @@ operations/workshop/box-max.c
 operations/workshop/box-min.c
 operations/workshop/box-percentile.c
 operations/workshop/buffer-cache.c
+operations/workshop/color-warp.c
 operations/workshop/demosaic-bimedian.c
 operations/workshop/demosaic-simple.c
 operations/workshop/disc-percentile.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]