[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