[gegl] alpha-inpaint: adjust cohesion part of metric



commit 6ec0fa68aa8cef4c29942d2e9d3f447cb2be62e1
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Jul 11 02:43:40 2019 +0200

    alpha-inpaint: adjust cohesion part of metric
    
    instead of wanting the smallest possible distance to the average neighborhood
    we now consider the situation optimal when we are on average 1px away from
    the sources of the neighbors, hoping to encourage texture synthesis.

 gegl/gegl-config.c                  |   4 +-
 gegl/gegl-serialize.c               |  62 +++++++++----
 operations/common/saturation.c      |   3 +-
 operations/workshop/alpha-inpaint.c | 172 ++++++++++++++++++++++++++----------
 4 files changed, 174 insertions(+), 67 deletions(-)
---
diff --git a/gegl/gegl-config.c b/gegl/gegl-config.c
index 1b6fc25e8..984e2fc4a 100644
--- a/gegl/gegl-config.c
+++ b/gegl/gegl-config.c
@@ -316,8 +316,8 @@ gegl_config_class_init (GeglConfigClass *klass)
                               + zfs_arc_size;
     }
 #else
-    mem_total = sysconf (_SC_PHYS_PAGES) * sysconf (_SC_PAGESIZE);
-    mem_available = sysconf (_SC_AVPHYS_PAGES) * sysconf (_SC_PAGESIZE);
+    mem_total = (uint64_t) sysconf (_SC_PHYS_PAGES) * sysconf (_SC_PAGESIZE);
+    mem_available = (uint64_t) sysconf (_SC_AVPHYS_PAGES) * sysconf (_SC_PAGESIZE);
 #endif
 
     default_tile_cache_size = mem_total;
diff --git a/gegl/gegl-serialize.c b/gegl/gegl-serialize.c
index dcfcaa168..cf6d1c09b 100644
--- a/gegl/gegl-serialize.c
+++ b/gegl/gegl-serialize.c
@@ -190,8 +190,31 @@ gegl_node_set_time (GeglNode   *node,
 }
 
 
+static char *
+gegl_migrate_saturation_0_0_to_1_0 (const char  *input)
+{
+  //params_add_entry (params, "colorspace=CIE-lab");
+  //return TRUE;
+  return g_strdup (input);
+}
+
+
+
+
+gboolean
+gegl_migrate_api (GeglNode    *node,
+                  const char  *operation,
+                  char       **params)
+{
+  // if there is no opi entry, nothing to migrate
+  // if we find opi key.. look for valid migration
+
+  return TRUE;
+}
+
+
 void
