[gegl] workshop: add integral-image operation



commit b5c9f9052c5b94ca55a0f9b781aaebd3d9b66767
Author: Thomas Manni <thomas manni free fr>
Date:   Sun Jan 29 15:53:49 2017 +0100

    workshop: add integral-image operation

 operations/workshop/Makefile.am      |    1 +
 operations/workshop/integral-image.c |  258 ++++++++++++++++++++++++++++++++++
 po/POTFILES.in                       |    1 +
 3 files changed, 260 insertions(+), 0 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 7569c28..8f9220e 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -20,6 +20,7 @@ op_LTLIBRARIES =    \
        gradient-map.la \
        hstack.la \
        image-gradient.la \
+       integral-image.la \
        kuwahara.la \
        mandelbrot.la \
        median-blur.la \
diff --git a/operations/workshop/integral-image.c b/operations/workshop/integral-image.c
new file mode 100644
index 0000000..7467725
--- /dev/null
+++ b/operations/workshop/integral-image.c
@@ -0,0 +1,258 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2017 Thomas Manni <thomas manni free fr>
+ *
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_boolean (squared, _("squared integral"), FALSE)
+  description (_("Add squared values sum to the output"))
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME         integral_image
+#define GEGL_OP_C_SOURCE     integral-image.c
+
+#include "gegl-op.h"
+
+#define SQR(x) ((x) * (x))
+
+static inline void
+compute_row_integral (gdouble  *src_row,
+                      gdouble  *top_row,
+                      gdouble  *dst_row,
+                      gint      width,
+                      gint      n_components,
+                      gboolean  squared)
+{
+  gint b;
+
+  if (squared)
+    {
+      while (width--)
+        {
+          for (b = 0; b < n_components; b++)
+            {
+              dst_row[b] = src_row[b] +
+                           dst_row[b - n_components] +
+                           top_row[b] -
+                           top_row[b - n_components];
+
+              dst_row[b + n_components] =   SQR(src_row[b])
+                                          + dst_row[b - n_components * 2]
+                                          + top_row[b + n_components]
+                                          - top_row[b - n_components * 2];
+            }
+
+          src_row += n_components;
+          top_row += n_components * 2;
+          dst_row += n_components * 2;
+        }
+    }
+  else
+    {
+      while (width--)
+        {
+          for (b = 0; b < n_components; b++)
+            dst_row[b] =   src_row[b]
+                         + dst_row[b - n_components]
+                         + top_row[b]
+                         - top_row[b - n_components];
+
+          src_row += n_components;
+          top_row += n_components;
+          dst_row += n_components;
+        }
+    }
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+  const Babl *src_format   = gegl_operation_get_source_format (operation, "input");
+  const Babl *input_format = babl_format ("RGB double");
+  gint        n_components = 3;
+  const Babl *output_format;
+
+  if (src_format)
+    {
+      const Babl *model = babl_format_get_model (src_format);
+
+      if (model == babl_model ("RGB") || model == babl_model ("R'G'B'") ||
+          model == babl_model ("RGBA") || model == babl_model ("R'G'B'A"))
+        {
+          input_format = babl_format ("RGB double");
+          n_components = 3;
+        }
+      else if (model == babl_model ("Y") || model == babl_model ("Y'") ||
+               model == babl_model ("YA") || model == babl_model ("Y'A"))
+        {
+          input_format = babl_format ("Y double");
+          n_components = 1;
+        }
+    }
+
+  if (o->squared)
+    n_components *= 2;
+
+  output_format = babl_format_n (babl_type ("double"), n_components);
+
+  gegl_operation_set_format (operation, "input", input_format);
+  gegl_operation_set_format (operation, "output", output_format);
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result,
+         gint                 level)
+{
+  GeglProperties *o        = GEGL_PROPERTIES (operation);
+  const Babl *src_format   = gegl_operation_get_source_format (operation, "input");
+  const Babl *dst_format   = gegl_operation_get_format (operation, "output");
+  gint        src_components = babl_format_get_n_components (src_format);
+  gint        dst_components = babl_format_get_n_components (dst_format);
+
+  gint     width, height;
+  gint     row_size;
+  gint     y;
+  gdouble *top_row  = NULL;
+  gdouble *dst_row  = NULL;
+  gdouble *src_row  = NULL;
+  gdouble *p_top    = NULL;
+  gdouble *p_dst    = NULL;
+
+  width = gegl_buffer_get_width (input);
+  height = gegl_buffer_get_height (input);
+  row_size = width + 1;
+
+  top_row = g_new0 (gdouble, row_size * dst_components);
+  dst_row = g_new0 (gdouble, row_size * dst_components);
+  src_row = g_new  (gdouble, row_size * src_components);
+
+  p_top = top_row;
+  p_dst = dst_row;
+
+  for (y = 0; y < height; y++)
+    {
+      GeglRectangle row_rect = {-1, y, width + 1, 1};
+
+      gegl_buffer_get (input, &row_rect, 1.0, src_format, src_row,
+                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+      compute_row_integral (src_row + src_components,
+                            p_top + dst_components,
+                            p_dst + dst_components,
+                            width,
+                            src_components,
+                            o->squared);
+
+      gegl_buffer_set (output, &row_rect, 0, dst_format, p_dst,
+                       GEGL_AUTO_ROWSTRIDE);
+
+      p_top = p_dst;
+
+      if (p_dst == top_row)
+        p_dst = dst_row;
+      else
+        p_dst = top_row;
+    }
+
+  g_free (top_row);
+  g_free (dst_row);
+  g_free (src_row);
+
+  return TRUE;
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *region)
+{
+  GeglRectangle result;
+  result.x = 0;
+  result.y = 0;
+  result.width = region->x + region->width;
+  result.height = region->y + region->height;
+
+  return result;
+}
+
+static GeglRectangle
+get_invalidated_by_change (GeglOperation       *operation,
+                           const gchar         *input_pad,
+                           const GeglRectangle *input_region)
+{
+  GeglRectangle  result;
+  GeglRectangle *src = gegl_operation_source_get_bounding_box (operation, "input");
+
+  if (!src)
+    return *input_region;
+
+  result.x = input_region->x;
+  result.y = input_region->y;
+  result.width  = src->width - input_region->x;
+  result.height = src->height - input_region->y;
+
+  return result;
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+
+  if (gegl_rectangle_is_infinite_plane (&result))
+    return *roi;
+
+  return result;
+}
+
+static void
+gegl_op_class_init (GeglOpClass *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->get_cached_region         = get_cached_region;
+  operation_class->get_invalidated_by_change = get_invalidated_by_change;
+  operation_class->get_required_for_output   = get_required_for_output;
+  operation_class->prepare                   = prepare;
+  operation_class->threaded                  = FALSE;
+  operation_class->opencl_support            = FALSE;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name",        "gegl:integral-image",
+    "title",       _("Integral Image"),
+    "categories",  "hidden",
+    "description", _("Compute integral and squared integral image"),
+    NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4044518..06477d2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -239,6 +239,7 @@ operations/workshop/generated/subtractive.c
 operations/workshop/gradient-map.c
 operations/workshop/hstack.c
 operations/workshop/image-gradient.c
+operations/workshop/integral-image.c
 operations/workshop/kuwahara.c
 operations/workshop/mandelbrot.c
 operations/workshop/median-blur.c


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