[gegl] median-blur: various additions



commit 019d3a72ac56f92d98534bb31b69bd39b4bf3d3c
Author: Ell <ell_se yahoo com>
Date:   Sun Feb 12 11:20:38 2017 -0500

    median-blur: various additions
    
    Performance
    -----------
    
    General performance improvement.  The speedup factor depends on
    the input image and the radius, but it ranges from about 5x for
    small radii, to 2x for large radii.
    
    The main boost comes from keeping track of the last computed
    median, and starting the histogram scan for the new median from
    it, instead of from 0.  This is a heuristic, based on the
    assumption that the median value changes very little across
    consecutive pixels.  This results in the median search
    approaching an amortized complexity of O(1), or at least a very
    small O(n) (where n is the number of bins), while keeping the
    cost of adding and removing values to the histogram O(1).
    
    There are a few other smaller optimizations, the most
    significant of which is probably converting input values to
    bin indices only once per pixel, instead of twice.
    
    Alpha
    -----
    
    Properly blur images with transparent regions.
    
    Properties
    ----------
    
    Add a few properties:
    
      - Neighborhood:  Controls the shape of the neighborhood.
        Can be either SQUARE (old behavior), CIRCLE (new default),
        or DIAMOND.
    
      - Percentile:  Which percentile of the neighborhood to use as
        the result, for the color channels.  Defaults to 50% (i.e.,
        the median), but can be anything from 0% (erosion), to 100%
        (dilation).  This, ofcourse, makes the name of the operation
        a misnomer :P  It's mostly for experimentation for now.
    
      - Alpha percentile:  Same thing, but for the alpha channel.

 operations/workshop/median-blur.c |  611 +++++++++++++++++++++++++------------
 1 files changed, 418 insertions(+), 193 deletions(-)
---
diff --git a/operations/workshop/median-blur.c b/operations/workshop/median-blur.c
index 12592bb..30eb12b 100644
--- a/operations/workshop/median-blur.c
+++ b/operations/workshop/median-blur.c
@@ -19,13 +19,34 @@
 
 #include "config.h"
 #include <glib/gi18n-lib.h>
+#include <stdlib.h>
 #include <math.h>
 
 #ifdef GEGL_PROPERTIES
 
+enum_start (gegl_median_blur_neighborhood)
+  enum_value (GEGL_MEDIAN_BLUR_NEIGHBORHOOD_SQUARE,  "square",  N_("Square"))
+  enum_value (GEGL_MEDIAN_BLUR_NEIGHBORHOOD_CIRCLE,  "circle",  N_("Circle"))
+  enum_value (GEGL_MEDIAN_BLUR_NEIGHBORHOOD_DIAMOND, "diamond", N_("Diamond"))
+enum_end (GeglMedianBlurNeighborhood)
+
+property_enum (neighborhood, _("Neighborhood"),
+               GeglMedianBlurNeighborhood, gegl_median_blur_neighborhood,
+               GEGL_MEDIAN_BLUR_NEIGHBORHOOD_CIRCLE)
+  description (_("Neighborhood type"))
+
 property_int  (radius, _("Radius"), 3)
-  value_range (1, 100)
-  description (_("Radius of square pixel region (width and height will be radius*2+1)"))
+  value_range (0, 100)
+  ui_meta     ("unit", "pixel-distance")
+  description (_("Neighborhood radius"))
+
+property_double  (percentile, _("Percentile"), 50)
+  value_range (0, 100)
+  description (_("Neighborhood color percentile"))
+
+property_double  (alpha_percentile, _("Alpha percentile"), 50)
+  value_range (0, 100)
+  description (_("Neighborhood alpha percentile"))
 
 #else
 
@@ -39,13 +60,17 @@ property_int  (radius, _("Radius"), 3)
 
 typedef struct
 {
-  gint       elems[3][N_BINS]; 
-  gint       count;
-  gint       xmin;
-  gint       ymin;
-  gint       xmax;
-  gint       ymax;
-} Histogram; 
+  gint bins[N_BINS];
+  gint last_median;
+  gint last_median_sum;
+} HistogramComponent;
+
+typedef struct
+{
+  HistogramComponent components[4];
+  gint               count;
+  gint               size;
+} Histogram;
 
 typedef enum
 {
@@ -55,174 +80,350 @@ typedef enum
 } Direction;
 
 static inline gfloat
