[gegl] sobel and laplace gegl filters



commit 10a6ec2b2c3d2213d6f9950363eb863f44d9d1bf
Author: Victor Oliveira <victormatheus gmail com>
Date:   Tue Apr 19 14:03:14 2011 -0300

    sobel and laplace gegl filters
    
    sobel and laplace filters using GEGL
    based on the original GIMP plugins
    
    * regression tests for sobel and laplace

 operations/common/edge-laplace.c    |  241 +++++++++++++++++++++++++++++++++++
 operations/common/edge-sobel.c      |  201 +++++++++++++++++++++++++++++
 tests/compositions/Makefile.am      |    4 +-
 tests/compositions/edge-laplace.xml |   12 ++
 tests/compositions/edge-sobel.xml   |   14 ++
 5 files changed, 471 insertions(+), 1 deletions(-)
---
diff --git a/operations/common/edge-laplace.c b/operations/common/edge-laplace.c
new file mode 100644
index 0000000..deae76c
--- /dev/null
+++ b/operations/common/edge-laplace.c
@@ -0,0 +1,241 @@
+/* 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 2011 Victor Oliveira <victormatheus gmail com>
+ */
+ 
+#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
+minmax  (gfloat  x1,
+	 gfloat  x2,
+	 gfloat  x3,
+	 gfloat  x4,
+	 gfloat  x5,
+	 gfloat *min_result,
+	 gfloat *max_result)
+{
+  gfloat min1, min2, max1, max2;
+
+  if (x1 > x2)
+    {
+      max1 = x1;
+      min1 = x2;
+    }
+  else
+    {
+      max1 = x2;
+      min1 = x1;
+    }
+
+  if (x3 > x4)
+    {
+      max2 = x3;
+      min2 = x4;
+    }
+  else
+    {
+      max2 = x4;
+      min2 = x3;
+    }
+
+  if (min1 < min2)
+    *min_result = fminf (min1, x5);
+  else
+    *min_result = fminf (min2, x5);
+
+  if (max1 > max2)
+    *max_result = fmaxf (max1, x5);
+  else
+    *max_result = fmaxf (max2, x5);
+}
+
+
+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 *temp_buf;
+  gfloat *dst_buf;
+
+  gint src_width = src_rect->width;
+
+  src_buf  = g_new0 (gfloat, src_rect->width * src_rect->height * 4);
+  temp_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);
+
+  for (y=0; y<dst_rect->height; y++)
+    for (x=0; x<dst_rect->width; x++)
+      {
+        gfloat *src_pix;
+        
+        gfloat gradient[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+                
+        gint c;
+
+        gfloat minval, maxval;
+        
+        gint i=x+LAPLACE_RADIUS, j=y+LAPLACE_RADIUS;
+        offset = i + j * src_width;
+        src_pix = src_buf + offset * 4;
+        
+        for (c=0;c<3;c++)
+        {
+          minmax (src_pix[c-src_width*4], src_pix[c+src_width*4],
+                  src_pix[c-4], src_pix[c+4], src_pix[c],
+                  &minval, &maxval); /* four-neighbourhood */
+          
+          gradient[c] = 0.5f * fmaxf((maxval-src_pix[c]), (src_pix[c]-minval));
+          
+          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]) > 0.0f?
+                        gradient[c] : -1.0f*gradient[c];
+        }
+        
+        //alpha
+        gradient[3] = src_pix[3];
+        
+        for (c=0; c<4;c++)
+          temp_buf[offset*4+c] = gradient[c];
+          
+      }
+  
+  //1-pixel edges
+
+  offset = 0;
+
+  for (y=0; y<dst_rect->height; y++)
+    for (x=0; x<dst_rect->width; x++)
+      {
+
+        gfloat value[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+        
+        gint c;
+
+        gint i=x+LAPLACE_RADIUS, j=y+LAPLACE_RADIUS;
+        gfloat *src_pix = temp_buf + (i + j * src_width) * 4;
+        
+        for (c=0;c<3;c++)
+        {
+          gfloat current = src_pix[c];
+          current = ((current > 0.0f) &&
+                     (src_pix[c-4-src_width*4] < 0.0f ||
+                      src_pix[c+4-src_width*4] < 0.0f ||
+                      src_pix[c  -src_width*4] < 0.0f ||
+                      src_pix[c-4+src_width*4] < 0.0f ||
+                      src_pix[c+4+src_width*4] < 0.0f ||
+                      src_pix[   +src_width*4] < 0.0f ||
+                      src_pix[c-4            ] < 0.0f ||
+                      src_pix[c+4            ] < 0.0f))?
+                    current : 0.0f;
+                    
+          value[c] = current;
+        }
+        
+        //alpha
+        value[3] = src_pix[3];
+        
+        for (c=0; c<4;c++)
+          dst_buf[offset*4+c] = value[c];
+          
+        offset++;
+      }
+
+  gegl_buffer_set (dst, dst_rect, babl_format ("RGBA float"), dst_buf,
+                   GEGL_AUTO_ROWSTRIDE);
+  g_free (src_buf);
+  g_free (temp_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..cfb3d9f
--- /dev/null
+++ b/operations/common/edge-sobel.c
@@ -0,0 +1,201 @@
+/* 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 2011 Victor Oliveira <victormatheus gmail com>
+ */
+
+#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 sqrtf(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] = fabsf(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
diff --git a/tests/compositions/Makefile.am b/tests/compositions/Makefile.am
index 9f6f1f4..3dd151f 100644
--- a/tests/compositions/Makefile.am
+++ b/tests/compositions/Makefile.am
@@ -51,7 +51,9 @@ TESTS = \
   run-transform.xml.sh                 \
   run-upsharptest.xml.sh               \
   run-upsizetest.xml.sh                \
-  run-upsmoothtest.xml.sh
+  run-upsmoothtest.xml.sh              \
+  run-edge-sobel.xml.sh                \
+  run-edge-laplace.xml.sh
 
 # Conditional tests
 if HAVE_JASPER
diff --git a/tests/compositions/edge-laplace.xml b/tests/compositions/edge-laplace.xml
new file mode 100644
index 0000000..e13068c
--- /dev/null
+++ b/tests/compositions/edge-laplace.xml
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:edge-laplace'>
+    <params>
+    </params>
+  </node>
+  <node operation='gegl:load'>
+    <params>
+      <param name='path'>data/duck.png</param>
+    </params>
+  </node>
+</gegl>
diff --git a/tests/compositions/edge-sobel.xml b/tests/compositions/edge-sobel.xml
new file mode 100644
index 0000000..04fdb12
--- /dev/null
+++ b/tests/compositions/edge-sobel.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:edge-sobel'>
+    <params>
+      <param name='horizontal'>1</param>
+      <param name='vertical'>1</param>
+    </params>
+  </node>
+  <node operation='gegl:load'>
+    <params>
+      <param name='path'>data/duck.png</param>
+    </params>
+  </node>
+</gegl>



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