[gegl] operations: add a basic motion-blur-zoom operation
- From: Téo Mazars <teom src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations: add a basic motion-blur-zoom operation
- Date: Sun, 2 Jun 2013 07:56:13 +0000 (UTC)
commit 5e2bfb18b57b1d838ebd740413fd9ba005ee8134
Author: Téo Mazars <teo mazars ensimag fr>
Date: Sun Jun 2 09:48:36 2013 +0200
operations: add a basic motion-blur-zoom operation
It is inspired by the GIMP's implementation, but more readable.
It is not included in the current motion-blur op because the set
of parameters is different. This one should be renamed in
motion-blur-linear perhaps.
operations/common/motion-blur-zoom.c | 233 ++++++++++++++++++++++++++++++++++
1 files changed, 233 insertions(+), 0 deletions(-)
---
diff --git a/operations/common/motion-blur-zoom.c b/operations/common/motion-blur-zoom.c
new file mode 100644
index 0000000..9cfc854
--- /dev/null
+++ b/operations/common/motion-blur-zoom.c
@@ -0,0 +1,233 @@
+/* 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 2013 Téo Mazars <teo mazars ensimag fr>
+ *
+ * This operation is inspired by and uses parts of blur-motion.c
+ * from GIMP 2.8.4.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_double_ui (center_x, _("X"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 20.0,
+ -100000.0, 100000.0, 1.0,
+ _("Horizontal center position"))
+
+gegl_chant_double_ui (center_y, _("Y"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 20.0,
+ -100000.0, 100000.0, 1.0,
+ _("Vertical center position"))
+
+gegl_chant_double_ui (factor, _("factor"),
+ 0.0, 1.0, 0.1,
+ 0.0, 1.0, 2.0,
+ _("Bluring factor"))
+
+#else
+
+#define GEGL_CHANT_TYPE_AREA_FILTER
+#define GEGL_CHANT_C_FILE "motion-blur-zoom.c"
+
+#include "gegl-chant.h"
+
+
+#define SQR(c) ((c) * (c))
+
+#define MAX_NUM_IT 200
+#define NOMINAL_NUM_IT 100
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglOperationAreaFilter* op_area = GEGL_OPERATION_AREA_FILTER (operation);
+ GeglChantO* o = GEGL_CHANT_PROPERTIES (operation);
+
+ GeglRectangle *whole_region = gegl_operation_source_get_bounding_box (operation, "input");
+
+ if (whole_region != NULL)
+ {
+ op_area->left = op_area->right
+ = MAX (fabs (whole_region->x - o->center_x),
+ fabs (whole_region->width + whole_region->x - o->center_x)) * o->factor +1;
+
+ op_area->top = op_area->bottom
+ = MAX (fabs (whole_region->y - o->center_y),
+ fabs (whole_region->height + whole_region->y - o->center_y)) * o->factor +1;
+ }
+ else
+ {
+ op_area->left =
+ op_area->right =
+ op_area->top =
+ op_area->bottom = 0;
+ }
+
+ gegl_operation_set_format (operation, "input", babl_format ("RaGaBaA float"));
+ gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
+}
+
+
+static inline gfloat*
+get_pixel_color (gfloat *in_buf,
+ const GeglRectangle *rect,
+ gint x,
+ gint y)
+{
+ gint ix = x - rect->x;
+ gint iy = y - rect->y;
+ ix = CLAMP (ix, 0, rect->width - 1);
+ iy = CLAMP (iy, 0, rect->height - 1);
+
+ return &in_buf[(iy * rect->width + ix) * 4];
+}
+
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GeglChantO *o;
+ GeglOperationAreaFilter *op_area;
+ gfloat *in_buf, *out_buf, *out_pixel;
+ gint x, y;
+ GeglRectangle src_rect;
+
+ op_area = GEGL_OPERATION_AREA_FILTER (operation);
+ o = GEGL_CHANT_PROPERTIES (operation);
+
+ src_rect = *roi;
+ src_rect.x -= op_area->left;
+ src_rect.y -= op_area->top;
+ src_rect.width += op_area->left + op_area->right;
+ src_rect.height += op_area->top + op_area->bottom;
+
+ in_buf = g_new (gfloat, src_rect.width * src_rect.height * 4);
+ out_buf = g_new0 (gfloat, roi->width * roi->height * 4);
+ out_pixel = out_buf;
+
+ gegl_buffer_get (input,
+ &src_rect,
+ 1.0,
+ babl_format ("RaGaBaA float"),
+ in_buf,
+ GEGL_AUTO_ROWSTRIDE,
+ GEGL_ABYSS_NONE);
+
+ for (y = roi->y; y < roi->height + roi->y; ++y)
+ {
+ for (x = roi->x; x < roi->width + roi->x; ++x)
+ {
+ gint c, i;
+ gfloat dxx, dyy, ix, iy, inv_xy_len;
+ gfloat sum[] = {0, 0, 0, 0};
+
+ gfloat x_start = x;
+ gfloat y_start = y;
+ gfloat x_end = x + (o->center_x - (gfloat) x) * o->factor;
+ gfloat y_end = y + (o->center_y - (gfloat) y) * o->factor;
+
+ gint dist = ceil (sqrt (SQR (x_end - x_start) + SQR (y_end - y_start)) +1);
+
+ /* ensure quality when near the center or with small factor */
+ gint xy_len = MAX (dist, 3);
+
+ /* performance concern */
+ if (xy_len > NOMINAL_NUM_IT)
+ xy_len = MIN (NOMINAL_NUM_IT + (gint) sqrt (xy_len - NOMINAL_NUM_IT), MAX_NUM_IT);
+
+ inv_xy_len = 1.0 / (gfloat) xy_len;
+
+ dxx = (x_end - x_start) * inv_xy_len;
+ dyy = (y_end - y_start) * inv_xy_len;
+
+ ix = x_start;
+ iy = y_start;
+
+ for (i = 0; i < xy_len; i++)
+ {
+ gfloat dx = ix - floor (ix);
+ gfloat dy = iy - floor (iy);
+
+ /* do bilinear interpolation to get a nice smooth result */
+ gfloat *pix0, *pix1, *pix2, *pix3;
+ gfloat mixy0[4];
+ gfloat mixy1[4];
+
+ pix0 = get_pixel_color (in_buf, &src_rect, ix, iy);
+ pix1 = get_pixel_color (in_buf, &src_rect, ix+1, iy);
+ pix2 = get_pixel_color (in_buf, &src_rect, ix, iy+1);
+ pix3 = get_pixel_color (in_buf, &src_rect, ix+1, iy+1);
+
+ for (c = 0; c < 4; ++c)
+ {
+ mixy0[c] = dy * (pix2[c] - pix0[c]) + pix0[c];
+ mixy1[c] = dy * (pix3[c] - pix1[c]) + pix1[c];
+
+ sum[c] += dx * (mixy1[c] - mixy0[c]) + mixy0[c];
+ }
+
+ ix += dxx;
+ iy += dyy;
+ }
+
+ for (c = 0; c < 4; ++c)
+ *out_pixel++ = sum[c] * inv_xy_len;
+ }
+ }
+
+ gegl_buffer_set (output,
+ roi,
+ 1.0,
+ babl_format ("RaGaBaA float"),
+ out_buf,
+ GEGL_AUTO_ROWSTRIDE);
+
+ g_free (in_buf);
+ g_free (out_buf);
+
+ return TRUE;
+}
+
+
+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;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name" , "gegl:motion-blur-zoom",
+ "categories" , "blur",
+ "description", _("Zoom motion blur"),
+ NULL);
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]