-histogram_get_median (Histogram *hist, gint component)
+histogram_get_median (Histogram *hist,
+                      gint       component,
+                      gdouble    percentile)
 {
-  gint count = hist->count;
-  gint i;
-  gint sum = 0;
+  gint                count = hist->count;
+  HistogramComponent *comp  = &hist->components[component];
+  gint                i     = comp->last_median;
+  gint                sum   = comp->last_median_sum;
 
-  count = (count + 1) / 2;
+  if (component == 3)
+    count = hist->size;
 
-  i = 0;
-  while ((sum += hist->elems[component][i]) < count)
-    i++;
+  if (count == 0)
+    return 0.0f;
 
-  return (gfloat) i / (gfloat) N_BINS;
-}
+  count = (gint) ceil (count * percentile);
+  count = MAX (count, 1);
 
-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++)
+  if (sum < count)
+    {
+      while ((sum += comp->bins[++i]) < count);
+    }
+  else
     {
-      gfloat value = *(src + pos + c);
-      gint idx     = (gint) (CLAMP (value, 0.0, 1.0) * (N_BINS - 1));
-      hist->elems[c][idx]++;
+      while ((sum -= comp->bins[i--]) >= count);
+      sum += comp->bins[++i];
     }
-  hist->count++;
+
+  comp->last_median     = i;
+  comp->last_median_sum = sum;
+
+  return ((gfloat) i + .5f) / (gfloat) N_BINS;
 }
 
 static inline void
-histogram_del_val (Histogram     *hist,
-                   const gfloat  *src,
-                   GeglRectangle *rect,
-                   gint           bpp,
-                   gint           x,
-                   gint           y)
+histogram_modify_val (Histogram    *hist,
+                      const gint32 *src,
+                      gboolean      has_alpha,
+                      gint          diff)
 {
-  const gint pos = (x + y * rect->width) * bpp;
+  gint alpha = diff;
   gint c;
 
+  if (has_alpha)
+    alpha *= src[3];
+
   for (c = 0; c < 3; c++)
     {
-      gfloat value = *(src + pos + c);
-      gint idx     = (gint) (CLAMP (value, 0.0, 1.0) * (N_BINS - 1));
-      hist->elems[c][idx]--;
+      HistogramComponent *comp = &hist->components[c];
+      gint                bin  = src[c];
+
+      comp->bins[bin] += alpha;
+
+      /* this is shorthand for:
+       *
+       *   if (bin <= comp->last_median)
+       *     comp->last_median_sum += alpha;
+       *
+       * but with a notable speed boost.
+       */
+      comp->last_median_sum += (bin <= comp->last_median) * alpha;
+    }
+
+  if (has_alpha)
+    {
+      HistogramComponent *comp = &hist->components[3];
+      gint                bin  = src[3];
+
+      comp->bins[bin] += diff;
+
+      comp->last_median_sum += (bin <= comp->last_median) * diff;
     }
-  hist->count--;
+
+  hist->count += alpha;
 }
 
 static inline void
-histogram_add_vals (Histogram     *hist,
-                    const gfloat  *src,
-                    GeglRectangle *rect,
-                    gint           bpp,
-                    gint           xmin,
-                    gint           ymin,
-                    gint           xmax,
-                    gint           ymax)
+histogram_modify_vals (Histogram    *hist,
+                       const gint32 *src,
+                       gint          bpp,
+                       gint          stride,
+                       gboolean      has_alpha,
+                       gint          xmin,
+                       gint          ymin,
+                       gint          xmax,
+                       gint          ymax,
+                       gint          diff)
 {
   gint x;
   gint y;
 
-  if (xmin > xmax)
+  if (xmin > xmax || ymin > ymax)
     return;
 
-  for (y = ymin; y <= ymax; y++)
+  src += ymin * stride + xmin * bpp;
+
+  for (y = ymin; y <= ymax; y++, src += stride)
     {
-      for (x = xmin; x <= xmax; x++)
+      const gint32 *pixel = src;
+
+      for (x = xmin; x <= xmax; x++, pixel += bpp)
         {
-          histogram_add_val (hist, src, rect, bpp, x, y);
+          histogram_modify_val (hist, pixel, has_alpha, diff);
         }
     }
 }
 
 static inline void
