[gegl] operations/workshop: add gegl:median-blur
- From: Thomas Manni <tmanni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations/workshop: add gegl:median-blur
- Date: Tue, 26 May 2015 18:43:37 +0000 (UTC)
commit 9a41c0b0ab47338812e2059074885b5aecf82473
Author: Thomas Manni <thomas manni free fr>
Date: Tue May 26 20:14:10 2015 +0200
operations/workshop: add gegl:median-blur
operations/workshop/Makefile.am | 1 +
operations/workshop/median-blur.c | 414 +++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
3 files changed, 416 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index e8556e6..ccde61e 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -21,6 +21,7 @@ op_LTLIBRARIES = \
ink-simulator.la \
kuwahara.la \
mandelbrot.la \
+ median-blur.la \
rawbayer-load.la \
unpremul.la \
gradient-map.la
diff --git a/operations/workshop/median-blur.c b/operations/workshop/median-blur.c
new file mode 100644
index 0000000..e4f8caf
--- /dev/null
+++ b/operations/workshop/median-blur.c
@@ -0,0 +1,414 @@
+/* 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 2015 Thomas Manni <thomas manni free fr>
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_int (radius, _("Radius"), 3)
+ value_range (1, 100)
+ description (_("Radius of square pixel region (width and height will be radius*2+1)"))
+
+#else
+
+#define GEGL_OP_AREA_FILTER
+#define GEGL_OP_C_SOURCE median-blur.c
+
+#include "gegl-op.h"
+
+#define N_BINS 1024
+
+typedef struct
+{
+ gint elems[3][N_BINS];
+ gint count;
+ gint xmin;
+ gint ymin;
+ gint xmax;
+ gint ymax;
+} Histogram;
+
+typedef enum
+{
+ LEFT_TO_RIGHT,
+ RIGHT_TO_LEFT,
+ TOP_TO_BOTTOM
+} Direction;
+
+static inline gfloat
+histogram_get_median (Histogram *hist, gint component)
+{
+ gint count = hist->count;
+ gint i;
+ gint sum = 0;
+
+ count = (count + 1) / 2;
+
+ i = 0;
+ while ((sum += hist->elems[component][i]) < count)
+ i++;
+
+ return (gfloat) i / (gfloat) N_BINS;
+}
+
+static inline void
+histogram_add_val (Histogram *hist,
+ const gfloat *src,
+ GeglRectangle *rect,
+ gint bpp,
+ gint x,
+ gint y)
+{
+ const gint pos = (x + y * rect->width) * bpp;
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat value = *(src + pos + c);
+ gint idx = (gint) (value * (N_BINS - 1));
+ hist->elems[c][idx]++;
+ }
+ hist->count++;
+}
+
+static inline void
+histogram_del_val (Histogram *hist,
+ const gfloat *src,
+ GeglRectangle *rect,
+ gint bpp,
+ gint x,
+ gint y)
+{
+ const gint pos = (x + y * rect->width) * bpp;
+ gint c;
+
+ for (c = 0; c < 3; c++)
+ {
+ gfloat value = *(src + pos + c);
+ gint idx = (gint) (value * (N_BINS - 1));
+ hist->elems[c][idx]--;
+ }
+ hist->count--;
+}
+
+static inline void
+histogram_add_vals (Histogram *hist,
+ const gfloat *src,
+ GeglRectangle *rect,
+ gint bpp,
+ gint xmin,
+ gint ymin,
+ gint xmax,
+ gint ymax)
+{
+ gint x;
+ gint y;
+
+ if (xmin > xmax)
+ return;
+
+ for (y = ymin; y <= ymax; y++)
+ {
+ for (x = xmin; x <= xmax; x++)
+ {
+ histogram_add_val (hist, src, rect, bpp, x, y);
+ }
+ }
+}
+
+static inline void
+histogram_del_vals (Histogram *hist,
+ const gfloat *src,
+ GeglRectangle *rect,
+ gint bpp,
+ gint xmin,
+ gint ymin,
+ gint xmax,
+ gint ymax)
+{
+ gint x;
+ gint y;
+
+ if (xmin > xmax)
+ return;
+
+ for (y = ymin; y <= ymax; y++)
+ {
+ for (x = xmin; x <= xmax; x++)
+ {
+ histogram_del_val (hist, src, rect, bpp, x, y);
+ }
+ }
+}
+
+static inline void
+histogram_update (Histogram *hist,
+ const gfloat *src,
+ GeglRectangle *rect,
+ gint bpp,
+ gint xmin,
+ gint ymin,
+ gint xmax,
+ gint ymax,
+ Direction dir)
+{
+ switch (dir)
+ {
+ case LEFT_TO_RIGHT:
+ histogram_del_vals (hist, src, rect, bpp,
+ hist->xmin, hist->ymin,
+ hist->xmin, hist->ymax);
+
+ histogram_add_vals (hist, src, rect, bpp,
+ xmax, ymin,
+ xmax, ymax);
+ break;
+
+ case RIGHT_TO_LEFT:
+ histogram_del_vals (hist, src, rect, bpp,
+ hist->xmax, hist->ymin,
+ hist->xmax, hist->ymax);
+
+ histogram_add_vals (hist, src, rect, bpp,
+ xmin, ymin,
+ xmin, ymax);
+ break;
+
+ case TOP_TO_BOTTOM:
+ histogram_del_vals (hist, src, rect, bpp,
+ hist->xmin, hist->ymin,
+ hist->xmax, hist->ymin);
+
+ histogram_add_vals (hist, src, rect, bpp,
+ xmin, ymax,
+ xmax, ymax);
+ break;
+ }
+
+ hist->xmin = xmin;
+ hist->ymin = ymin;
+ hist->xmax = xmax;
+ hist->ymax = ymax;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *in_format = gegl_operation_get_source_format (operation, "input");
+ const Babl *format = babl_format ("RGB float");;
+
+ area->left =
+ area->right =
+ area->top =
+ area->bottom = o->radius;
+
+ if (in_format)
+ {
+ if (babl_format_has_alpha (in_format))
+ format = babl_format ("RGBA float");
+ }
+
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglRectangle result = { 0, 0, 0, 0 };
+ GeglRectangle *in_rect;
+
+ in_rect = gegl_operation_source_get_bounding_box (operation, "input");
+ if (in_rect)
+ {
+ result = *in_rect;
+ }
+
+ return result;
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = gegl_operation_get_format (operation, "input");
+ gint n_components = babl_format_get_n_components (format);
+ gboolean has_alpha = babl_format_has_alpha (format);
+
+ gfloat *src_buf;
+ gfloat *dst_buf;
+ gint n_pixels;
+ GeglRectangle src_rect;
+
+ Histogram *hist;
+ Direction dir;
+
+ gint src_x, src_y;
+ gint dst_x, dst_y;
+ gint dst_idx, src_idx;
+ gint xmin, ymin, xmax, ymax;
+
+ src_rect = gegl_operation_get_required_for_output (operation, "input", roi);
+ n_pixels = roi->width * roi->height;
+ dst_buf = g_new0 (gfloat, n_pixels * n_components);
+ src_buf = g_new0 (gfloat, src_rect.width * src_rect.height * n_components);
+
+ gegl_buffer_get (input, &src_rect, 1.0, format, src_buf,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+ hist = g_slice_new0 (Histogram);
+
+ dst_x = 0;
+ dst_y = 0;
+ src_x = o->radius;
+ src_y = o->radius;
+
+ /* compute the first window */
+
+ hist->xmin = src_x - o->radius;
+ hist->ymin = src_y - o->radius;
+ hist->xmax = src_x + o->radius;
+ hist->ymax = src_y + o->radius;
+
+ histogram_add_vals (hist, src_buf, &src_rect, n_components,
+ hist->xmin, hist->ymin,
+ hist->xmax, hist->ymax);
+
+ dst_idx = (dst_x + dst_y * roi->width) * n_components;
+
+ dst_buf[dst_idx] = histogram_get_median (hist, 0);
+ dst_buf[dst_idx + 1] = histogram_get_median (hist, 1);
+ dst_buf[dst_idx + 2] = histogram_get_median (hist, 2);
+
+ if (has_alpha)
+ {
+ src_idx = (src_x + src_y * src_rect.width) * n_components;
+ dst_buf[dst_idx + 3] = src_buf[src_idx + 3];
+ }
+
+ n_pixels--;
+ dir = LEFT_TO_RIGHT;
+
+ while (n_pixels--)
+ {
+ /* move the src coords based on current direction and positions */
+ if (dir == LEFT_TO_RIGHT)
+ {
+ if (dst_x != roi->width - 1)
+ {
+ src_x++;
+ dst_x++;
+ }
+ else
+ {
+ src_y++;
+ dst_y++;
+ dir = TOP_TO_BOTTOM;
+ }
+ }
+ else if (dir == TOP_TO_BOTTOM)
+ {
+ if (dst_x == 0)
+ {
+ src_x++;
+ dst_x++;
+ dir = LEFT_TO_RIGHT;
+ }
+ else
+ {
+ src_x--;
+ dst_x--;
+ dir = RIGHT_TO_LEFT;
+ }
+ }
+ else if (dir == RIGHT_TO_LEFT)
+ {
+ if (dst_x != 0)
+ {
+ src_x--;
+ dst_x--;
+ }
+ else
+ {
+ src_y++;
+ dst_y++;
+ dir = TOP_TO_BOTTOM;
+ }
+ }
+
+ xmin = src_x - o->radius;
+ ymin = src_y - o->radius;
+ xmax = src_x + o->radius;
+ ymax = src_y + o->radius;
+
+ histogram_update (hist, src_buf, &src_rect, n_components,
+ xmin, ymin, xmax, ymax, dir);
+
+ dst_idx = (dst_x + dst_y * roi->width) * n_components;
+
+ dst_buf[dst_idx] = histogram_get_median (hist, 0);
+ dst_buf[dst_idx + 1] = histogram_get_median (hist, 1);
+ dst_buf[dst_idx + 2] = histogram_get_median (hist, 2);
+
+ if (has_alpha)
+ {
+ src_idx = (src_x + src_y * src_rect.width) * n_components;
+ dst_buf[dst_idx + 3] = src_buf[src_idx + 3];
+ }
+ }
+
+ gegl_buffer_set (output, roi, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);
+
+ g_free (src_buf);
+ g_free (dst_buf);
+ g_slice_free (Histogram, hist);
+
+ return TRUE;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *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->get_bounding_box = get_bounding_box;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:median-blur",
+ "title", _("Median Blur"),
+ "categories", "blur",
+ "description", _("Blur resulting from computing the median color of in a square neighbourhood."),
+ NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ad59544..a32b2cb 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -227,4 +227,5 @@ operations/workshop/hstack.c
operations/workshop/ink-simulator.c
operations/workshop/kuwahara.c
operations/workshop/mandelbrot.c
+operations/workshop/median-blur.c
operations/workshop/rawbayer-load.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]