[gegl] wavelet-blur: use a 1d filter to perform horizontal and vertical steps
- From: Thomas Manni <tmanni src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] wavelet-blur: use a 1d filter to perform horizontal and vertical steps
- Date: Mon, 25 Sep 2017 19:12:45 +0000 (UTC)
commit 08e7c8ee3f8b5f4d16ca45dcc98276d9cb43f24e
Author: Thomas Manni <thomas manni free fr>
Date: Mon Sep 25 19:39:09 2017 +0100
wavelet-blur: use a 1d filter to perform horizontal and vertical steps
Wavelet-blur is now a meta operation, using a new wavelet-blur-1d
operation which implement the one-dimensional filter.
Use ABYSS_CLAMP policy to avoid signal degradation at buffer boundaries
when used in a "wavelet decompose" context.
Update reference hash.
operations/common/Makefile.am | 3 +-
operations/common/wavelet-blur-1d.c | 281 +++++++++++++++++++++++++++++++++++
operations/common/wavelet-blur.c | 254 ++++----------------------------
3 files changed, 309 insertions(+), 229 deletions(-)
---
diff --git a/operations/common/Makefile.am b/operations/common/Makefile.am
index 1626c86..4fc847f 100644
--- a/operations/common/Makefile.am
+++ b/operations/common/Makefile.am
@@ -11,7 +11,7 @@ LIBS = $(op_libs)
opdir = $(ext_dir)
op_LTLIBRARIES = \
- gegl-common.la
+ gegl-common.la
gegl_common_la_SOURCES =\
alien-map.c \
@@ -157,6 +157,7 @@ gegl_common_la_SOURCES =\
waterpixels.c \
watershed-transform.c \
waves.c \
+ wavelet-blur-1d.c \
wavelet-blur.c \
weighted-blend.c \
whirl-pinch.c \
diff --git a/operations/common/wavelet-blur-1d.c b/operations/common/wavelet-blur-1d.c
new file mode 100644
index 0000000..e789a28
--- /dev/null
+++ b/operations/common/wavelet-blur-1d.c
@@ -0,0 +1,281 @@
+/* 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 2016 Miroslav Talasek <miroslav talasek seznam cz>
+ * 2017 Thomas Manni <thomas manni free fr>
+ *
+ * one dimensional wavelet blur used by wavelet-blur operation
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+
+property_double (radius, _("Radius"), 1.0)
+ description (_("Radius of the wavelet blur"))
+ value_range (0.0, 1500.0)
+ ui_range (0.0, 256.0)
+ ui_gamma (3.0)
+ ui_meta ("unit", "pixel-distance")
+ ui_meta ("radius", "blur")
+
+property_enum (orientation, _("Orientation"),
+ GeglOrientation, gegl_orientation,
+ GEGL_ORIENTATION_HORIZONTAL)
+description (_("The orientation of the blur - hor/ver"))
+
+
+#else
+
+#define GEGL_OP_AREA_FILTER
+#define GEGL_OP_NAME wavelet_blur_1d
+#define GEGL_OP_C_SOURCE wavelet-blur-1d.c
+
+#include "gegl-op.h"
+#include <math.h>
+
+static inline void
+wav_get_mean_pixel_1D (gfloat *src,
+ gfloat *dst,
+ gint radius)
+{
+ gint i, offset;
+ gdouble weights[3] = {0.25, 0.5, 0.25};
+ gdouble acc[3] = {0.0, };
+
+ for (i = 0; i < 3; i++)
+ {
+ offset = i * radius * 3;
+ acc[0] += src[offset] * weights[i];
+ acc[1] += src[offset + 1] * weights[i];
+ acc[2] += src[offset + 2] * weights[i];
+ }
+
+ dst[0] = acc[0];
+ dst[1] = acc[1];
+ dst[2] = acc[2];
+}
+
+static void
+wav_hor_blur (GeglBuffer *src,
+ GeglBuffer *dst,
+ const GeglRectangle *dst_rect,
+ gint radius,
+ const Babl *format)
+{
+ gint x, y;
+
+ GeglRectangle write_rect = {dst_rect->x, dst_rect->y, dst_rect->width, 1};
+
+ GeglRectangle read_rect = {dst_rect->x - radius, dst_rect->y,
+ dst_rect->width + 2 * radius, 1};
+
+ gfloat *src_buf = gegl_malloc (read_rect.width * sizeof (gfloat) * 3);
+ gfloat *dst_buf = gegl_malloc (write_rect.width * sizeof (gfloat) * 3);
+
+ for (y = 0; y < dst_rect->height; y++)
+ {
+ gint offset = 0;
+ read_rect.y = dst_rect->y + y;
+ write_rect.y = dst_rect->y + y;
+
+ gegl_buffer_get (src, &read_rect, 1.0, format, src_buf,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+ for (x = 0; x < dst_rect->width; x++)
+ {
+ wav_get_mean_pixel_1D (src_buf + offset,
+ dst_buf + offset,
+ radius);
+ offset += 3;
+ }
+
+ gegl_buffer_set (dst, &write_rect, 0, format, dst_buf,
+ GEGL_AUTO_ROWSTRIDE);
+ }
+
+ gegl_free (src_buf);
+ gegl_free (dst_buf);
+}
+
+static void
+wav_ver_blur (GeglBuffer *src,
+ GeglBuffer *dst,
+ const GeglRectangle *dst_rect,
+ gint radius,
+ const Babl *format)
+{
+ gint x, y;
+
+ GeglRectangle write_rect = {dst_rect->x, dst_rect->y, 1, dst_rect->height};
+
+ GeglRectangle read_rect = {dst_rect->x, dst_rect->y - radius,
+ 1, dst_rect->height + 2 * radius};
+
+ gfloat *src_buf = gegl_malloc (read_rect.height * sizeof(gfloat) * 3);
+ gfloat *dst_buf = gegl_malloc (write_rect.height * sizeof(gfloat) * 3);
+
+ for (x = 0; x < dst_rect->width; x++)
+ {
+ gint offset = 0;
+ read_rect.x = dst_rect->x + x;
+ write_rect.x = dst_rect->x + x;
+
+ gegl_buffer_get (src, &read_rect, 1.0, format, src_buf,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
+
+ for (y = 0; y < dst_rect->height; y++)
+ {
+ wav_get_mean_pixel_1D (src_buf + offset,
+ dst_buf + offset,
+ radius);
+ offset += 3;
+ }
+
+ gegl_buffer_set (dst, &write_rect, 0, format, dst_buf,
+ GEGL_AUTO_ROWSTRIDE);
+ }
+
+ gegl_free (src_buf);
+ gegl_free (dst_buf);
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
+
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = babl_format ("R'G'B' float");
+
+ if (o->orientation == GEGL_ORIENTATION_HORIZONTAL)
+ {
+ area->left = area->right = ceil (o->radius);
+ area->top = area->bottom = 0;
+ }
+ else
+ {
+ area->left = area->right = 0;
+ area->top = area->bottom = ceil (o->radius);
+ }
+
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglRectangle result = { 0, };
+ GeglRectangle *in_rect;
+
+ in_rect = gegl_operation_source_get_bounding_box (operation,"input");
+
+ if (!in_rect)
+ return result;
+
+ return *in_rect;
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *format = gegl_operation_get_format (operation, "output");
+
+ gint radius = ceil (o->radius);
+
+ if (o->orientation == GEGL_ORIENTATION_HORIZONTAL)
+ wav_hor_blur (input, output, result, radius, format);
+ else
+ wav_ver_blur (input, output, result, radius, format);
+
+ return TRUE;
+}
+
+static gboolean
+operation_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglOperationClass *operation_class;
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class);
+
+ if (! o->radius)
+ {
+ gpointer in = gegl_operation_context_get_object (context, "input");
+ gegl_operation_context_take_object (context, "output",
+ g_object_ref (G_OBJECT (in)));
+ return TRUE;
+ }
+
+ return operation_class->process (operation, context, output_prop, result,
+ gegl_operation_context_get_level (context));
+}
+
+static GeglSplitStrategy
+get_split_strategy (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ if (o->orientation == GEGL_ORIENTATION_HORIZONTAL)
+ return GEGL_SPLIT_STRATEGY_HORIZONTAL;
+ else
+ return GEGL_SPLIT_STRATEGY_VERTICAL;
+}
+
+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);
+
+ operation_class->get_bounding_box = get_bounding_box;
+ operation_class->prepare = prepare;
+ operation_class->process = operation_process;
+ operation_class->opencl_support = FALSE;
+ operation_class->threaded = TRUE;
+
+ filter_class->get_split_strategy = get_split_strategy;
+ filter_class->process = process;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:wavelet-blur-1d",
+ "categories", "hidden:blur",
+ "title", _("1D Wavelet-blur"),
+ "reference-hash", "822a7c396b93fad84e0416a3bfba7a46",
+ "description", _("This blur is used for the wavelet decomposition filter, "
+ "each pixel is computed from another by the HAT transform"),
+ NULL);
+}
+
+#endif
diff --git a/operations/common/wavelet-blur.c b/operations/common/wavelet-blur.c
index 1743a14..be136b1 100644
--- a/operations/common/wavelet-blur.c
+++ b/operations/common/wavelet-blur.c
@@ -12,7 +12,7 @@
* 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 2016 Miroslav Talasek <miroslav talasek seznam cz>
+ * Copyright 2017 Thomas Manni <thomas manni free fr>
*
* Wavelet blur used in wavelet decompose filter
* theory is from original wavelet plugin
@@ -24,7 +24,6 @@
#ifdef GEGL_PROPERTIES
-
property_double (radius, _("Radius"), 1.0)
description (_("Radius of the wavelet blur"))
value_range (0.0, 1500.0)
@@ -33,256 +32,55 @@ property_double (radius, _("Radius"), 1.0)
ui_meta ("unit", "pixel-distance")
ui_meta ("radius", "blur")
-
#else
-#define GEGL_OP_AREA_FILTER
+#define GEGL_OP_META
#define GEGL_OP_NAME wavelet_blur
#define GEGL_OP_C_SOURCE wavelet-blur.c
#include "gegl-op.h"
-#include <math.h>
-#include <stdio.h>
-
-
-static gint
-wav_gen_convolve_matrix (gdouble radius,
- gdouble **cmatrix_p);
-
-
-
-static gint
-wav_calc_convolve_matrix_length (gdouble radius)
-{
- return ceil (radius) * 2 + 1;
-}
-
-static gint
-wav_gen_convolve_matrix (gdouble radius,
- gdouble **cmatrix_p)
-{
- gint matrix_length;
- gdouble *cmatrix;
-
- matrix_length = wav_calc_convolve_matrix_length (radius);
- cmatrix = g_new (gdouble, matrix_length);
-
- if (matrix_length == 1)
- {
- cmatrix[0] = 1;
- }
- else
- {
- gint i;
-
- for (i = 0; i < matrix_length; i++)
- {
- if (i == 0 || i == matrix_length - 1)
- {
- cmatrix[i] = 0.25;
- }
- else if (i == matrix_length / 2)
- {
- cmatrix[i] = 0.5;
- }
- else
- {
- cmatrix[i] = 0;
- }
- }
- }
-
- *cmatrix_p = cmatrix;
- return matrix_length;
-}
-
-static inline void
-wav_get_mean_pixel_1D (gfloat *src,
- gfloat *dst,
- gint components,
- gdouble *cmatrix,
- gint matrix_length)
-{
- gint i, c;
- gint offset;
- gdouble acc[components];
-
- for (c = 0; c < components; ++c)
- acc[c] = 0;
-
- offset = 0;
-
- for (i = 0; i < matrix_length; i++)
- {
- for (c = 0; c < components; ++c)
- acc[c] += src[offset++] * cmatrix[i];
- }
-
- for (c = 0; c < components; ++c)
- dst[c] = acc[c];
-}
-
-static void
-wav_hor_blur (GeglBuffer *src,
- GeglBuffer *dst,
- const GeglRectangle *dst_rect,
- gdouble *cmatrix,
- gint matrix_length,
- const Babl *format)
-{
- gint u, v;
- const gint radius = matrix_length / 2;
- const gint nc = babl_format_get_n_components (format);
-
- GeglRectangle write_rect = {dst_rect->x, dst_rect->y, dst_rect->width, 1};
- gfloat *dst_buf = gegl_malloc (write_rect.width * sizeof(gfloat) * nc);
-
- GeglRectangle read_rect = {dst_rect->x - radius, dst_rect->y, dst_rect->width + matrix_length -1, 1};
- gfloat *src_buf = gegl_malloc (read_rect.width * sizeof(gfloat) * nc);
-
- for (v = 0; v < dst_rect->height; v++)
- {
- gint offset = 0;
- read_rect.y = dst_rect->y + v;
- write_rect.y = dst_rect->y + v;
- gegl_buffer_get (src, &read_rect, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
-
- for (u = 0; u < dst_rect->width; u++)
- {
- wav_get_mean_pixel_1D (src_buf + offset,
- dst_buf + offset,
- nc,
- cmatrix,
- matrix_length);
- offset += nc;
- }
-
- gegl_buffer_set (dst, &write_rect, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);
- }
-
- gegl_free (src_buf);
- gegl_free (dst_buf);
-}
static void
-wav_ver_blur (GeglBuffer *src,
- GeglBuffer *dst,
- const GeglRectangle *dst_rect,
- gdouble *cmatrix,
- gint matrix_length,
- const Babl *format)
+attach (GeglOperation *operation)
{
- gint u,v;
- const gint radius = matrix_length / 2;
- const gint nc = babl_format_get_n_components (format);
+ GeglNode *gegl = operation->node;
+ GeglNode *input = gegl_node_get_input_proxy (gegl, "input");
+ GeglNode *output = gegl_node_get_output_proxy (gegl, "output");
- GeglRectangle write_rect = {dst_rect->x, dst_rect->y, 1, dst_rect->height};
- gfloat *dst_buf = gegl_malloc (write_rect.height * sizeof(gfloat) * nc);
+ GeglNode *vblur = gegl_node_new_child (gegl,
+ "operation", "gegl:wavelet-blur-1d",
+ "orientation", 1,
+ NULL);
- GeglRectangle read_rect = {dst_rect->x, dst_rect->y - radius , 1, dst_rect->height + matrix_length -1};
- gfloat *src_buf = gegl_malloc (read_rect.height * sizeof(gfloat) * nc);
+ GeglNode *hblur = gegl_node_new_child (gegl,
+ "operation", "gegl:wavelet-blur-1d",
+ "orientation", 0,
+ NULL);
- for (u = 0; u < dst_rect->width; u++)
- {
- gint offset = 0;
- read_rect.x = dst_rect->x + u;
- write_rect.x = dst_rect->x + u;
- gegl_buffer_get (src, &read_rect, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
-
- for (v = 0; v < dst_rect->height; v++)
- {
- wav_get_mean_pixel_1D (src_buf + offset,
- dst_buf + offset,
- nc,
- cmatrix,
- matrix_length);
- offset += nc;
- }
+ gegl_node_link_many (input, hblur, vblur, output, NULL);
- gegl_buffer_set (dst, &write_rect, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);
- }
+ gegl_operation_meta_redirect (operation, "radius", hblur, "radius");
+ gegl_operation_meta_redirect (operation, "radius", vblur, "radius");
- gegl_free (src_buf);
- gegl_free (dst_buf);
+ gegl_operation_meta_watch_nodes (operation, hblur, vblur, NULL);
}
static void
-prepare (GeglOperation *operation)
-{
- GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
- GeglProperties *o = GEGL_PROPERTIES (operation);
-
-
- /* XXX: these should be calculated exactly considering o->filter, but we just
- * make sure there is enough space */
- area->left = area->right = ceil (o->radius);
- area->top = area->bottom = ceil (o->radius);
-
- gegl_operation_set_format (operation, "input",
- babl_format ("R'G'B' float"));
- gegl_operation_set_format (operation, "output",
- babl_format ("R'G'B' float"));
-}
-
-static gboolean
-process (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *output,
- const GeglRectangle *result,
- gint level)
-{
- GeglRectangle rect;
- GeglBuffer *temp;
- GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
- GeglProperties *o = GEGL_PROPERTIES (operation);
- const Babl *format = gegl_operation_get_format (operation, "output");
-
- GeglRectangle temp_extend;
- gdouble *cmatrix;
- gint cmatrix_len;
-
- rect.x = result->x - op_area->left;
- rect.width = result->width + op_area->left + op_area->right;
- rect.y = result->y - op_area->top;
- rect.height = result->height + op_area->top + op_area->bottom;
-
-
- gegl_rectangle_intersect (&temp_extend, &rect, gegl_buffer_get_extent (input));
- temp_extend.x = result->x;
- temp_extend.width = result->width;
- temp = gegl_buffer_new (&temp_extend, format);
-
- cmatrix_len = wav_gen_convolve_matrix (o->radius, &cmatrix);
- wav_hor_blur (input, temp, &temp_extend, cmatrix, cmatrix_len, format);
- wav_ver_blur (temp, output, result, cmatrix, cmatrix_len, format);
- g_free (cmatrix);
-
- g_object_unref (temp);
- return TRUE;
-}
-
-
-static void
gegl_op_class_init (GeglOpClass *klass)
{
- GeglOperationClass *operation_class;
- GeglOperationFilterClass *filter_class;
+ GeglOperationClass *operation_class;
operation_class = GEGL_OPERATION_CLASS (klass);
- filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
-
- operation_class->prepare = prepare;
- operation_class->opencl_support = FALSE;
- filter_class->process = process;
+ operation_class->attach = attach;
gegl_operation_class_set_keys (operation_class,
- "name", "gegl:wavelet-blur",
- "title", _("Wavelet Blur"),
-// "license", "LGPL3+",
- "categories", "blur",
- "reference-hash", "ae56a8da120f29554bafa08789aa37b6",
- "description", _("This blur is used for the wavelet decomposition filter, each pixel is computed from
another by the HAT transform"),
+ "name", "gegl:wavelet-blur",
+ "title", "Wavelet Blur",
+ "categories", "blur",
+ "reference-hash", "49eaf3d22cf5a5999991c4e7a0fbe8e2",
+ "description", _("This blur is used for the wavelet decomposition filter, "
+ "each pixel is computed from another by the HAT transform"),
NULL);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]