Blame operations/workshop/box-percentile.c

Packit bc1512
/* This file is an image processing operation for GEGL
Packit bc1512
 *
Packit bc1512
 * GEGL is free software; you can redistribute it and/or
Packit bc1512
 * modify it under the terms of the GNU Lesser General Public
Packit bc1512
 * License as published by the Free Software Foundation; either
Packit bc1512
 * version 3 of the License, or (at your option) any later version.
Packit bc1512
 *
Packit bc1512
 * GEGL is distributed in the hope that it will be useful,
Packit bc1512
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bc1512
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit bc1512
 * Lesser General Public License for more details.
Packit bc1512
 *
Packit bc1512
 * You should have received a copy of the GNU Lesser General Public
Packit bc1512
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit bc1512
 *
Packit bc1512
 * Copyright 2005 Øyvind Kolås <pippin@gimp.org>,
Packit bc1512
 *           2007 Øyvind Kolås <oeyvindk@hig.no>
Packit bc1512
 */
Packit bc1512
Packit bc1512
Packit bc1512
#include "config.h"
Packit bc1512
#include <glib/gi18n-lib.h>
Packit bc1512
Packit bc1512
Packit bc1512
#ifdef GEGL_CHANT_PROPERTIES
Packit bc1512
Packit bc1512
gegl_chant_double (radius, _("Radius"), 0.0, 70.0, 4.0,
Packit bc1512
  _("Radius of square pixel region (width and height will be radius*2+1)"))
Packit bc1512
gegl_chant_double (percentile, _("Percentile"), 0.0, 100.0, 50,
Packit bc1512
  _("The percentile to compute, defaults to 50, which is a median filter"))
Packit bc1512
Packit bc1512
#else
Packit bc1512
Packit bc1512
#define MAX_SAMPLES 20000 /* adapted to max level of radius */
Packit bc1512
Packit bc1512
#define GEGL_CHANT_TYPE_AREA_FILTER
Packit bc1512
#define GEGL_CHANT_C_FILE       "box-percentile.c"
Packit bc1512
Packit bc1512
#include "gegl-chant.h"
Packit bc1512
#include <stdio.h>
Packit bc1512
#include <math.h>
Packit bc1512
Packit bc1512
static void median (GeglBuffer *src,
Packit bc1512
                    GeglBuffer *dst,
Packit bc1512
                    gint        radius,
Packit bc1512
                    gdouble     rank);
Packit bc1512
Packit bc1512
Packit bc1512
static void prepare (GeglOperation *operation)
Packit bc1512
{
Packit bc1512
  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
Packit bc1512
  GeglChantO              *o = GEGL_CHANT_PROPERTIES (operation);
Packit bc1512
  area->left = area->right = area->top = area->bottom = ceil (o->radius);
Packit bc1512
Packit bc1512
  gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
Packit bc1512
}
Packit bc1512
Packit bc1512
static gboolean
Packit bc1512
process (GeglOperation       *operation,
Packit bc1512
         GeglBuffer          *input,
Packit bc1512
         GeglBuffer          *output,
Packit bc1512
         const GeglRectangle *result,
Packit bc1512
         gint                 level)
Packit bc1512
{
Packit bc1512
  GeglChantO   *o = GEGL_CHANT_PROPERTIES (operation);
Packit bc1512
  GeglBuffer   *temp_in;
Packit bc1512
  GeglRectangle compute = gegl_operation_get_required_for_output (operation, "input", result);
Packit bc1512
Packit bc1512
  if (o->radius < 1.0)
Packit bc1512
    {
Packit bc1512
      output = g_object_ref (input);
Packit bc1512
    }
Packit bc1512
  else
Packit bc1512
    {
Packit bc1512
      temp_in = gegl_buffer_create_sub_buffer (input, &compute);
Packit bc1512
Packit bc1512
      median (temp_in, output, o->radius, o->percentile / 100.0);
Packit bc1512
      g_object_unref (temp_in);
Packit bc1512
    }
Packit bc1512
Packit bc1512
  return  TRUE;
Packit bc1512
}
Packit bc1512
Packit bc1512
Packit bc1512
typedef struct
Packit bc1512
{
Packit bc1512
  int       head;
Packit bc1512
  int       next[MAX_SAMPLES];
Packit bc1512
  float     luma[MAX_SAMPLES];
Packit bc1512
  float    *pixel[MAX_SAMPLES];
Packit bc1512
  int       items;
Packit bc1512
} RankList;
Packit bc1512
Packit bc1512
static void
Packit bc1512
list_clear (RankList * p)
Packit bc1512
{
Packit bc1512
  p->items = 0;
Packit bc1512
  p->next[0] = -1;
Packit bc1512
}
Packit bc1512
Packit bc1512
static inline void
Packit bc1512
list_add (RankList *p,
Packit bc1512
          gfloat    lumniosity,
Packit bc1512
          gfloat   *pixel)
