[gegl] sobel and laplace gegl filters
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] sobel and laplace gegl filters
- Date: Tue, 19 Apr 2011 17:38:28 +0000 (UTC)
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]