-histogram_del_vals (Histogram     *hist,
-                    const gfloat  *src,
-                    GeglRectangle *rect,
-                    gint           bpp,
-                    gint           xmin,
-                    gint           ymin,
-                    gint           xmax,
-                    gint           ymax)
+histogram_update (Histogram                  *hist,
+                  const gint32               *src,
+                  gint                        bpp,
+                  gint                        stride,
+                  gboolean                    has_alpha,
+                  GeglMedianBlurNeighborhood  neighborhood,
+                  gint                        radius,
+                  const gint                 *neighborhood_outline,
+                  Direction                   dir)
 {
-  gint x;
-  gint y;
-
-  if (xmin > xmax)
-    return;
+  gint i;
 
-  for (y = ymin; y <= ymax; y++)
+  switch (neighborhood)
     {
-      for (x = xmin; x <= xmax; x++)
+    case GEGL_MEDIAN_BLUR_NEIGHBORHOOD_SQUARE:
+      switch (dir)
         {
-          histogram_del_val (hist, src, rect, bpp, x, y);
+          case LEFT_TO_RIGHT:
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -radius - 1, -radius,
+                                   -radius - 1, +radius,
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   +radius, -radius,
+                                   +radius, +radius,
+                                   +1);
+            break;
+
+          case RIGHT_TO_LEFT:
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   +radius + 1, -radius,
+                                   +radius + 1, +radius,
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -radius, -radius,
+                                   -radius, +radius,
+                                   +1);
+            break;
+
+          case TOP_TO_BOTTOM:
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -radius, -radius - 1,
+                                   +radius, -radius - 1,
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -radius, +radius,
+                                   +radius, +radius,
+                                   +1);
+            break;
         }
+      break;
+
+    default:
+      switch (dir)
+        {
+          case LEFT_TO_RIGHT:
+            for (i = 0; i < radius; i++)
+              {
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -i - 1, -neighborhood_outline[i],
+                                       -i - 1, -neighborhood_outline[i + 1] - 1,
+                                       -1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -i - 1, +neighborhood_outline[i + 1] + 1,
+                                       -i - 1, +neighborhood_outline[i],
+                                       -1);
+
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +i, -neighborhood_outline[i],
+                                       +i, -neighborhood_outline[i + 1] - 1,
+                                       +1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +i, +neighborhood_outline[i + 1] + 1,
+                                       +i, +neighborhood_outline[i],
+                                       +1);
+              }
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -i - 1, -neighborhood_outline[i],
+                                   -i - 1, +neighborhood_outline[i],
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   +i, -neighborhood_outline[i],
+                                   +i, +neighborhood_outline[i],
+                                   +1);
+
+            break;
+
+          case RIGHT_TO_LEFT:
+            for (i = 0; i < radius; i++)
+              {
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +i + 1, -neighborhood_outline[i],
+                                       +i + 1, -neighborhood_outline[i + 1] - 1,
+                                       -1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +i + 1, +neighborhood_outline[i + 1] + 1,
+                                       +i + 1, +neighborhood_outline[i],
+                                       -1);
+
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -i, -neighborhood_outline[i],
+                                       -i, -neighborhood_outline[i + 1] - 1,
+                                       +1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -i, +neighborhood_outline[i + 1] + 1,
+                                       -i, +neighborhood_outline[i],
+                                       +1);
+              }
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   +i + 1, -neighborhood_outline[i],
+                                   +i + 1, +neighborhood_outline[i],
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -i, -neighborhood_outline[i],
+                                   -i, +neighborhood_outline[i],
+                                   +1);
+
+            break;
+
+          case TOP_TO_BOTTOM:
+            for (i = 0; i < radius; i++)
+              {
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -neighborhood_outline[i],         -i - 1,
+                                       -neighborhood_outline[i + 1] - 1, -i - 1,
+                                       -1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +neighborhood_outline[i + 1] + 1, -i - 1,
+                                       +neighborhood_outline[i],         -i - 1,
+                                       -1);
+
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       -neighborhood_outline[i],         +i,
+                                       -neighborhood_outline[i + 1] - 1, +i,
+                                       +1);
+                histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                       +neighborhood_outline[i + 1] + 1, +i,
+                                       +neighborhood_outline[i],         +i,
+                                       +1);
+              }
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -neighborhood_outline[i], -i - 1,
+                                   +neighborhood_outline[i], -i - 1,
+                                   -1);
+
+            histogram_modify_vals (hist, src, bpp, stride, has_alpha,
+                                   -neighborhood_outline[i], +i,
+                                   +neighborhood_outline[i], +i,
+                                   +1);
+
+            break;
+        }
+      break;
     }
 }
 