Packit bc1512
{
Packit bc1512
  gint location;
Packit bc1512
Packit bc1512
  location = p->items;
Packit bc1512
Packit bc1512
  p->items++;
Packit bc1512
  p->luma[location] = lumniosity;
Packit bc1512
  p->pixel[location] = pixel;
Packit bc1512
  p->next[location] = -1;
Packit bc1512
Packit bc1512
  if (p->items == 1)
Packit bc1512
    {
Packit bc1512
      p->head = location;
Packit bc1512
      return;
Packit bc1512
    }
Packit bc1512
  if (lumniosity <= p->luma[p->head])
Packit bc1512
    {
Packit bc1512
      p->next[location] = p->head;
Packit bc1512
      p->head = location;
Packit bc1512
    }
Packit bc1512
  else
Packit bc1512
    {
Packit bc1512
      gint   prev, i;
Packit bc1512
      prev = p->head;
Packit bc1512
      i = prev;
Packit bc1512
      while (i >= 0 && p->luma[i] < lumniosity)
Packit bc1512
        {
Packit bc1512
          prev = i;
Packit bc1512
          i = p->next[i];
Packit bc1512
        }
Packit bc1512
      p->next[location] = p->next[prev];
Packit bc1512
      p->next[prev] = location;
Packit bc1512
    }
Packit bc1512
}
Packit bc1512
Packit bc1512
static inline gfloat *
Packit bc1512
list_percentile (RankList *p,
Packit bc1512
                 gdouble   percentile)
Packit bc1512
{
Packit bc1512
  gint       i = p->head;
Packit bc1512
  gint       pos = 0;
Packit bc1512
  if (!p->items)
Packit bc1512
    return NULL;
Packit bc1512
  if (percentile >= 1.0)
Packit bc1512
    percentile = 1.0;
Packit bc1512
  while (pos < p->items * percentile &&
Packit bc1512
         p->pixel[p->next[i]])
Packit bc1512
    {
Packit bc1512
      i = p->next[i];
Packit bc1512
      pos++;
Packit bc1512
    }
Packit bc1512
  return p->pixel[i];
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
median (GeglBuffer *src,
Packit bc1512
        GeglBuffer *dst,
Packit bc1512
        gint        radius,
Packit bc1512
        gdouble     rank)
Packit bc1512
{
Packit bc1512
  RankList list={0};
Packit bc1512
Packit bc1512
  gint x,y;
Packit bc1512
  gint offset;
Packit bc1512
  gfloat *src_buf;
Packit bc1512
  gfloat *dst_buf;
Packit bc1512
Packit bc1512
Packit bc1512
  src_buf = g_malloc0 (gegl_buffer_get_pixel_count (src) * 4 * 4);
Packit bc1512
  dst_buf = g_malloc0 (gegl_buffer_get_pixel_count (dst) * 4 * 4);
Packit bc1512
Packit bc1512
  gegl_buffer_get (src, NULL, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE,
Packit bc1512
                   GEGL_ABYSS_NONE);
Packit bc1512
Packit bc1512
  offset = 0;
Packit bc1512
  for (y=0; y
Packit bc1512
    for (x=0; x
Packit bc1512
      {
Packit bc1512
        gint u,v;
Packit bc1512
        gfloat *median_pix;
Packit bc1512
Packit bc1512
        list_clear (&list);
Packit bc1512
Packit bc1512
        for (v=y-radius;v<=y+radius;v++)
Packit bc1512
          for (u=x-radius;u<=x+radius;u++)
Packit bc1512
            {
Packit bc1512
              if (u >= 0 && u < gegl_buffer_get_width (dst) &&
Packit bc1512
                  v >= 0 && v < gegl_buffer_get_height (dst))
Packit bc1512
                {
Packit bc1512
                  gfloat *src_pix = src_buf + (u+(v * gegl_buffer_get_width (src))) * 4;
Packit bc1512
                  gfloat luma = (src_pix[0] * 0.212671 +
Packit bc1512
                                 src_pix[1] * 0.715160 +
Packit bc1512
                                 src_pix[2] * 0.072169);
Packit bc1512
                  list_add (&list, luma, src_pix);
Packit bc1512
                }
Packit bc1512
            }
Packit bc1512
Packit bc1512
        median_pix = list_percentile (&list, rank);
Packit bc1512
        for (u=0; u<4;u++)
Packit bc1512
          dst_buf[offset*4+u] = median_pix[u];
Packit bc1512
        offset++;
Packit bc1512
      }
Packit bc1512
  gegl_buffer_set (dst, NULL, 0, babl_format ("RGBA float"), dst_buf,
Packit bc1512
                   GEGL_AUTO_ROWSTRIDE);
Packit bc1512
  g_free (src_buf);
Packit bc1512
  g_free (dst_buf);
Packit bc1512
}
Packit bc1512
Packit bc1512
Packit bc1512
static void
Packit bc1512
gegl_chant_class_init (GeglChantClass *klass)
Packit bc1512
{
Packit bc1512
  GeglOperationClass       *operation_class;
Packit bc1512
  GeglOperationFilterClass *filter_class;
Packit bc1512
Packit bc1512
  operation_class = GEGL_OPERATION_CLASS (klass);
Packit bc1512
  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
Packit bc1512
Packit bc1512
  filter_class->process = process;
Packit bc1512
  operation_class->prepare = prepare;
Packit bc1512
Packit bc1512
  gegl_operation_class_set_keys (operation_class,
Packit bc1512
    "name"       , "gegl:box-percentile",
Packit bc1512
    "categories" , "misc",
Packit bc1512
    "description",
Packit bc1512
        _("Sets the target pixel to the color corresponding to a given percentile "
Packit bc1512
          "when colors are sorted by luminance"),
Packit bc1512
        NULL);
Packit bc1512
}
Packit bc1512
Packit bc1512
#endif