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
From b81a2e12a9d6f23c9063e0a42f00940ce1791df2 Mon Sep 17 00:00:00 2001 From: Victor Oliveira <victormatheus@xxxxxxxxx> 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
#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@xxxxxxxxxxxxxxxxxxxxxx https://lists.XCF.Berkeley.EDU/mailman/listinfo/gimp-developer