-gegl_create_chain_argv (char      **ops,
+gegl_create_chain_argv (char      **argv,
                         GeglNode   *start,
                         GeglNode   *proxy,
                         double      time,
@@ -201,7 +224,7 @@ gegl_create_chain_argv (char      **ops,
 {
   GeglNode   *iter[10] = {start, NULL};
   GeglNode   *new = NULL;
-  gchar     **arg = ops;
+  gchar     **arg = argv;
   int level = 0;
   char       *level_op[10];
   char       *level_pad[10];
@@ -212,6 +235,8 @@ gegl_create_chain_argv (char      **ops,
   GeglPath   *path = NULL;
   GString    *string = NULL;
   GeglNode **ret_sinkp = NULL;
+  char      *op_args[64]={NULL, };
+  int        n_op_args = 0;
 
   if (error && *error)
   {
@@ -227,7 +252,6 @@ gegl_create_chain_argv (char      **ops,
   ht = g_hash_table_new (g_str_hash, g_str_equal);
 
 
-
   while (*arg)
     {
       if (in_keyframes)
@@ -388,6 +412,7 @@ gegl_create_chain_argv (char      **ops,
                   {
                     /* should check for incompatibility rather than difference
                      */
+                    fprintf (stderr, "{%s}", value);
                     if (!g_str_equal (value,
                                       gegl_operation_get_op_version (level_op[
                                                                        level])))
@@ -851,12 +876,11 @@ gegl_create_chain (const char *str, GeglNode *op_start, GeglNode *op_end,
     }
 }
 
-/* TODO: serialize keyframed properties */
 static gchar *
-gegl_serialize2 (GeglNode         *start, 
-                 GeglNode         *end, 
+gegl_serialize2 (GeglNode         *start,
+                 GeglNode         *end,
                  const char       *basepath,
-                 GHashTable       *ht, 
+                 GHashTable       *ht,
                  GeglSerializeFlag flags)
 {
   char *ret = NULL;
@@ -937,6 +961,7 @@ gegl_serialize2 (GeglNode         *start,
             gint i;
             guint n_properties;
             GParamSpec **properties;
+            gboolean printed = FALSE;
 
             properties = gegl_operation_list_properties (gegl_node_get_operation (
                                                            iter),
@@ -950,7 +975,6 @@ gegl_serialize2 (GeglNode         *start,
                   properties[i]);
                 char tmpbuf[1024];
                 GeglPath *anim_path = NULL;
-                gboolean printed = FALSE;
                 char *rel_orig = NULL;
                 GQuark anim_quark, rel_quark;
                 sprintf (tmpbuf, "%s-anim", property_name);
@@ -1180,21 +1204,21 @@ gegl_serialize2 (GeglNode         *start,
                       "%s: serialization of %s properties not implemented",
                       property_name, g_type_name (property_type));
                   }
+              }
 
-                if (printed && (flags & GEGL_SERIALIZE_INDENT))
+              if (printed && (flags & GEGL_SERIALIZE_INDENT))
                   g_string_append_printf (s2, "\n");
 
-                {
-                  GeglNode *aux = gegl_node_get_producer (iter, "aux", NULL);
-                  if (aux)
-                    {
-                      char *str = gegl_serialize2 (NULL, aux, basepath, ht,
-                                                   flags);
-                      g_string_append_printf (s2, " aux=[ %s ]%s", str,
+              {
+                GeglNode *aux = gegl_node_get_producer (iter, "aux", NULL);
+                if (aux)
+                  {
+                    char *str = gegl_serialize2 (NULL, aux, basepath, ht,
+                                                 flags);
+                    g_string_append_printf (s2, " aux=[ %s ]%s", str,
                             (flags& GEGL_SERIALIZE_INDENT)?"\n":" ");
-                      g_free (str);
-                    }
-                }
+                    g_free (str);
+                  }
               }
           }
 
diff --git a/operations/common/saturation.c b/operations/common/saturation.c
index 9283d89dd..42630a40d 100644
--- a/operations/common/saturation.c
+++ b/operations/common/saturation.c
@@ -36,7 +36,7 @@ property_double (scale, _("Scale"), 1.0)
 property_enum (colorspace, _("Interpolation Color Space"),
     description(_("Set at Native if uncertain, the CIE based spaces might introduce hue shifts."))
     GeglSaturationType, gegl_saturation_type,
-    GEGL_SATURATION_TYPE_CIE_LAB)
+    GEGL_SATURATION_TYPE_NATIVE)
 
 #else
 
@@ -380,6 +380,7 @@ gegl_op_class_init (GeglOpClass *klass)
 
   gegl_operation_class_set_keys (operation_class,
     "name"       , "gegl:saturation",
+    "opi",         "1:0",
     "title",       _("Saturation"),
     "reference-hash", "584bfe714947a573f10399965c8b45b0",
     "categories" , "color",
diff --git a/operations/workshop/alpha-inpaint.c b/operations/workshop/alpha-inpaint.c
index 24dc954e3..8feb15703 100644
--- a/operations/workshop/alpha-inpaint.c
+++ b/operations/workshop/alpha-inpaint.c
@@ -29,7 +29,7 @@ property_int (seek_distance, "seek radius", 10)
   description ("Maximum distance in neighborhood we look for better candidates per improvement.")
   value_range (1, 512)
 
-property_double (seek_reduction, "seek reduction", 0.75)
+property_double (seek_reduction, "seek reduction", 0.6)
   description ("factor seek distance is shortened, until we're about 2px short per iteration, 1.0 means no 
reduction")
   value_range (0.0, 1.0)
 
@@ -45,27 +45,31 @@ property_int (max_iter, "max rounds", 800)
   description ("Mostly a saftey valve, so that we terminate")
   value_range (1, 40000)
 
-property_int (iterations, "iterations per round per probe", 16)
+property_int (iterations, "iterations per round per probe", 23)
   description ("number of improvement iterations, after initial search - that each probe gets.")
   value_range (1, 1000)
 
+property_double (histogram,    "histogram", 0.5)
+  description ("only consider pixels whose neighborhood color distribution is smaller than specified, set to 
1.0 for much faster processing, but needing lower seek distance to yield ok results.")
+  value_range (0.0, 1.0)
+
 
 property_double (ring_gap1,    "ring gap1", 1.1)
   description ("radius, in pixels of nearest to pixel circle of neighborhood metric")
   value_range (0.0, 16.0)
   ui_steps    (0.25, 0.25)
 
-property_double (ring_gap2,    "ring gap2", 1.75)
+property_double (ring_gap2,    "ring gap2", 1.9)
   description ("radius, in pixels of second nearest to pixel circle")
   value_range (0.0, 16.0)
   ui_steps    (0.25, 0.25)
 
-property_double (ring_gap3,    "ring gap3", 2.9)
+property_double (ring_gap3,    "ring gap3", 3.2)
   description ("radius, in pixels of third pixel circle")
   value_range (0.0, 16.0)
   ui_steps    (0.25, 0.25)
 
-property_double (ring_gap4, "ring gap4", 4.0)
+property_double (ring_gap4, "ring gap4", 4.1)
   description ("radius, in pixels of fourth pixel circle (not always in use)")
   value_range (0.0, 16.0)
   ui_steps    (0.25, 0.25)
@@ -73,11 +77,11 @@ property_double (ring_gap4, "ring gap4", 4.0)
 property_int (scale_needles, "scale needles", 5)
   value_range (1, 7)
 
-property_int (rounds, "rounds", 8)
+property_int (rounds, "rounds", 16)
   description ("number of improvement iterations, after initial search - that each probe gets.")
   value_range (0, 1000)
 
-property_double (chance_try, "try probability", 0.07)
+property_double (chance_try, "try probability", 0.015)
   description ("The chance that a candidate pixel probe will start being filled in")
   value_range (0.0, 1.0)
   ui_steps    (0.01, 0.1)
@@ -91,12 +95,12 @@ property_double (chance_neighbor, "chance neighbor", 1.0)
   value_range (0.0, 1.0)
   ui_steps    (0.01, 0.1)
 
-property_double (metric_dist_powk, "dist powk", 2.8)
+property_double (metric_dist_powk, "dist powk", 1.8)
   description ("influences the (lack of) importance of further away pixels")
   value_range (0.0, 10.0)
   ui_steps    (0.1, 1.0)
 
-property_double (metric_empty_hay_score, "empty hay score", 0.38)
+property_double (metric_empty_hay_score, "empty hay score", 0.275)
   description ("score given to pixels that are empty, in the search neighborhood of pixel, this being at 
default or higher value sometimes discourages some of the good very nearby matches")
   value_range (0.001, 100.0)
   ui_steps    (0.05, 0.1)
@@ -106,7 +110,7 @@ property_double (metric_empty_needle_score, "empty needle score", 0.18)
   value_range (0.001, 100.0)
   ui_steps    (0.05, 0.1)
 
-property_double (metric_cohesion, "metric cohesion", 0.5)
+property_double (metric_cohesion, "metric cohesion", 0.13)
   description ("influences the importance of probe spatial proximity")
   value_range (0.0, 100.0)
   ui_steps    (0.2, 0.2)
@@ -120,7 +124,7 @@ property_double (ring_twist, "ring twist", 0.0)
 property_boolean (direction_invariant, "direction invariant", TRUE)
   description ("wheter we normalize feature vector to start with highest energy ray")
 
-property_int (source_neighbors, "source neighbors", 4)
+property_int (source_neighbors, "source neighbors", 8)
   description ("pick neighbor of neighbors as starting point if good, 4connected 8conntected or 12/16 with 
longer teleport")
   value_range (0, 16)
 
@@ -141,7 +145,7 @@ property_int (source_neighbors, "source neighbors", 4)
  */
 
 #define RINGS                   3   // increments works up to 7-8 with no adver
-#define RAYS                    12  // good values for testing 6 8 10 12 16
+#define RAYS                   12   // good values for testing 6 8 10 12 16
 #define NEIGHBORHOOD            (RINGS*RAYS+1)
 
 /* The pattern of the sampling neighborhood is RAYS of samples radiating out
@@ -215,8 +219,10 @@ typedef struct
 
 typedef struct _Probe Probe;
 
+#define HIST_DIM 4
 
 typedef float   needles_t[N_SCALE_NEEDLES][4 * NEIGHBORHOOD ];// should be on stack
+typedef float   needles_hist_t[N_SCALE_NEEDLES][HIST_DIM * HIST_DIM * HIST_DIM];// should be on stack
 
 
 struct _Probe {
@@ -503,6 +509,62 @@ static inline float f_rgb_diff (float *a, float *b)
   return POW2(a[0]-b[0]) + POW2(a[1]-b[1]) + POW2(a[2]-b[2]);
 }
 
+
+
+static inline void make_hist (PixelDuster *duster, gfloat *signature, float *hist)
+{
+  float *rgba;
+  int count = 0;
+
+  rgba = signature + 4;
+
+  for (int i = 1; i < NEIGHBORHOOD; i++)
+  {
+    if (rgba[3] > 0.5)
+    {
+      int cell_a = rgba[0] * HIST_DIM + 0.5;
+      int cell_b = rgba[1] * HIST_DIM + 0.5;
+      int cell_c = rgba[2] * HIST_DIM + 0.5;
+      if (cell_a < 0) cell_a = 0;
+      if (cell_b < 0) cell_b = 0;
+      if (cell_c < 0) cell_c = 0;
+      if (cell_a >= HIST_DIM) cell_a = HIST_DIM-1;
+      if (cell_b >= HIST_DIM) cell_b = HIST_DIM-1;
+      if (cell_c >= HIST_DIM) cell_c = HIST_DIM-1;
+
+      hist[cell_a * HIST_DIM * HIST_DIM + cell_b * HIST_DIM + cell_c] += 1.0;
+      count++;
+    }
+
+    rgba += 4;
+  }
+  if (count)
+    for (int i = 0; i < HIST_DIM * HIST_DIM * HIST_DIM; i++)
+    {
+      hist[i] /= count;
+    }
+}
+
+static float inline
+histogram_compare (PixelDuster *duster,
+                   gfloat      *needle,
+                   gfloat      *needle_hist,
+                   gfloat      *hay)
+{
+  float diff = 0.0;
+  //float needle_hist[HIST_DIM * HIST_DIM * HIST_DIM]={0,};
+  float hay_hist[HIST_DIM * HIST_DIM * HIST_DIM]={0,};
+
+  //make_hist (duster, needle, needle_hist);
+  make_hist (duster, hay, hay_hist);
+
+  for (int i = 0; i < HIST_DIM * HIST_DIM * HIST_DIM; i++)
+    diff += POW2(needle_hist[i] - hay_hist[i]);
+
+  return sqrtf(diff);
+}
+
+
 static float inline
 score_site (PixelDuster *duster,
             Probe       *probe,
@@ -510,6 +572,7 @@ score_site (PixelDuster *duster,
             int          x,
             int          y,
             gfloat      *needle,
+            gfloat      *needle_hist,
             gfloat      *hay,
             float        bail)
 {
@@ -523,22 +586,30 @@ score_site (PixelDuster *duster,
     return INITIAL_SCORE;
   }
 
+ // return histogram_compare (duster, needle, hay);
+  if (o->histogram < 1.0)
+  {
+    score = histogram_compare (duster, needle, needle_hist, hay);
+    if (score > o->histogram)
+      return INITIAL_SCORE;
+  }
+
   {
-    float sum_x = probe->source_x;
-    float sum_y = probe->source_y;
-    int count = 1;
-    for (int i = 0; i < 4; i++)
+    float sum = 0;//probe->source_x;
+    int count = 0;
+    for (int i = 0; i < 8; i++)
     if (neighbors[i])
     {
-      sum_x += neighbors[i]->source_x;
-      sum_y += neighbors[i]->source_y;
+      int dx = abs(probe->source_x - neighbors[i]->source_x);
+      int dy = abs(probe->source_y - neighbors[i]->source_y);
+      int val = abs (MAX(dx,dy)-1);
+
+      sum += val;
       count++;
     }
-    sum_x /= count;
-    sum_y /= count;
+    sum /= count;
 
-    score += (POW2(sum_x - probe->source_x) +
-             POW2(sum_y - probe->source_y)) * o->metric_cohesion / 1000.0f;
+    score += sum * o->metric_cohesion;
   }
 
   for (i = 1; i < NEIGHBORHOOD && score < bail; i++)
@@ -623,6 +694,7 @@ probe_score (PixelDuster *duster,
              Probe       *probe,
              Probe      **neighbors,
              needles_t    needles,
+             needles_hist_t needles_hist,
              int          x,
              int          y,
              gfloat      *hay,
@@ -655,23 +727,20 @@ static inline void
 probe_prep (PixelDuster *duster,
             Probe       *probe,
             Probe      **neighbors,
-            needles_t    needles)
+            needles_t    needles,
+            needles_hist_t needles_hist)
 {
+  float scales[]={1.0, 1.2, 0.83333, 1.4, 0.7, 1.5, 0.66667};
+
   gint  dst_x  = probe->target_x;
   gint  dst_y  = probe->target_y;
-  extract_site (duster, duster->output, dst_x, dst_y, 1.0, &needles[0][0]);
-  if (duster->o->scale_needles > 1)
-    extract_site (duster, duster->output, dst_x, dst_y, 1.2, &needles[1][0]);
-  if (duster->o->scale_needles > 2)
-    extract_site (duster, duster->output, dst_x, dst_y, 0.8333, &needles[2][0]);
-  if (duster->o->scale_needles > 3)
-    extract_site (duster, duster->output, dst_x, dst_y, 1.4, &needles[3][0]);
-  if (duster->o->scale_needles > 4)
-    extract_site (duster, duster->output, dst_x, dst_y, 0.7, &needles[4][0]);
-  if (duster->o->scale_needles > 5)
-    extract_site (duster, duster->output, dst_x, dst_y, 1.5, &needles[5][0]);
-  if (duster->o->scale_needles > 6)
-    extract_site (duster, duster->output, dst_x, dst_y, 0.66667,&needles[6][0]);
+
+  for (int i = 0; i < sizeof(scales)/sizeof(scales[0]) &&
+                      i < duster->o->scale_needles; i++)
+  {
+    extract_site (duster, duster->output, dst_x, dst_y, scales[i], &needles[i][0]);
+    make_hist (duster, &needles[i][0], &needles_hist[i][0]);
+  }
 
   /* find neighbors */
   {
@@ -697,7 +766,7 @@ probe_prep (PixelDuster *duster,
         float test_x = oprobe->source_x + coords[c][0];
         float test_y = oprobe->source_y + coords[c][1];
         float *hay = ensure_hay (duster, test_x, test_y);
-        float score = probe_score (duster, probe, neighbors, needles, test_x, test_y, hay, probe->score);
+        float score = probe_score (duster, probe, neighbors, needles, needles_hist, test_x, test_y, hay, 
probe->score);
         if (score <= probe->score)
         {
           probe->source_x = test_x;
@@ -715,6 +784,7 @@ probe_score (PixelDuster *duster,
              Probe       *probe,
              Probe      **neighbors,
              needles_t    needles,
+             needles_hist_t needles_hist,
              int          x,
              int          y,
              gfloat      *hay,
@@ -730,7 +800,7 @@ probe_score (PixelDuster *duster,
 
   for (int n = 0; n < duster->o->scale_needles; n++)
   {
-    float score = score_site (duster, probe, neighbors, x, y, &needles[n][0], hay, bail);
+    float score = score_site (duster, probe, neighbors, x, y, &needles[n][0], &needles_hist[n][0], hay, 
bail);
     if (score < best_score)
       best_score = score;
   }
@@ -745,6 +815,7 @@ static void probe_improve (PixelDuster *duster,
   Probe *neighbors[16]={NULL,};
   GeglProperties *o = duster->o;
   needles_t needles;
+  needles_hist_t needles_hist = {{0.0,},};
   float old_score = probe->score;
 
   if (probe->age >= o->rounds)
@@ -753,26 +824,36 @@ static void probe_improve (PixelDuster *duster,
       return;
     }
 
-  probe_prep (duster, probe, neighbors, needles);
+  probe_prep (duster, probe, neighbors, needles, needles_hist);
 
   {
-    float mag = o->seek_distance;
+    float mag = 5;//o->seek_distance;
     float startx = probe->source_x;
     float starty = probe->source_y;
+    int dir = 0;
+
     for (int i = 0; i < o->iterations; i++)
     {
       int dx = g_random_int_range (-mag, mag);
       int dy = g_random_int_range (-mag, mag);
-      mag *= o->seek_reduction; // reduce seek radius for each iteration
+      if (dir)
+        mag *= o->seek_reduction; // reduce seek radius for each iteration
+      else
+        mag /= o->seek_reduction; // reduce seek radius for each iteration
       if (mag < 3)
         mag = 2;
+      if (mag > o->seek_distance)
+      {
+        mag = o->seek_distance;
+        dir = 1;
+      }
       if (!(dx == 0 && dy == 0))
       {
         int test_x = startx + dx;
         int test_y = starty + dy;
 
         float *hay = ensure_hay (duster, test_x, test_y);
-        float score = probe_score (duster, probe, neighbors, needles, test_x, test_y, hay, probe->score);
+        float score = probe_score (duster, probe, neighbors, needles, needles_hist, test_x, test_y, hay, 
probe->score);
         if (score <= probe->score)
         {
           probe->source_x = test_x;
@@ -844,7 +925,7 @@ pixel_duster_trim (PixelDuster *duster)
 static int random_compare (gconstpointer a,
                            gconstpointer b)
 {
-  return g_random_int_range (-1, 1);
+  return g_random_int_range (-5, 6);
 }
 
 static GList *list_randomize (GList *input)
@@ -891,13 +972,13 @@ static inline void pixel_duster_fill (PixelDuster *duster)
     }
     else
     {
-      try_replace = ((rand()%100)/100.0) < o->chance_retry;
+      try_replace = ((rand()%1000)/1000.0) < o->chance_retry;
     }
     total ++;
 
     if (probe->score == INITIAL_SCORE || try_replace)
     {
-      if ((rand()%100)/100.0 < o->chance_try)
+      if ((rand()%1000)/1000.0 < o->chance_try)
       {
         if (probe->score != INITIAL_SCORE ||
             (probe_neighbors (duster, duster->output, probe, o->min_neighbors) >= o->min_neighbors))
@@ -1135,6 +1216,7 @@ gegl_op_class_init (GeglOpClass *klass)
   operation_class->get_required_for_output = get_required_for_output;
   operation_class->get_cached_region       = get_cached_region;
   operation_class->opencl_support          = FALSE;
+//  operation_class->threaded                = FALSE; // it kind of works, set to TRUE for more performance 
and possible crashes
   operation_class->threaded                = FALSE; // it kind of works, set to TRUE for more performance 
and possible crashes
 
   gegl_operation_class_set_keys (operation_class,


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