[gegl] Introduce a new WIP two-step seamless-cloning procedure



commit eb017ab689797ed4154c0849807b3175795583a4
Author: Barak Itkin <lightningismyname gmail com>
Date:   Sun Aug 14 20:25:55 2011 +0300

    Introduce a new WIP two-step seamless-cloning procedure

 operations/common/seamless-clone/Makefile.am       |   17 +-
 operations/common/seamless-clone/find-outline.c    |    4 +-
 operations/common/seamless-clone/find-outline.h    |    2 +-
 .../common/seamless-clone/seamless-clone-prepare.c |  100 ++++++++
 .../common/seamless-clone/seamless-clone-render.c  |  241 ++++++++++++++++++++
 operations/common/seamless-clone/seamless-clone.h  |   24 ++-
 6 files changed, 371 insertions(+), 17 deletions(-)
---
diff --git a/operations/common/seamless-clone/Makefile.am b/operations/common/seamless-clone/Makefile.am
index 30d5b39..9f36646 100644
--- a/operations/common/seamless-clone/Makefile.am
+++ b/operations/common/seamless-clone/Makefile.am
@@ -2,21 +2,20 @@ SUBDIRS = poly2tri-c
 
 include $(top_srcdir)/operations/Makefile-common.am
 
-LIBS            = $(op_libs)
+AM_LDFLAGS += $(op_libs) poly2tri-c/libpoly2tri-c.la
 
-seamless_clone_la_SOURCES = \
-       make-mesh.c                     \
+sc_common_files =              \
+       make-mesh.c                     \
        make-mesh.h                     \
        find-outline.c          \
        find-outline.h          \
-       seamless-clone.c        \
        seamless-clone.h
 
-seamless_clone_la_LIBADD = $(op_libs) poly2tri-c/libpoly2tri-c.la
-seamless_clone_la_CFLAGS = $(AM_CFLAGS) $(BABL_CFLAGS) $(GLIB_CFLAGS)
+seamless_clone_la_SOURCES = seamless-clone.c $(sc_common_files)
+seamless_clone_render_la_SOURCES = seamless-clone-render.c $(sc_common_files)
+seamless_clone_prepare_la_SOURCES = seamless-clone-prepare.c $(sc_common_files)
 
 opdir = $(libdir)/gegl- GEGL_API_VERSION@
-op_LTLIBRARIES = seamless-clone.la
 
