[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gimp-developer
Subject:    [Gimp-developer] Some edge filters in GEGL
From:       Victor Oliveira <victormatheus () gmail ! com>
Date:       2011-03-30 16:12:23
Message-ID: AANLkTim1Gouo8RoF9Fn1Ni8y7tEMAaaCUdo09VorZQ3r () mail ! gmail ! com
[Download RAW message or body]

Hello everyone. As a way to learn how GEGL works, I decided to
implement some GIMP plug-ins in it [1,2]. I hope this code can help
someone in the task of making your own plugins.
I've done a sobel and a laplace filter. Both use RGBA float format for
input and output. Basically, I just do a convolution with the
appropriate mask, although in sobel filter I implemented some of the
options of the original GIMP plugin.

There are some differences in the results, but I think this code is
"almost there" to whom wants to port these plugins to GEGL.

[1] http://git.gnome.org/browse/gimp/tree/plug-ins/common/edge-sobel.c
[2] http://git.gnome.org/browse/gimp/tree/plug-ins/common/edge-laplace.c

["edge_filters.patch" (text/x-patch)]

From b81a2e12a9d6f23c9063e0a42f00940ce1791df2 Mon Sep 17 00:00:00 2001
From: Victor Oliveira <victormatheus@gmail.com>
Date: Tue, 29 Mar 2011 18:15:26 -0300
Subject: [PATCH] edge filters

---
 operations/common/edge-laplace.c |  141 +++++++++++++++++++++++++++
 operations/common/edge-sobel.c   |  199 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 340 insertions(+), 0 deletions(-)
 create mode 100644 operations/common/edge-laplace.c
 create mode 100644 operations/common/edge-sobel.c

diff --git a/operations/common/edge-laplace.c b/operations/common/edge-laplace.c
new file mode 100644
index 0000000..912720e
--- /dev/null
+++ b/operations/common/edge-laplace.c
@@ -0,0 +1,141 @@
+/* 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_CHANT_PROPERTIES
+
+#else
+
+#define GEGL_CHANT_TYPE_AREA_FILTER
+#define GEGL_CHANT_C_FILE       "edge-laplace.c"
+
+#include "gegl-chant.h"
+#include <math.h>
+
+#define LAPLACE_RADIUS 1
+
+static void
+edge_laplace (GeglBuffer          *src,
+              const GeglRectangle *src_rect,
+              GeglBuffer          *dst,
+              const GeglRectangle *dst_rect);
+              
+#include <stdio.h>
+
+static void prepare (GeglOperation *operation)
+{
+  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
+  //GeglChantO              *o = GEGL_CHANT_PROPERTIES (operation);
+
+  area->left = area->right = area->top = area->bottom = LAPLACE_RADIUS;
+  gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
+  gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglRectangle compute;
+
+  compute = gegl_operation_get_required_for_output (operation, "input",result);
+
+  edge_laplace (input, &compute, output, result);
+
+  return  TRUE;
+}
+
+static void
+edge_laplace (GeglBuffer          *src,
+              const GeglRectangle *src_rect,
+              GeglBuffer          *dst,
+              const GeglRectangle *dst_rect)
+{
+
+  gint x,y;
+  gint offset;
+  gfloat *src_buf;
+  gfloat *dst_buf;
+
+  gint src_width = src_rect->width;
+
+  src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4);
+  dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 4);
+
+  gegl_buffer_get (src, 1.0, src_rect, babl_format ("RGBA float"), src_buf, \
GEGL_AUTO_ROWSTRIDE); +
+  offset = 0;
+
+  for (y=0; y<dst_rect->height; y++)
+    for (x=0; x<dst_rect->width; x++)
+      {
+
+        gfloat gradient[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+                
+        gint c;
+
+        gint i=x+LAPLACE_RADIUS, j=y+LAPLACE_RADIUS;
+        gfloat *src_pix = src_buf + (i + j * src_width) * 4;
+                
+        for (c=0;c<3;c++)
+          gradient[c] += src_pix[c-4-src_width*4]+     \
src_pix[c-src_width*4]+src_pix[c+4-src_width*4] + \ +                         \
src_pix[c-4]            -8.0f*src_pix[c]            +src_pix[c+4]             + \ +   \
src_pix[c-4+src_width*4]+     src_pix[c+src_width*4]+src_pix[c+4+src_width*4]; +      \
 +
+        //alpha
+        gradient[3] = src_pix[3];
+        
+        for (c=0; c<4;c++)
+          dst_buf[offset*4+c] = gradient[c];
+          
+        offset++;
+      }
+      
+  gegl_buffer_set (dst, dst_rect, babl_format ("RGBA float"), dst_buf,
+                   GEGL_AUTO_ROWSTRIDE);
+  g_free (src_buf);
+  g_free (dst_buf);
+}
+
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class  = GEGL_OPERATION_CLASS (klass);
+  filter_class     = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  filter_class->process   = process;
+  operation_class->prepare = prepare;
+
+  operation_class->name        = "gegl:edge-laplace";
+  operation_class->categories  = "edge-detect";
+  operation_class->description =
+        _("High-resolution edge detection");
+}
+
+#endif
diff --git a/operations/common/edge-sobel.c b/operations/common/edge-sobel.c
new file mode 100644
index 0000000..36d3366
--- /dev/null
+++ b/operations/common/edge-sobel.c
@@ -0,0 +1,199 @@
+/* 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_CHANT_PROPERTIES
+
+gegl_chant_boolean (horizontal,  _("Horizontal"),  TRUE,
+                    _("Horizontal"))
+
+gegl_chant_boolean (vertical,  _("Vertical"),  TRUE,
+                    _("Vertical"))
+  
+gegl_chant_boolean (keep_signal,  _("Keep Signal"),  TRUE,
+                    _("Keep Signal"))
+                  
+#else
+
+#define GEGL_CHANT_TYPE_AREA_FILTER
+#define GEGL_CHANT_C_FILE       "edge-sobel.c"
+
+#include "gegl-chant.h"
+#include <math.h>
+
+#define SOBEL_RADIUS 1
+
+static void
+edge_sobel (GeglBuffer          *src,
+            const GeglRectangle *src_rect,
+            GeglBuffer          *dst,
+            const GeglRectangle *dst_rect,
+            gboolean            horizontal,
+            gboolean            vertical,
+            gboolean            keep_signal);
+
+#include <stdio.h>
+
+static void prepare (GeglOperation *operation)
+{
+  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
+  //GeglChantO              *o = GEGL_CHANT_PROPERTIES (operation);
+
+  area->left = area->right = area->top = area->bottom = SOBEL_RADIUS;
+  gegl_operation_set_format (operation, "input", babl_format ("RGBA float"));
+  gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglChantO   *o = GEGL_CHANT_PROPERTIES (operation);
+  GeglRectangle compute;
+
+  compute = gegl_operation_get_required_for_output (operation, "input",result);
+
+  edge_sobel (input, &compute, output, result, o->horizontal, o->vertical, \
o->keep_signal); +
+  return  TRUE;
+}
+
+inline static gfloat
+RMS(gfloat a, gfloat b)
+{
+  return sqrt(a*a+b*b);
+}
+
+static void
+edge_sobel (GeglBuffer          *src,
+            const GeglRectangle *src_rect,
+            GeglBuffer          *dst,
+            const GeglRectangle *dst_rect,
+            gboolean            horizontal,
+            gboolean            vertical,
+            gboolean            keep_signal)
+{
+
+  gint x,y;
+  gint offset;
+  gfloat *src_buf;
+  gfloat *dst_buf;
+
+  gint src_width = src_rect->width;
+
+  src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4);
+  dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 4);
+
+  gegl_buffer_get (src, 1.0, src_rect, babl_format ("RGBA float"), src_buf, \
GEGL_AUTO_ROWSTRIDE); +
+  offset = 0;
+
+  for (y=0; y<dst_rect->height; y++)
+    for (x=0; x<dst_rect->width; x++)
+      {
+
+        gfloat hor_grad[3] = {0.0f, 0.0f, 0.0f};
+        gfloat ver_grad[3] = {0.0f, 0.0f, 0.0f};
+        gfloat gradient[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+        
+        gfloat *center_pix = src_buf + ((x+SOBEL_RADIUS)+((y+SOBEL_RADIUS) * \
src_width)) * 4; +        
+        gint c;
+
+        if (horizontal)
+        {
+          gint i=x+SOBEL_RADIUS, j=y+SOBEL_RADIUS;
+          gfloat *src_pix = src_buf + (i + j * src_width) * 4;
+                  
+          for (c=0;c<3;c++)
+              hor_grad[c] += -1.0f*src_pix[c-4-src_width*4]+     \
src_pix[c+4-src_width*4] + \ +                             -2.0f*src_pix[c-4]         \
+2.0f*src_pix[c+4]             + \ +                             \
-1.0f*src_pix[c-4+src_width*4]+     src_pix[c+4+src_width*4]; +        }
+        
+        if (vertical)
+        {
+          gint i=x+SOBEL_RADIUS, j=y+SOBEL_RADIUS;
+          gfloat *src_pix = src_buf + (i + j * src_width) * 4;
+                  
+          for (c=0;c<3;c++)
+              ver_grad[c] += \
-1.0f*src_pix[c-4-src_width*4]-2.0f*src_pix[c-src_width*4]-1.0f*src_pix[c+4-src_width*4] \
+ \ +                                   \
src_pix[c-4+src_width*4]+2.0f*src_pix[c+src_width*4]+     src_pix[c+4+src_width*4]; + \
} +
+        if (horizontal && vertical)
+        {
+          for (c=0;c<3;c++)
+            // normalization to [0, 1]
+            gradient[c] = RMS(hor_grad[c],ver_grad[c])/1.41f; 
+        }
+        else
+        {
+          if (keep_signal)
+          {
+            for (c=0;c<3;c++)
+              gradient[c] = hor_grad[c]+ver_grad[c]; 
+          }
+          else
+          {
+            for (c=0;c<3;c++)
+                gradient[c] = fabs(hor_grad[c]+ver_grad[c]); 
+          }
+        }
+
+        //alpha
+        gradient[3] = center_pix[3];
+        
+        for (c=0; c<4;c++)
+          dst_buf[offset*4+c] = gradient[c];
+          
+        offset++;
+      }
+      
+  gegl_buffer_set (dst, dst_rect, babl_format ("RGBA float"), dst_buf,
+                   GEGL_AUTO_ROWSTRIDE);
+  g_free (src_buf);
+  g_free (dst_buf);
+}
+
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationFilterClass *filter_class;
+
+  operation_class  = GEGL_OPERATION_CLASS (klass);
+  filter_class     = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  filter_class->process   = process;
+  operation_class->prepare = prepare;
+
+  operation_class->name        = "gegl:edge-sobel";
+  operation_class->categories  = "edge-detect";
+  operation_class->description =
+        _("Specialized direction-dependent edge detection");
+}
+
+#endif
-- 
1.7.1


["test-edge.c" (text/x-csrc)]

#include <gegl.h>
#include <glib/gprintf.h>
#include <time.h>

gint
main (gint    argc,
      gchar **argv)
{
  g_thread_init (NULL);
  gegl_init (&argc, &argv);  /* initialize the GEGL library */

  {
    /* instantiate a graph */
    GeglNode *gegl = gegl_node_new ();

    GeglNode *load = gegl_node_new_child (gegl,
                     "operation", "gegl:load",
                     "path", argv[1],
                     NULL);

    GeglNode *sobel = gegl_node_new_child (gegl,
                      "operation", "gegl:edge-sobel",
                      "horizontal", TRUE,
                      "vertical", TRUE,
                      "keep_signal", TRUE,
                      NULL);

    GeglNode *laplace = gegl_node_new_child (gegl,
                        "operation", "gegl:edge-laplace",
                        NULL);

    GeglNode *save = gegl_node_new_child (gegl,
                     "operation", "gegl:save",
                     "path", argv[2],
                     NULL);

    GeglNode *save2 = gegl_node_new_child (gegl,
                      "operation", "gegl:save",
                      "path", argv[3],
                      NULL);

    gegl_node_link_many (sobel, save, NULL);
    gegl_node_link_many (laplace, save2, NULL);
    
    gegl_node_link(load, sobel);
    gegl_node_link(load, laplace);
    
    gegl_node_process (save);
    gegl_node_process (save2);
    
    g_object_unref (gegl);
  }

  gegl_exit ();

  return 0;
}


_______________________________________________
Gimp-developer mailing list
Gimp-developer@lists.XCF.Berkeley.EDU
https://lists.XCF.Berkeley.EDU/mailman/listinfo/gimp-developer


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic