Hi, I am applying for the GSoC GEGL operation porting task for GIMP. I am a
MS Computer Science student at the University of Massachusetts: Boston. I
have experimented with gegl a little bit and have some experience in C. Here
is the required information, including a ripple operation that I was
experimenting with a few months ago that I cleaned up to submit.


Algorithm Analysis

-Split image up into even tiles
-fill up image with background color
-process each tiles in random order so that the tiles overlap randomly
-shift tile a random amount depending on tile size
-resize width and height of tile by random amounts with constraints
depending on tile size and tile saturation
-rotate tile a random amount
-fill polygon with a color taken by sampling the color of a corner pixel and
then blending so that the rectangle gets progressively lighter from one edge
to the opposite edge.

Code review

There are some calculations that are done many times when once is enough.
For example, for each tile, the value cvals.tilesize/2.0 is used both for
the x and y positions, but is calculated each time. This makes an additional
calculation per tile. In the same loop there is also cvals.tilesize/4.0 and
width/2.0 and many others. It would be ore efficient to save these
calculation in temporary values in each iteration of the loop.

Fractral Trace:

-Scale down image so that it is workable within the bounds of Mandelbrot
-For each pixel, use the Mandelbrot set definition to determine a pixel to
map from after the user defined number of iterations. This is the pixel that
is confirmed to be in the Mandelbrot set after this many iterations.
-For each pixel, scale the mapping back up so that the image can be drawn,
and then draw the pixel.

Code review

There is a reliance on global values that is somewhat dangerous. In
particular the array dpixels, which is written to and then copied to the
main pixel region. A better way might be to pass in pointers to the pixel
region or the buffer to modify within the functions, which would make
debugging easier.


-put random colors into 9 pixels in the area to be drawn on: the corners,
the midpoints between the corners, and the pixel in the center.
-recursively split the image into four quadrants. For each quadrant,
determine the colors of pixels at the midpoints between the corners but
averaging the color of the two corner pixels and then adding a random shift
in the rgb values that depends on the turbulence parameter. The color for
the point in the middle of all four corners is determined by averaging the
colors of all four corners (plus the random color shift). For each upper
level of recursion, the corner colors will have been determined by the
recursive call lower on the recursion tree. At the lowest recursive call,
when the quadrant is 2x2 pixels large or less, we are done because the
corners are known and there cannot be any midpoints.

Code Review

Plasma does an iteration to determine the colors of evenly spaced pixels
across the drawing region. It does recursive calls at each iteration to get
to the first pixels that have not been colored yet. These previous recursive
calls are probably not needed as they go through work thats already been
complete. A better way might be to do everything iteratively and use the
depth value to determine which pixels need to be calculated next through an
iterative call. This way stack overflow can still be avoided but there is no
need to go through many recursive calls at each step.

Gaussian Blur:

-Blur horizontally and then vertically depending on the x and y standard
deviation parameters. How it blurs depends on if it is iir or fir.
-In iir, each pixel's new value is calculated as the weighted average of
three pixels in front and behind it on the row depending on if it is
blurring horizontally or vertically. The weights are calculated using the
standard deviation parameter and values that approximate the relevant values
on a normal curve.
-The fir algorithm is similar but instead of using estimated values,
generates a convolution matrix that stores the weights. The weights in the
matrix are calculated using the Gaussian function so that the higher values
are in the center of the matrix. For each pixel in the row, the matrix is
then iterated through to calculate a weighted average of pixels around it.

Code Review

There are many arbitrary constants in the code. For example the weights in
iir are calculated by doing arithmetic on the standard deviation with
seemingly arbitrary values. My guess is that these values are used to
approximate a normal curve at a few points, but it be better to use named
constants or at least document the code so that what these values do are


Thank you for your time,

Hans Lo
From c7ba406ec346e4dd398e58f453440edd07a58bde Mon Sep 17 00:00:00 2001
From: Hans Lo <hanssh...@gmail.com>
Date: Fri, 8 Apr 2011 03:56:26 -0400
Subject: [PATCH] ripple experimentation with gegl

 operations/common/ripple-test.c |  149 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 149 insertions(+), 0 deletions(-)
 create mode 100644 operations/common/ripple-test.c

