[gegl] refactor to make inner function portable C
- From: Ãyvind KolÃs <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] refactor to make inner function portable C
- Date: Mon, 20 Jun 2011 03:18:19 +0000 (UTC)
commit ac809dcb2efef6ba2994bae33b959f15de11336a
Author: Ãyvind KolÃs <pippin gimp org>
Date: Sun Jun 19 21:36:18 2011 +0100
refactor to make inner function portable C
operations/common/noise-reduction.c | 294 ++++++++++++++++-------------------
tests/compositions/Makefile.am | 1 +
2 files changed, 134 insertions(+), 161 deletions(-)
---
diff --git a/operations/common/noise-reduction.c b/operations/common/noise-reduction.c
index a338f78..6f23d8e 100644
--- a/operations/common/noise-reduction.c
+++ b/operations/common/noise-reduction.c
@@ -18,7 +18,7 @@
#ifdef GEGL_CHANT_PROPERTIES
-gegl_chant_int (iterations, "Iterations", 1, 32, 5, "Number of iterations, more iterations takes longer time but might also make the image less noise, the number of iterations is the longest distance pixel content from one pixel can be diffusd out in the image.")
+gegl_chant_int (iterations, "Strength", 1, 32, 4, "How many iteratarion to run the algorithm.")
#else
@@ -28,27 +28,116 @@ gegl_chant_int (iterations, "Iterations", 1, 32, 5, "Number of iterations, more
#include "gegl-chant.h"
#include <math.h>
-#define POW2(a) ((a)*(a))
+/* The core noise_reduction function, which is implemented as
+ * portable C - this is the function where most cpu time goes
+ */
+static void
+noise_reduction (float *src_buf, /* source buffer, one pixel to the left
+ and up from the starting pixel */
+ int src_stride, /* stridewidth of buffer in pixels */
+ float *dst_buf, /* destination buffer */
+ int dst_width, /* width to render */
+ int dst_height, /* height to render */
+ int dst_stride) /* stride of target buffer */
+{
+ int c;
+ int x,y;
+ int dst_offset;
+
+#define NEIGHBOURS 8
+#define AXES (NEIGHBOURS/2)
+#define POW2(a) ((a)*(a))
/* core code/formulas to be tweaked for the tuning the implementation */
#define GEN_METRIC(before, center, after) \
- POW2((center - before) + (center - after))
- //POW2((center) * 2 - (before) - (after))
+ POW2((center) * 2 - (before) - (after))
/* Condition used to bail diffusion from a direction */
#define BAIL_CONDITION(new,original) ((new) > (original))
+#define SYMMETRY(a) (NEIGHBOURS - (a) - 1) /* point-symmetric neighbour pixel */
-static void
-noise_reduction (GeglBuffer *src,
- const GeglRectangle *src_rect,
- GeglBuffer *dst,
- const GeglRectangle *dst_rect);
+#define O(u,v) (((u)+((v) * src_stride)) * 4)
+ int offsets[NEIGHBOURS] = { /* array of the relative distance i float
+ * pointers to each of neighbours
+ * in source buffer, allows quick referencing.
+ */
+ O( -1, -1), O(0, -1), O(1, -1),
+ O( -1, 0), O(1, 0),
+ O( -1, 1), O(0, 1), O(1, 1)};
+#undef O
+
+ dst_offset = 0;
+ for (y=0; y<dst_height; y++)
+ {
+ float *center_pix = src_buf + ((y+1) * src_stride + 1) * 4;
+ dst_offset = dst_stride * y;
+ for (x=0; x<dst_width; x++)
+ {
+ for (c=0; c<3; c++) /* do each color component individually */
+ {
+ float metric_reference[AXES];
+ int axis;
+ int direction;
+ float sum;
+ int count;
+
+ for (axis = 0; axis < AXES; axis++)
+ { /* initialize original metrics for the horizontal, vertical
+ and 2 diagonal metrics */
+ float *before_pix = center_pix + offsets[axis];
+ float *after_pix = center_pix + offsets[SYMMETRY(axis)];
+
+ metric_reference[axis] =
+ GEN_METRIC (before_pix[c], center_pix[c], after_pix[c]);
+ }
+
+ sum = center_pix[c];
+ count = 1;
+
+ /* try smearing in data from all neighbours */
+ for (direction = 0; direction < NEIGHBOURS; direction++)
+ {
+ float *pix = center_pix + offsets[direction];
+ float value = pix[c] * 0.5 + center_pix[c] * 0.5;
+ int axis;
+ int valid;
+
+ /* check if the non-smoothing operating check is true if
+ * smearing from this direction for any of the axes */
+ valid = 1; /* assume it will be valid */
+ for (axis = 0; axis < AXES; axis++)
+ {
+ float *before_pix = center_pix + offsets[axis];
+ float *after_pix = center_pix + offsets[SYMMETRY(axis)];
+ float metric_new =
+ GEN_METRIC (before_pix[c], value, after_pix[c]);
+
+ if (BAIL_CONDITION(metric_new, metric_reference[axis]))
+ {
+ valid = 0; /* mark as not a valid smoothing, and .. */
+ break; /* .. break out of loop */
+ }
+ }
+ if (valid) /* we were still smooth in all axes */
+ { /* add up contribution to final result */
+ sum += value;
+ count ++;
+ }
+ }
+ dst_buf[dst_offset*4+c] = sum / count;
+ }
+ dst_buf[dst_offset*4+3] = center_pix[3]; /* copy alpha unmodified */
+ dst_offset++;
+ center_pix += 4;
+ }
+ }
+}
static void prepare (GeglOperation *operation)
{
GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
- GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
area->left = area->right = area->top = area->bottom = o->iterations;
gegl_operation_set_format (operation, "input", babl_format ("R'G'B'A float"));
@@ -62,171 +151,54 @@ process (GeglOperation *operation,
const GeglRectangle *result)
{
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
- GeglRectangle compute;
- GeglBuffer *temp[2] = {NULL, NULL};
int iteration;
-
- compute = gegl_operation_get_required_for_output (operation, "input",result);
-
- if (o->iterations > 1)
- {
- temp[0] = gegl_buffer_new (&compute, babl_format ("R'G'B'A float"));
- temp[1] = gegl_buffer_new (&compute, babl_format ("R'G'B'A float"));
- }
-
- for (iteration = 0; iteration < o->iterations; iteration++)
- {
- GeglBuffer *source, *target;
- GeglRectangle source_rect;
- GeglRectangle target_rect;
-
- /* compute extent of rectangles needed for this iteration,
- * minimizing the work neccesary to do
- */
- target_rect = *result;
- target_rect.x -= (o->iterations-iteration-1);
- target_rect.y -= (o->iterations-iteration-1);
- target_rect.width += (o->iterations-iteration-1)*2;
- target_rect.height += (o->iterations-iteration-1)*2;
-
- source_rect = target_rect;
- source_rect.x -= 1;
- source_rect.y -= 1;
- source_rect.width += 2;
- source_rect.height += 2;
-
- source = temp[iteration%2];
- target = temp[(iteration+1)%2];
- if (iteration == 0)
- source = input;
- if (iteration == o->iterations-1)
- target = output;
-
- noise_reduction (source, &source_rect, target, &target_rect);
- }
-
- if (temp[0])
- g_object_unref (temp[0]);
- if (temp[1])
- g_object_unref (temp[1]);
-
- return TRUE;
-}
-
-static void
-noise_reduction (GeglBuffer *src,
- const GeglRectangle *src_rect,
- GeglBuffer *dst,
- const GeglRectangle *dst_rect)
-{
- int c;
- int x,y;
- int offset;
+ int stride;
float *src_buf;
float *dst_buf;
+ GeglRectangle rect;
+ rect = *result;
- int src_width = src_rect->width;
-#define OFFSETS 8
-
-/* fetch symmetric entry */
-#define SYMMETRY(a) (OFFSETS - a - 1)
-
- int rel_offsets[OFFSETS][2] = {
- { -1, -1}, {0, -1},{1, -1},
- { -1, 0}, {1, 0},
- { -1, 1}, {0, 1}, {1, 1}
- };
- int offsets[OFFSETS]; /* sizeof(float) offsets for neighbours */
-
- /* initialize offsets, dependent on source buffer width */
- for (c = 0; c < OFFSETS; c++)
- offsets[c] = ((rel_offsets[c][0])+((rel_offsets[c][1]) * src_width)) * 4;
+ stride = result->width + o->iterations * 2;
- src_buf = g_new0 (float, src_rect->width * src_rect->height * 4);
- dst_buf = g_new0 (float, dst_rect->width * dst_rect->height * 4);
+ src_buf = g_new0 (float,
+ (stride) * (result->height + o->iterations * 2) * 4);
+ dst_buf = g_new0 (float,
+ (stride) * (result->height + o->iterations * 2) * 4);
- gegl_buffer_get (src, 1.0, src_rect, babl_format ("R'G'B'A float"), src_buf,
- GEGL_AUTO_ROWSTRIDE);
+ {
+ rect.x -= o->iterations;
+ rect.y -= o->iterations;
+ rect.width += o->iterations*2;
+ rect.height += o->iterations*2;
+ gegl_buffer_get (input, 1.0, &rect, babl_format ("R'G'B'A float"),
+ src_buf, stride * 4 * 4);
+ }
- offset = 0;
- for (y=0; y<dst_rect->height; y++)
+ for (iteration = 0; iteration < o->iterations; iteration++)
{
- float *center_pix = src_buf + (1+((y+1) * src_width)) * 4;
- for (x=0; x<dst_rect->width; x++)
- {
- for (c=0; c<3; c++)
- {
- float original_metric[OFFSETS];
- int dir;
- float sum;
- int count;
-
- for (dir = 0; dir < OFFSETS/2; dir++)
- { /* initialize original metrics for the horizontal, vertical and 2 diagonal
- * metrics
- */
- float *before_pix = center_pix + offsets[dir];
- float *after_pix = center_pix + offsets[SYMMETRY(dir)];
-
- original_metric[dir] =
- GEN_METRIC (before_pix[c], center_pix[c], after_pix[c]);
- }
-
- sum = center_pix[c];
- count = 1;
-
- /* try smearing in data from each of the 8 neighbours */
- for (dir = 0; dir < OFFSETS; dir++)
- {
- float *pix = center_pix + offsets[dir];
- float value = pix[c] * 0.5 + center_pix[c] * 0.5;
- /* ... assumption for magic number 0.2, assume that each
- * direction contributes on average 0.2
- thus that seems like a reasonable value to check with.. */
- int comparison_dir;
- gboolean valid = TRUE; /* if diffusion from this direction
- * should be made
- */
- for (comparison_dir = 0; comparison_dir < OFFSETS/2; comparison_dir++)
- if (G_LIKELY (comparison_dir != dir))
- {
- float *before_pix = center_pix + offsets[comparison_dir];
- float *after_pix = center_pix + offsets[SYMMETRY(comparison_dir)];
- float new_metric =
- GEN_METRIC (before_pix[c], value, after_pix[c]);
-
-
- if (G_UNLIKELY (BAIL_CONDITION(new_metric,
- original_metric[comparison_dir])))
- { /* bail condition */
- valid = FALSE;
- break;
- }
- }
- if (valid)
- {
- sum += value; /* accumulate value */
- count ++; /* increase denominator */
- }
- }
- dst_buf[offset*4+c] = sum / count; /* write back the average of center pixel
- and all pixels that would be valid to
- replace the center pixel with while
- continuing to fulfil our criteria.
- */
- }
- dst_buf[offset*4+3] = center_pix[3]; /* copy alpha unmodified */
- offset++;
- center_pix += 4;
- }
+ noise_reduction (src_buf, stride,
+ dst_buf,
+ result->width + (o->iterations - 1 - iteration) * 2,
+ result->height + (o->iterations - 1 - iteration) * 2,
+ stride);
+ { /* swap buffers */
+ float *tmp = src_buf;
+ src_buf = dst_buf;
+ dst_buf = tmp;
+ }
}
- gegl_buffer_set (dst, dst_rect, babl_format ("R'G'B'A float"), dst_buf,
- GEGL_AUTO_ROWSTRIDE);
+ gegl_buffer_set (output , result, babl_format ("R'G'B'A float"),
+ src_buf,
+ stride * 4 * 4);
+
g_free (src_buf);
g_free (dst_buf);
+
+ return TRUE;
}
+
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
diff --git a/tests/compositions/Makefile.am b/tests/compositions/Makefile.am
index 6842f95..5b12563 100644
--- a/tests/compositions/Makefile.am
+++ b/tests/compositions/Makefile.am
@@ -31,6 +31,7 @@ testsuffix = .sh
# EXTRA_DISTS
TESTS = \
run-clones.xml.sh \
+ run-denoise.xml.sh \
run-composite-transform.xml.sh \
run-edge-laplace-broken.xml.sh \
run-edge-sobel.xml.sh \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]