[gegl: 13/55] Oilify Operation: Stop using samplers.



commit ebfd3d401db82bb26b8aea06a0d6f6e2cee040d5
Author: Hans Lo <hansshulo gmail com>
Date:   Thu Jul 12 18:36:27 2012 -0400

    Oilify Operation: Stop using samplers.
    
    Significant speed up.

 operations/common/oilify.c |  284 +++++++++++++++++++++++++++-----------------
 1 files changed, 173 insertions(+), 111 deletions(-)
---
diff --git a/operations/common/oilify.c b/operations/common/oilify.c
index 7afb6c4..5c3e97f 100644
--- a/operations/common/oilify.c
+++ b/operations/common/oilify.c
@@ -24,16 +24,14 @@
 
 #ifdef GEGL_CHANT_PROPERTIES
 
-gegl_chant_double (mask_radius, _("Mask Radius"), 1.0, 25.0, 4.0,
-                   _("Radius of circle around pixel"))
+gegl_chant_int (mask_radius, _("Mask Radius"), 1, 25, 4,
+                _("Radius of circle around pixel"))
 
 gegl_chant_double (exponent, _("Exponent"), 1.0, 20.0, 8.0,
                    _("Exponent"))
 
-gegl_chant_boolean (use_inten, _("Intensity Mode"), TRUE, _("Use pixel luminance values"))
-
-gegl_chant_enum (sampler_type, _("Sampler"), GeglSamplerType, gegl_sampler_type,
-                 GEGL_SAMPLER_CUBIC, _("Sampler used internally"))
+gegl_chant_boolean (use_inten, _("Intensity Mode"), TRUE,
+                    _("Use pixel luminance values"))
 
 #else
 
