[gegl] connected-components: new op in workshop



commit 6f66bf950c436554d9112b47a820bfc4ce7194cd
Author: Ell <ell_se yahoo com>
Date:   Wed Nov 21 16:53:43 2018 -0500

    connected-components: new op in workshop
    
    The gegl:connected-components op fills each connected region of
    the input, separated from the rest of the input by a parameterized
    color, with a unique color.

 operations/workshop/Makefile.am            |   1 +
 operations/workshop/connected-components.c | 298 +++++++++++++++++++++++++++++
 po/POTFILES.in                             |   1 +
 3 files changed, 300 insertions(+)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index e01d2cc91..edc6a5ff5 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -12,6 +12,7 @@ opdir = $(ext_dir)
 op_LTLIBRARIES = \
        bayer-matrix.la \
        bilateral-filter-fast.la \
+       connected-components.la \
        demosaic-bimedian.la \
        demosaic-simple.la \
        ditto.la \
diff --git a/operations/workshop/connected-components.c b/operations/workshop/connected-components.c
new file mode 100644
index 000000000..edefe0426
--- /dev/null
+++ b/operations/workshop/connected-components.c
@@ -0,0 +1,298 @@
+/* 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 <https://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2018 Ell
+ */
+
+#define GEGL_ITERATOR2_API
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_color (separator, _("Separator"), "black")
+  description (_("Component separator color"))
+
+property_boolean (invert, _("Invert"), FALSE)
+  description (_("Invert the separator region"))
+
+property_double (base, _("Base"), 0.0)
+  description (_("Base index"))
+  value_range (-G_MAXDOUBLE, G_MAXDOUBLE)
+  ui_range    (0.0, 1.0)
+
+property_double (step, _("Step"), 1.0)
+  description (_("Index step"))
+  value_range (-G_MAXDOUBLE, G_MAXDOUBLE)
+  ui_range    (0.0, 1.0)
+
+property_boolean (normalize, _("Normalize"), TRUE)
+  description (_("Normalize output to the range [base,base + step]"))
+
+property_boolean (linear, _("Linear"), FALSE)
+  description (_("Linear output"))
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME     connected_components
+#define GEGL_OP_C_SOURCE connected-components.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *roi)
+{
+  return gegl_operation_get_bounding_box (operation);
+}
+
+static GeglRectangle
+get_invalidated_by_change (GeglOperation       *operation,
+                           const gchar         *input_pad,
+                           const GeglRectangle *roi)
+{
+  return gegl_operation_get_bounding_box (operation);
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  return gegl_operation_get_bounding_box (operation);
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+
+  gegl_operation_set_format (operation, "output",
+                             o->linear ? babl_format ("Y float") :
+                                         babl_format ("Y' float"));
+}
+
+static gint
+get_target_index (GArray *indices,
+                  gint    index)
+{
+  gint target = g_array_index (indices, gint32, index);
+
+  if (target != index)
+    {
+      target = get_target_index (indices, target);
+
+      g_array_index (indices, gint32, index) = target;
+    }
+
+  return target;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *roi,
+         gint                 level)
+{
+  GeglProperties     *o             = GEGL_PROPERTIES (operation);
+  gboolean            invert        = o->invert;
+  const Babl         *input_format  = gegl_buffer_get_format (input);
+  const Babl         *output_format = gegl_buffer_get_format (output);
+  gint                input_bpp     = babl_format_get_bytes_per_pixel (
+                                        input_format);
+  guint8             *in_row;
+  gint32             *out_rows[2];
+  guint8              separator[64];
+  GArray             *indices;
+  gint                n_indices;
+  gint32              index;
+  GeglBufferIterator *iter;
+  gint                y;
+  gint                i;
+
+  G_STATIC_ASSERT (sizeof (gint32) == sizeof (gfloat));
+
+  if (input_bpp > sizeof (separator))
+    return FALSE;
+
+  gegl_color_get_pixel (o->separator, input_format, separator);
+
+  indices = g_array_new (FALSE, FALSE, sizeof (gint32));
+
+  in_row      = g_malloc (input_bpp * roi->width);
+  out_rows[0] = g_new (gint32, roi->width);
+  out_rows[1] = g_new (gint32, roi->width);
+
+  g_array_append_val (indices, (gint32) {0});
+
+  n_indices = 1;
+
+  for (y = 0; y < roi->height; y++)
+    {
+      guint8       *in   = in_row;
+      const gint32 *out0 = out_rows[y       % 2];
+      gint32       *out1 = out_rows[(y + 1) % 2];
+      gint          x;
+
+      gegl_buffer_get (input,
+                       GEGL_RECTANGLE (roi->x, roi->y + y, roi->width, 1), 1.0,
+                       input_format, in, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+      for (x = 0; x < roi->width; x++)
+        {
+          index = 0;
+
+          if ((! memcmp (in, separator, input_bpp)) == invert)
+            {
+              gint index1 = 0;
+              gint index2 = 0;
+
+              if (x > 0)
+                index1 = out1[-1];
+
+              if (y > 0)
+                index2 = out0[0];
+
+              if (index1 && index2 && index1 != index2)
+                {
+                  index1 = get_target_index (indices, index1);
+                  index2 = get_target_index (indices, index2);
+
+                  index = MIN (index1, index2);
+
+                  if (index1 != index2)
+                    {
+                      g_array_index (indices, gint32,
+                                     MAX (index1, index2)) = index;
+
+                      n_indices--;
+                    }
+                }
+              else
+                {
+                  index = MAX (index1, index2);
+
+                  if (! index)
+                    {
+                      index = indices->len;
+
+                      g_array_append_val (indices, index);
+
+                      n_indices++;
+                    }
+                }
+            }
+
+          *out1 = index;
+
+          in += input_bpp;
+
+          out0++;
+          out1++;
+        }
+
+      gegl_buffer_set (output,
+                       GEGL_RECTANGLE (roi->x, roi->y + y, roi->width, 1), 0,
+                       output_format, out1 - roi->width, GEGL_AUTO_ROWSTRIDE);
+    }
+
+  g_free (in_row);
+  g_free (out_rows[0]);
+  g_free (out_rows[1]);
+
+  n_indices = MAX (n_indices - 1, 1);
+
+  index = 0;
+
+  for (i = 0; i < indices->len; i++)
+    {
+      gint   j = g_array_index (indices, gint32, i);
+      gfloat v;
+
+      if (j == i)
+        {
+          if (o->normalize)
+            v = o->base + o->step * index++ / n_indices;
+          else
+            v = o->base + o->step * index++;
+        }
+      else
+        {
+          v = g_array_index (indices, gfloat, j);
+        }
+
+      g_array_index (indices, gfloat, i) = v;
+    }
+
+  iter = gegl_buffer_iterator_new (output, roi, 0, output_format,
+                                   GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
+
+  while (gegl_buffer_iterator_next (iter))
+    {
+      gint32 *data = iter->items[0].data;
+
+      for (i = 0; i < iter->length; i++)
+        {
+          *(gfloat *) data = g_array_index (indices, gfloat, *data);
+
+          data++;
+        }
+    }
+
+  g_array_unref (indices);
+
+  return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  operation_class->get_required_for_output   = get_required_for_output;
+  operation_class->get_invalidated_by_change = get_invalidated_by_change;
+  operation_class->get_cached_region         = get_cached_region;
+  operation_class->prepare                   = prepare;
+
+  operation_class->threaded                  = FALSE;
+  operation_class->want_in_place             = TRUE;
+
+  filter_class->process                      = process;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name",           "gegl:connected-components",
+    "title",          _("Connected Components"),
+    "categories",     "map",
+    "reference-chain", "vector-stroke d='                           "
+                       "  M  0  0 l 100 0 l 0 100 l -100 0 l0 -100  "
+                       "  M 50 50 l 100 0 l 0 100 l -100 0 l0 -100' "
+                       "connected-components                        ",
+    "reference-hash", "b2670884d959e1448d9001a5a1855b55",
+    "description",    _("Fills each connected region of the input, separated "
+                        "from the rest of the input by a given color, with a "
+                        "unique color."),
+    NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8092da800..b1f4b71e6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -249,6 +249,7 @@ operations/transform/translate.c
 operations/workshop/aces-rrt.c
 operations/workshop/bayer-matrix.c
 operations/workshop/bilateral-filter-fast.c
+operations/workshop/connected-components.c
 operations/workshop/demosaic-bimedian.c
 operations/workshop/demosaic-simple.c
 operations/workshop/ditto.c


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