[gegl] median-blur: various additions
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] median-blur: various additions
- Date: Sun, 12 Feb 2017 18:36:02 +0000 (UTC)
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]