@@ -46,18 +44,48 @@ gegl_chant_enum (sampler_type, _("Sampler"), GeglSamplerType, gegl_sampler_type,
 
 #define NUM_INTENSITIES       256
 
-  static void oilify_pixel (gint x,
-			    gint y,
-			    gboolean use_inten,
-			    gdouble radius,
-			    gdouble exponent,
-			    GeglSampler *sampler,
-			    GeglSampler *sampler_inten,
-			    gfloat *dst_pixel)
+/* Get the pixel from x, y offset from the center pixel src_pix */
+static void
+get_pixel(gint x,
+          gint y,
+          gint buf_width,
+          gfloat* src_begin,
+          gfloat* dst)
+{
+  gint b;
+  gfloat* src = src_begin + 4*(x + buf_width*y);
+  for (b = 0; b < 4; b++)
+    {
+      dst[b] = src[b];
+    }
+}
+
+static void
+get_pixel_inten(gint x,
+                gint y,
+                gint buf_width,
+                gfloat* inten_begin,
+                gfloat* dst)
+{
+  *dst = *(inten_begin + (x + buf_width*y));
+}
+
+static void
+oilify_pixel (gint x,
+              gint y,
+              GeglRectangle *whole_rect,
+              gboolean use_inten,
+              gdouble radius,
+              gdouble exponent,
+              gint buf_width,
+              gfloat *src_buf,
+              gfloat *inten_buf,
+              gfloat *dst_pixel)
 {
   gint hist[4][NUM_INTENSITIES];
   gfloat cumulative_rgb[4][NUM_INTENSITIES];
   gint hist_inten[NUM_INTENSITIES];
+  gfloat mult_inten[NUM_INTENSITIES];
   gfloat temp_pixel[4];
   gfloat temp_inten_pixel;
   gint ceil_radius = ceil(radius);
@@ -71,99 +99,118 @@ gegl_chant_enum (sampler_type, _("Sampler"), GeglSamplerType, gegl_sampler_type,
   gfloat weight;
   gfloat color;
   gfloat result;
-
+  gfloat div;
   for (i = 0; i < NUM_INTENSITIES; i++)
     {
       hist_inten[i] = 0;
       for (b = 0; b < 4; b++)
-	{
-	  hist[b][i] = 0;
-	  cumulative_rgb[b][i] = 0.0;
-	}
+        {
+          hist[b][i] = 0;
+          cumulative_rgb[b][i] = 0.0;
+        }
     }
 
-  for (i = -ceil_radius; i < ceil_radius; i++)
+  /* calculate histograms */
+  for (i = -ceil_radius; i <= ceil_radius; i++)
     {
-      for (j = -ceil_radius; j < ceil_radius; j++)
-	{
-	  if (i*i + j*j < radius_sq) 
-	    {
-	      gegl_sampler_get (sampler,
-				x+i,
-				y+j,
-				NULL,
-				temp_pixel);
-	      
-	      if (use_inten)
-		{
-		  
-		  gegl_sampler_get (sampler_inten,
-				    x+i,
-				    y+j,
-				    NULL,
-				    &temp_inten_pixel);
-		  intensity = temp_inten_pixel * NUM_INTENSITIES;
-		  hist_inten[intensity]++;
-		  for (b = 0; b < 4; b++) 
-		    {
-		      cumulative_rgb[b][intensity] += temp_pixel[b];
-		    }
-		}
-	      else 
-		{
-		  for (b = 0; b < 4; b++) 
-		    {
-		      intensity = temp_pixel[b] * NUM_INTENSITIES;
-		      hist[b][intensity]++;
-		    }
-		}
-	    }
-	}
+      for (j = -ceil_radius; j <= ceil_radius; j++)
+        {
+          if (i*i + j*j <= radius_sq)
+            {
+              if (x + i < 0 ||
+                  x + i > whole_rect->width ||
+                  y + j < 0 ||
+                  y + j > whole_rect->height)
+                {
+                  if (x + i < 0)
+                    g_print("%d %d\n", x+i, y+j);
+                  continue;
+                }
+              get_pixel (x + i,
+                         y + j,
+                         buf_width,
+                         src_buf,
+                         temp_pixel);
+
+              if (use_inten)
+                {
+                  get_pixel_inten (x + i,
+                                   y + j,
+                                   buf_width,
+                                   inten_buf,
+                                   &temp_inten_pixel);
+                  intensity = temp_inten_pixel * NUM_INTENSITIES;
+                  hist_inten[intensity]++;
+                  for (b = 0; b < 4; b++)
+                    {
+                      cumulative_rgb[b][intensity] += temp_pixel[b];
+                    }
+                }
+              else
+                {
+                  for (b = 0; b < 4; b++)
+                    {
+                      intensity = temp_pixel[b] * NUM_INTENSITIES;
+                      hist[b][intensity]++;
+                    }
+                }
+            }
+        }
     }
-  
+
   inten_max = 1;
 
   /* calculated maximums */
   for (i = 0; i < NUM_INTENSITIES; i++) {
     inten_max = MAX (inten_max, hist_inten[i]);
   }
-  
-  for (b = 0; b < 4; b++) 
+
+  for (b = 0; b < 4; b++)
     {
       hist_max[b] = 1;
       for (i = 0; i < NUM_INTENSITIES; i++) {
-	hist_max[b] = MAX (hist_max[b], hist[b][i]);
+        hist_max[b] = MAX (hist_max[b], hist[b][i]);
       }
     }
-  
+
   /* calculate weight and use it to set the pixel */
-  for (b = 0; b < 4; b++) 
+  div = 0.0;
+  for (i = 0; i < NUM_INTENSITIES; i++)
+    {
+      if (use_inten && hist_inten[i] > 0)
+        {
+          ratio = (gfloat) hist_inten[i] / (gfloat) inten_max;
+          weight = pow (ratio, exponent);
+          mult_inten[i] = weight / (gfloat) hist_inten[i];
+          div += weight;
+        }
+    }
+  for (b = 0; b < 4; b++)
     {
       sum = 0.0;
       color = 0.0;
       if (use_inten)
-	{
-	  for (i = 0; i < NUM_INTENSITIES; i++)  
-	    {
-	      ratio = (gfloat) hist_inten[i] / (gfloat) inten_max;
-	      weight = pow (ratio, exponent);
-	      if (hist_inten[i] > 0)
-		color += weight * cumulative_rgb[b][i] / (gfloat) hist_inten[i];
-	    }
-	  result = color;
-	  dst_pixel[b] = result;
-	}
+        {
+          for (i = 0; i < NUM_INTENSITIES; i++)
+            {
+              if (hist_inten[i] > 0)
+                color += mult_inten[i] * cumulative_rgb[b][i];
+            }
+          dst_pixel[b] = color/div;
+        }
       else
-	{ 
-	  for (i = 0; i < NUM_INTENSITIES; i++)
-	    {
-	      ratio = (gfloat) hist[b][i] / (gfloat) hist_max[b];
-	      weight = pow (ratio, exponent);
-	      sum += weight * (gfloat) i;
-	    }
-	  result = sum / (gfloat) NUM_INTENSITIES;
-	  dst_pixel[b] = result;
-	}
+        {
+          div = 0.0;
+          for (i = 0; i < NUM_INTENSITIES; i++)
+            {
+              ratio = (gfloat) hist[b][i] / (gfloat) hist_max[b];
+              weight = pow (ratio, exponent);
+              sum += weight * (gfloat) i;
+              div += weight;
+            }
+          result = sum / (gfloat) NUM_INTENSITIES;
+          dst_pixel[b] = result/div;
+        }
     }
 }
 
@@ -175,9 +222,9 @@ static void prepare (GeglOperation *operation)
   op_area = GEGL_OPERATION_AREA_FILTER (operation);
   o       = GEGL_CHANT_PROPERTIES (operation);
 
-  op_area->left   = 
-    op_area->right  = 
-    op_area->top    = 
+  op_area->left   =
+    op_area->right  =
+    op_area->top    =
     op_area->bottom = o->mask_radius;
 
   gegl_operation_set_format (operation, "input",
@@ -194,50 +241,65 @@ process (GeglOperation       *operation,
          gint                 level)
 {
   GeglChantO *o                    = GEGL_CHANT_PROPERTIES (operation);
+  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
+
+  GeglRectangle* whole_rect;
+  gint x = o->mask_radius; /* initial x                   */
+  gint y = o->mask_radius; /*           and y coordinates */
+  gfloat *src_buf;
+  gfloat *dst_buf;
+  gfloat *inten_buf;
+  gfloat *out_pixel;
+  gint n_pixels = result->width * result->height;
+  GeglRectangle src_rect;
+  gint total_pixels;
 
-  gint x = result->x; /* initial x                   */
-  gint y = result->y; /*           and y coordinates */
-  
-  gfloat *dst_buf = g_slice_alloc (result->width * result->height * 4 * sizeof(gfloat));
+  whole_rect = gegl_operation_source_get_bounding_box (operation, "input");
 
-  gfloat *out_pixel = dst_buf;
+  src_rect.x      = result->x - op_area->left;
+  src_rect.width  = result->width + op_area->left + op_area->right;
+  src_rect.y      = result->y - op_area->top;
+  src_rect.height = result->height + op_area->top + op_area->bottom;
 
-  GeglSampler *sampler = gegl_buffer_sampler_new (input,
-                                                  babl_format ("RGBA float"),
-                                                  o->sampler_type);
+  total_pixels = src_rect.width * src_rect.height;
 
-  GeglSampler *sampler_inten = gegl_buffer_sampler_new (input,
-							babl_format ("Y float"),
-							o->sampler_type);
+  src_buf = g_slice_alloc (4 * total_pixels * sizeof(gfloat));
+  dst_buf = g_slice_alloc (4 * total_pixels * sizeof(gfloat));
+  inten_buf = g_slice_alloc (total_pixels * sizeof(gfloat));
 
-  gint n_pixels = result->width * result->height;
+  gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RGBA float"),
+                   src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+  gegl_buffer_get (input, &src_rect, 1.0, babl_format ("Y float"),
+                   inten_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
 
+  out_pixel = dst_buf;
   while (n_pixels--)
     {
-      
-      oilify_pixel(x, y, o->use_inten, o->mask_radius, o->exponent, 
-		   sampler, sampler_inten, out_pixel);
+      oilify_pixel(x, y, whole_rect, o->use_inten, o->mask_radius, o->exponent,
+                   src_rect.width, src_buf, inten_buf, out_pixel);
 
       out_pixel += 4;
 
       /* update x and y coordinates */
       x++;
-      if (x>=result->x + result->width)
+      if (x >= result->width + o->mask_radius)
         {
-          x=result->x;
+          x=o->mask_radius;
           y++;
         }
     }
 
-  gegl_buffer_set (output, result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
-  g_slice_free1 (result->width * result->height * 4 * sizeof(gfloat), dst_buf);
-
-  g_object_unref (sampler);
+  gegl_buffer_set (output, result, 0,
+                   babl_format ("RGBA float"),
+                   dst_buf, GEGL_AUTO_ROWSTRIDE);
+  g_slice_free1 (4 * total_pixels * sizeof(gfloat), src_buf);
+  g_slice_free1 (4 * total_pixels * sizeof(gfloat), dst_buf);
+  g_slice_free1 (total_pixels * sizeof(gfloat), inten_buf);
 
   return  TRUE;
 }
 
-
 static void
 gegl_chant_class_init (GeglChantClass *klass)
 {
@@ -251,9 +313,9 @@ gegl_chant_class_init (GeglChantClass *klass)
   operation_class->prepare = prepare;
 
   gegl_operation_class_set_keys (operation_class,
-				 "categories" , "artistic",
-				 "name"       , "gegl:oilify",
-				 "description", _("Emulate an oil painting"),
-				 NULL);
+                                 "categories" , "artistic",
+                                 "name"       , "gegl:oilify",
+                                 "description", _("Emulate an oil painting"),
+                                 NULL);
 }
 #endif



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