diff --git a/operations/common/ripple-test.c b/operations/common/ripple-test.c
new file mode 100644
index 0000000..dc62973
--- /dev/null
+++ b/operations/common/ripple-test.c
@@ -0,0 +1,149 @@
+#include "config.h"
+#include <glib/gi18n-lib.h>
+gegl_chant_int (amplitude, _("Amplitude"), 0, 200, 50,
+   _("Amplitude of ripple."))
+gegl_chant_int (period, _("Period"), 0, 200, 50,
+   _("Period of ripple."))
+gegl_chant_double (phi, _("Phase Shift"), -1.0, 1.0, 0.0,
+   _("As proportion of pi."))
+gegl_chant_boolean (antialias,   _("Antialiasing"),   FALSE,
+                    _("Antialiasing"))
+#define GEGL_CHANT_C_FILE       "ripple-test.c"
+#include "gegl-chant.h"
+#include <stdio.h>
+#include <math.h>
+static gdouble
+displace_amount (gint location, gint amplitude, gint period, gdouble phi)
+  return ((gdouble)amplitude *
+	  sin (2 * G_PI * (((gdouble)location / (gdouble)period) + G_PI*phi)));
+static void
+horizontal_shift (GeglBuffer          *src,
+      const GeglRectangle *src_rect,
+      GeglBuffer          *dst,
+      const GeglRectangle *dst_rect,
+      gint amplitude,
+      gint period,
+      gdouble phi,
+      gboolean antialias)
+  gint u,v;
+  gint src_offset, dst_offset;
+  gfloat *src_buf;
+  gfloat *dst_buf;
+  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 ("RaGaBaA float"), src_buf, GEGL_AUTO_ROWSTRIDE);
+  src_offset = 0;
+  dst_offset = 0;
+  for (v=0; v<dst_rect->height; v++)
+    {
+      gdouble shift = displace_amount(v+dst_rect->y, amplitude, period, phi);
+      gdouble floor_shift = floor(shift);
+      gdouble remainder = shift-floor_shift;
+      gdouble temp_value;
+      for (u=0; u<(dst_rect->width); u++)
+        {
+          gint i;
+          for (i=0; i<4; i++)
+            {
+              gint new_pixel = src_offset + (4*amplitude + 4*amplitude*2*v + 4*(gint)floor_shift);
+              //antialias
+              temp_value = src_buf[new_pixel];
+              if(antialias && u>3 && i < 3)
+                {
+                  gint upper_pixel = new_pixel - 4;
+                  temp_value = (remainder)*src_buf[new_pixel] + (1.0-remainder)*src_buf[upper_pixel];
+                }
+              dst_buf[dst_offset] = temp_value;
+              src_offset++;
+              dst_offset++;
+            }
+        }
+    }
+  gegl_buffer_set (dst, dst_rect, babl_format ("RaGaBaA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
+  g_free (src_buf);
+  g_free (dst_buf);
+static void prepare (GeglOperation *operation)
+  GeglChantO              *o;
+  GeglOperationAreaFilter *op_area;
+  op_area = GEGL_OPERATION_AREA_FILTER (operation);
+  o       = GEGL_CHANT_PROPERTIES (operation);
+    op_area->left   =
+    op_area->right  = o->amplitude;
+    //op_area->top    =
+    //op_area->bottom = 
+  gegl_operation_set_format (operation, "output",
+                             babl_format ("RaGaBaA float"));
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+  GeglRectangle rect;
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  GeglOperationAreaFilter *op_area;
+  op_area = GEGL_OPERATION_AREA_FILTER (operation);
+  rect = *result;
+  rect.x-=op_area->left;
+  rect.width+=op_area->left + op_area->right;
+  horizontal_shift(input, &rect, output, result, o->amplitude, o->period, o->phi, o->antialias);
+  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;
+  operation_class->categories  = "blur";
+  operation_class->name        = "gegl:ripple-test";
+  operation_class->description =
+       _("Trying out GEGL.");

Gimp-developer mailing list

Reply via email to