-AM_CPPFLAGS += \
-       -I$(top_srcdir)/operations/common
+op_LTLIBRARIES = seamless-clone.la seamless-clone-render.la seamless-clone-prepare.la
+Introduce a new WIP two-step seamless-cloning procedure
diff --git a/operations/common/seamless-clone/find-outline.c b/operations/common/seamless-clone/find-outline.c
index eef86ab..ddf3d49 100644
--- a/operations/common/seamless-clone/find-outline.c
+++ b/operations/common/seamless-clone/find-outline.c
@@ -167,8 +167,8 @@ outline_walk_cw (GeglRectangle      *rect,
 #define pteq(pt1,pt2) (((pt1)->x == (pt2)->x) && ((pt1)->y == (pt2)->y))
 
 GPtrArray*
-sc_outline_find_ccw (GeglRectangle *rect,
-                     GeglBuffer    *pixels)
+sc_outline_find_ccw (const GeglRectangle *rect,
+                     const GeglBuffer    *pixels)
 {
   Babl      *format = babl_format("RGBA float");
   GPtrArray *points = g_ptr_array_new ();
diff --git a/operations/common/seamless-clone/find-outline.h b/operations/common/seamless-clone/find-outline.h
index a708c54..5eb44f5 100644
--- a/operations/common/seamless-clone/find-outline.h
+++ b/operations/common/seamless-clone/find-outline.h
@@ -33,7 +33,7 @@ typedef struct  {
  */
 typedef GPtrArray ScOutline;
 
-ScOutline* sc_outline_find_ccw (GeglRectangle *rect, GeglBuffer *pixels);
+ScOutline* sc_outline_find_ccw (const GeglRectangle *rect, const GeglBuffer *pixels);
 
 void       sc_outline_free  (ScOutline *self);
 
diff --git a/operations/common/seamless-clone/seamless-clone-prepare.c 
b/operations/common/seamless-clone/seamless-clone-prepare.c
new file mode 100644
index 0000000..9aa399c
--- /dev/null
+++ b/operations/common/seamless-clone/seamless-clone-prepare.c
@@ -0,0 +1,100 @@
+/* This file is an image processing operation for GEGL
+ *
+ * seamless-clone-prepare.c
+ * Copyright (C) 2011 Barak Itkin <lightningismyname gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is part 1 of 2 in the process of real-time seamless cloning.
+ * This operation takes a paste to be seamlessly cloned, and a property
+ * which is a pointer to a pointer. Through that pointer, the operation
+ * should return a data structure that is to be passed to the next
+ * operations.
+ */
+
+#ifdef GEGL_CHANT_PROPERTIES
+gegl_chant_pointer (result, _("result"),
+  _("A pointer to a pointer (gpointer*) to store the result in"))
+#else
+
+#define GEGL_CHANT_TYPE_SINK
+#define GEGL_CHANT_C_FILE       "seamless-clone-prepare.c"
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include "gegl-chant.h"
+
+#include "poly2tri-c/poly2tri.h"
+#include "poly2tri-c/refine/triangulation.h"
+#include "poly2tri-c/render/mesh-render.h"
+#include "seamless-clone.h"
+
+static void
+prepare (GeglOperation *operation)
+{
+  Babl *format = babl_format ("R'G'B'A float");
+
+  gegl_operation_set_format (operation, "input",  format);
+}
+
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         const GeglRectangle *roi)
+{
+  ScPreprocessResult *result = sc_preprocess_new ();
+  
+  /* First, find the paste outline */
+  result->outline = sc_outline_find_ccw (roi, input);
+
+  /* Then, Generate the mesh */
+  result->mesh = sc_make_fine_mesh (result->outline, &result->mesh_bounds);
+
+  /* Finally, Generate the mesh sample list for each point */
+  result->sampling = sc_mesh_sampling_compute (result->outline, result->mesh);
+
+  /* If caching of UV is desired, it shold be done here, and possibly
+   * by using a regular operation rather than a sink one, so that we can
+   * output UV coords */
+
+  GEGL_CHANT_PROPERTIES (operation) -> result = result;
+
+  /*
+  sc_mesh_sampling_free (mesh_sampling);
+  p2tr_triangulation_free (mesh);
+  sc_outline_free (outline);
+  */
+  
+  return  TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass         *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationSinkClass     *sink_class      = GEGL_OPERATION_SINK_CLASS (klass);
+
+  operation_class->prepare     = prepare;
+  operation_class->name        = "gegl:seamless-clone-prepare";
+  operation_class->categories  = "programming";
+  operation_class->description = _("Seamless cloning preprocessing operation");
+
+  sink_class->process          = process;
+  sink_class->needs_full       = TRUE;
+}
+
+#endif
diff --git a/operations/common/seamless-clone/seamless-clone-render.c 
b/operations/common/seamless-clone/seamless-clone-render.c
new file mode 100644
index 0000000..6c06ab9
--- /dev/null
+++ b/operations/common/seamless-clone/seamless-clone-render.c
@@ -0,0 +1,241 @@
+/* This file is an image processing operation for GEGL
+ *
+ * seamless-clone-render.c
+ * Copyright (C) 2011 Barak Itkin <lightningismyname gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_int (xoff, "xoff", G_MININT, G_MAXINT, 0,
+  _("The x offset to apply to the paste"))
+
+gegl_chant_int (yoff, "yoff", G_MININT, G_MAXINT, 0,
+  _("The y offset to apply to the paste"))
+
+gegl_chant_pointer (prepare, _("prepare"),
+  _("The pointer returned from the seamless-clone-prepare operation, applied on the aux buf"))
+
+#else
+
+#define GEGL_CHANT_TYPE_COMPOSER
+#define GEGL_CHANT_C_FILE       "seamless-clone-render.c"
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include "gegl-chant.h"
+
+#include "poly2tri-c/poly2tri.h"
+#include "poly2tri-c/refine/triangulation.h"
+#include "poly2tri-c/render/mesh-render.h"
+#include "seamless-clone.h"
+
+static GeglRectangle
+get_required_for_output (GeglOperation       *operation,
+                         const gchar         *input_pad,
+                         const GeglRectangle *region)
+{
+  GeglRectangle *temp = NULL;
+  GeglRectangle  result;
+
+  if (g_strcmp0 (input_pad, "input") || g_strcmp0 (input_pad, "aux"))
+    temp = gegl_operation_source_get_bounding_box (operation, input_pad);
+  else
+    g_warning ("seamless-clone::Unknown input pad \"%s\"\n", input_pad);
+
+  if (temp != NULL)
+    result = *temp;
+  else
+    {
+      result.width = result.height = 0;
+    }
+  
+  return result;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  Babl *format = babl_format ("R'G'B'A float");
+
+  gegl_operation_set_format (operation, "input",  format);
+  gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "output", format);
+}
+
+
+typedef struct {
+  GeglBuffer     *aux_buf;
+  GeglBuffer     *input_buf;
+  ScMeshSampling *sampling;
+  GHashTable     *pt2col;
+
+  /* Offset to be applied to the paste */
+  gint xoff, yoff;
+} ScColorComputeInfo;
+
+static void
+sc_point_to_color_func (P2tRPoint *point,
+                        gfloat    *dest,
+                        gpointer   cci_p)
+{
+  ScColorComputeInfo *cci = (ScColorComputeInfo*) cci_p;
+  ScSampleList       *sl = g_hash_table_lookup (cci->sampling, point);
+  gfloat aux_c[4], input_c[4], dest_c[3] = {0, 0, 0};
+  gint i;
+  gdouble weightT = 0;
+  guint N = sl->points->len;
+  gfloat *col_cpy;
+
+  Babl *format = babl_format ("R'G'B'A float");
+
+  if ((col_cpy = g_hash_table_lookup (cci->pt2col, point)) != NULL)
+    {
+      dest[0] = col_cpy[0];
+      dest[1] = col_cpy[1];
+      dest[2] = col_cpy[2];
+      dest[3] = col_cpy[3];
+      return;
+    }
+  else
+    {
+      col_cpy = g_new (gfloat, 4);
+      g_hash_table_insert (cci->pt2col, point, col_cpy);
+    }
+
+  for (i = 0; i < N; i++)
+    {
+      ScPoint *pt = g_ptr_array_index (sl->points, i);
+      gdouble weight = g_array_index (sl->weights, gdouble, i);
+
+      gegl_buffer_sample (cci->aux_buf, pt->x, pt->y, NULL, aux_c, format, GEGL_INTERPOLATION_NEAREST);
+      /* Sample the BG with the offset */
+      gegl_buffer_sample (cci->input_buf, pt->x + cci->xoff, pt->y + cci->yoff, NULL, input_c, format, 
GEGL_INTERPOLATION_NEAREST);
+      
+      dest_c[0] += weight * (input_c[0] - aux_c[0]);
+      dest_c[1] += weight * (input_c[1] - aux_c[1]);
+      dest_c[2] += weight * (input_c[2] - aux_c[2]);
+      weightT += weight;
+       }
+
+  col_cpy[0] = dest[0] = dest_c[0] / weightT;
+  col_cpy[1] = dest[1] = dest_c[1] / weightT;
+  col_cpy[2] = dest[2] = dest_c[2] / weightT;
+  col_cpy[3] = dest[3] = 1;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *aux,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  ScPreprocessResult *spr = o->prepare;
+  
+  gfloat    *out_raw, *pixel;
+  gdouble    x, y;
+
+  GeglRectangle aux_rect = *gegl_operation_source_get_bounding_box (operation, "aux");
+  GeglRectangle to_render;
+
+  ScColorComputeInfo  cci;
+  P2tRImageConfig     imcfg;
+
+  Babl               *format = babl_format("R'G'B'A float");
+
+  if (spr == NULL)
+    {
+      g_warning ("No preprocessing result given. Stop.");
+      return FALSE;
+    }
+
+  /* The location of the aux will actually be computed with an offset */
+  aux_rect.x += o->xoff;
+  aux_rect.y += o->yoff;
+  
+  /* We only need to render the intersection of the mesh bounds and the
+   * desired output */
+  gegl_rectangle_intersect (&to_render, result, &aux_rect);
+
+  /* Alocate the output buffer */
+  out_raw = g_new (gfloat, 4 * to_render.width * to_render.height);
+
+  /* Render the mesh into it */
+  cci.aux_buf = aux;
+  cci.input_buf = input;
+  cci.sampling = spr->sampling;
+  cci.pt2col = (gpointer) g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+
+  /* In order to sample colors correctly, the sampling function will
+   * need to know the offset */
+  cci.xoff = o->xoff;
+  cci.yoff = o->yoff;
+
+  /* Render as if there is no offset, since the mesh has no offset */
+  imcfg.min_x = to_render.x - o->xoff;
+  imcfg.min_y = to_render.y - o->yoff;
+  imcfg.step_x = imcfg.step_y = 1;
+  imcfg.x_samples = to_render.width;
+  imcfg.y_samples = to_render.height;
+  imcfg.cpp = 4;
+
+  p2tr_mesh_render_scanline (spr->mesh, out_raw, &imcfg, sc_point_to_color_func, &cci);
+
+  pixel = out_raw;
+
+  /* Note that when composing the aux, we still ignore the offset */
+  pixel = out_raw;
+  for (y = 0; y < imcfg.y_samples; y++)
+    for (x = 0; x < imcfg.x_samples; x++)
+      {
+        gfloat aux_c[4];
+        gdouble Px = imcfg.min_x + x * imcfg.step_x;
+        gdouble Py = imcfg.min_y + y * imcfg.step_y;
+        gegl_buffer_sample (aux, Px, Py, NULL, aux_c, format, GEGL_INTERPOLATION_NEAREST);
+        *pixel++ += aux_c[0];
+        *pixel++ += aux_c[1];
+        *pixel++ += aux_c[2];
+        pixel++;// += 0;//aux_c[3];
+      }
+  
+  /* Now, finally commit the result. Note that we commit in the
+   * offsetted to_result area! */
+  gegl_buffer_set (output, &to_render, babl_format("R'G'B'A float"), out_raw, GEGL_AUTO_ROWSTRIDE);
+
+  g_free (out_raw);
+  g_hash_table_destroy (cci.pt2col);
+  
+  return TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass         *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationComposerClass *composer_class  = GEGL_OPERATION_COMPOSER_CLASS (klass);
+
+  operation_class->prepare     = prepare;
+  operation_class->name        = "gegl:seamless-clone-render";
+  operation_class->categories  = "programming";
+  operation_class->description = "Seamless cloning rendering operation";
+  operation_class->get_required_for_output = get_required_for_output;
+
+  composer_class->process      = process;
+}
+
+
+#endif
diff --git a/operations/common/seamless-clone/seamless-clone.h 
b/operations/common/seamless-clone/seamless-clone.h
index 88d41f0..96254a8 100644
--- a/operations/common/seamless-clone/seamless-clone.h
+++ b/operations/common/seamless-clone/seamless-clone.h
@@ -20,15 +20,29 @@
 #ifndef __SEAMLESS_CLONE_H__
 #define __SEAMLESS_CLONE_H__
 
-#define TO_CAIRO(col) ((col)/2+0.5)
-//#define FROM_CAIRO(col) (((col)-0.5)*2)
-//#define TO_CAIRO(col) (col)
-#define FROM_CAIRO(col) ((col - 128)*2)
-
 #include "poly2tri-c/poly2tri.h"
 #include "poly2tri-c/refine/triangulation.h"
 
 #include "find-outline.h"
 #include "make-mesh.h"
 
+typedef struct {
+  ScOutline         *outline;
+  P2tRTriangulation *mesh;
+  GeglRectangle      mesh_bounds;
+  ScMeshSampling    *sampling;
+} ScPreprocessResult;
+
+#define sc_preprocess_new() (g_new0 (ScPreprocessResult, 1))
+
+//inline void
+//sc_preprocess_result_free (ScPreprocessResult *self)
+//{
+//  sc_mesh_sampling_free (self->sampling);
+//  p2tr_triangulation_free (self->mesh);
+//  sc_outline_free (self->outline);
+//
+//  g_free (self);
+//}
+
 #endif


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