-static inline void
-histogram_update (Histogram     *hist,
-                  const gfloat  *src,
-                  GeglRectangle *rect,
-                  gint           bpp,
-                  gint           xmin,
-                  gint           ymin,
-                  gint           xmax,
-                  gint           ymax,
-                  Direction      dir)
+static void
+init_neighborhood_outline (GeglMedianBlurNeighborhood  neighborhood,
+                           gint                        radius,
+                           gint                       *neighborhood_outline)
 {
-  switch (dir)
+  gint i;
+
+  for (i = 0; i <= radius; i++)
     {
-      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;
+      switch (neighborhood)
+        {
+        case GEGL_MEDIAN_BLUR_NEIGHBORHOOD_SQUARE:
+          neighborhood_outline[i] = radius;
+          break;
+
+        case GEGL_MEDIAN_BLUR_NEIGHBORHOOD_CIRCLE:
+          neighborhood_outline[i] =
+            (gint) sqrt ((radius + .5) * (radius + .5) - i * i);
+          break;
+
+        case GEGL_MEDIAN_BLUR_NEIGHBORHOOD_DIAMOND:
+          neighborhood_outline[i] = radius - i;
+          break;
+        }
     }
+}
+
+static void
+convert_values_to_bins (gint32   *src,
+                        gint      bpp,
+                        gboolean  has_alpha,
+                        gint      count)
+{
+  gint components = 3;
+  gint c;
+
+  if (has_alpha)
+    components++;
+
+  while (count--)
+    {
+      for (c = 0; c < components; c++)
+        {
+          gfloat value = ((gfloat *) src)[c];
+          gint   bin;
+
+          bin = (gint) (CLAMP (value, 0.0f, 1.0f) * N_BINS);
+          bin = MIN (bin, N_BINS - 1);
+
+          src[c] = bin;
+        }
 
-  hist->xmin = xmin;
-  hist->ymin = ymin;
-  hist->xmax = xmax;
-  hist->ymax = ymax;
+      src += bpp;
+    }
 }
 
 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");;
+  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;
 
+  o->user_data = g_renew (gint, o->user_data, o->radius + 1);
+  init_neighborhood_outline (o->neighborhood, o->radius, o->user_data);
+
   if (in_format)
     {
       if (babl_format_has_alpha (in_format))
@@ -255,61 +456,71 @@ process (GeglOperation       *operation,
          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);
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+
+  gdouble         percentile           = o->percentile       / 100.0;
+  gdouble         alpha_percentile     = o->alpha_percentile / 100.0;
+  const gint     *neighborhood_outline = o->user_data;
+
+  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);
+
+  G_STATIC_ASSERT (sizeof (gint32) == sizeof (gfloat));
+  gint32         *src_buf;
+  gfloat         *dst_buf;
+  GeglRectangle   src_rect;
+  gint            src_stride;
+  gint            dst_stride;
+  gint            n_pixels;
+
+  Histogram      *hist;
+
+  const gint32   *src;
+  gfloat         *dst;
+  gint            dst_x, dst_y;
+  Direction       dir;
+
+  gint            i;
+  gint            c;
+
+  src_rect   = gegl_operation_get_required_for_output (operation, "input", roi);
+  src_stride = src_rect.width * n_components;
+  dst_stride = roi->width * n_components;
+  n_pixels   = roi->width * roi->height;
+  dst_buf = g_new0 (gfloat, n_pixels                         * n_components);
+  src_buf = g_new0 (gint32, 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);
+  convert_values_to_bins (src_buf, n_components, has_alpha,
+                          src_rect.width * src_rect.height);
 
   hist = g_slice_new0 (Histogram);
 
-  dst_x = 0;
-  dst_y = 0;
-  src_x = o->radius;
-  src_y = o->radius;
+  src = src_buf + o->radius * (src_rect.width + 1) * n_components;
+  dst = dst_buf;
 
   /* 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;
+  for (i = -o->radius; i <= o->radius; i++)
+    {
+      histogram_modify_vals (hist, src, n_components, src_stride, has_alpha,
+                             i, -neighborhood_outline[abs (i)],
+                             i, +neighborhood_outline[abs (i)],
+                             +1);
 
-  histogram_add_vals (hist, src_buf, &src_rect, n_components,
-                      hist->xmin, hist->ymin,
-                      hist->xmax, hist->ymax);
+      hist->size += 2 * neighborhood_outline[abs (i)] + 1;
+    }
 
-  dst_idx = (dst_x + dst_y * roi->width) * n_components;
+  for (c = 0; c < 3; c++)
+    dst[c] = histogram_get_median (hist, c, percentile);
 
-  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];
-    }
+    dst[3] = histogram_get_median (hist, 3, alpha_percentile);
+
+  dst_x = 0;
+  dst_y = 0;
 
   n_pixels--;
   dir = LEFT_TO_RIGHT;
@@ -321,28 +532,32 @@ process (GeglOperation       *operation,
         {
           if (dst_x != roi->width - 1)
             {
-              src_x++;
               dst_x++;
+              src += n_components;
+              dst += n_components;
             }
           else
             {
-              src_y++;
               dst_y++;
-              dir = TOP_TO_BOTTOM; 
+              src += src_stride;
+              dst += dst_stride;
+              dir = TOP_TO_BOTTOM;
             }
         }
       else if (dir == TOP_TO_BOTTOM)
         {
           if (dst_x == 0)
             {
-              src_x++;
               dst_x++;
+              src += n_components;
+              dst += n_components;
               dir = LEFT_TO_RIGHT;
             }
           else
             {
-              src_x--;
               dst_x--;
+              src -= n_components;
+              dst -= n_components;
               dir = RIGHT_TO_LEFT;
             }
         }
@@ -350,56 +565,66 @@ process (GeglOperation       *operation,
         {
           if (dst_x != 0)
             {
-              src_x--;
               dst_x--;
+              src -= n_components;
+              dst -= n_components;
             }
           else
             {
-              src_y++;
               dst_y++;
-              dir = TOP_TO_BOTTOM; 
+              src += src_stride;
+              dst += dst_stride;
+              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, n_components, src_stride, has_alpha,
+                        o->neighborhood, o->radius, neighborhood_outline,
+                        dir);
 
-      histogram_update (hist, src_buf, &src_rect, n_components,
-                        xmin, ymin, xmax, ymax, dir);
+      for (c = 0; c < 3; c++)
+        dst[c] = histogram_get_median (hist, c, percentile);
 
-      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];
-        }
+        dst[3] = histogram_get_median (hist, 3, alpha_percentile);
     }
 
   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);
- 
+  g_free (dst_buf);
+  g_free (src_buf);
+
   return TRUE;
 }
 
 static void
+finalize (GObject *object)
+{
+  GeglOperation  *op = (void*) object;
+  GeglProperties *o  = GEGL_PROPERTIES (op);
+
+  if (o->user_data)
+    {
+      g_free (o->user_data);
+      o->user_data = NULL;
+    }
+
+  G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+}
+
+static void
 gegl_op_class_init (GeglOpClass *klass)
 {
+  GObjectClass             *object_class;
   GeglOperationClass       *operation_class;
   GeglOperationFilterClass *filter_class;
 
+  object_class    = G_OBJECT_CLASS (klass);
   operation_class = GEGL_OPERATION_CLASS (klass);
   filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
 
+  object_class->finalize            = finalize;
   filter_class->process             = process;
   operation_class->prepare          = prepare;
   operation_class->get_bounding_box = get_bounding_box;
@@ -409,7 +634,7 @@ gegl_op_class_init (GeglOpClass *klass)
     "title",       _("Median Blur"),
     "categories",  "blur",
     "description", _("Blur resulting from computing the median "
-                     "color of in a square neighbourhood."),
+                     "color in the neighborhood of each pixel."),
     NULL);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]