[gegl] workshop: refactor pixel-duster and add content aware enlarger
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] workshop: refactor pixel-duster and add content aware enlarger
- Date: Fri, 16 Feb 2018 11:35:15 +0000 (UTC)
commit 9fb5ff7f15561cae46dfb5279b3a447a00cb8606
Author: Øyvind Kolås <pippin gimp org>
Date: Sat Feb 10 17:01:09 2018 +0100
workshop: refactor pixel-duster and add content aware enlarger
operations/workshop/Makefile.am | 5 +-
operations/workshop/enlarge.c | 295 ++++++++++++++++++++++++++
operations/workshop/inpaint.c | 20 +-
operations/workshop/pixel-duster.h | 403 +++++++++++++++++++-----------------
4 files changed, 525 insertions(+), 198 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 9ec396e..d88437d 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -9,7 +9,7 @@ AM_CPPFLAGS += -I$(srcdir)
LIBS = $(op_libs)
opdir = $(ext_dir)
-op_LTLIBRARIES = \
+op_LTLIBRARIES = \
bayer-matrix.la \
bilateral-filter-fast.la \
demosaic-bimedian.la \
@@ -18,9 +18,10 @@ op_LTLIBRARIES = \
domain-transform.la \
gradient-map.la \
hstack.la \
+ enlarge.la \
inpaint.la \
integral-image.la \
linear-sinusoid.la \
- rawbayer-load.la \
+ rawbayer-load.la \
segment-kmeans.la \
spherize.la
diff --git a/operations/workshop/enlarge.c b/operations/workshop/enlarge.c
new file mode 100644
index 0000000..6a2aecc
--- /dev/null
+++ b/operations/workshop/enlarge.c
@@ -0,0 +1,295 @@
+/* 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 2018 Øyvind Kolås <pippin gimp org>
+ *
+ */
+
+#include <stdio.h>
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+/* most of these should go away - here for ease of algorithm experimentation */
+
+property_int (seek_distance, "seek radius", 8)
+ value_range (4, 512)
+
+property_int (min_neigh, "min neigh", 1)
+ value_range (1, 10)
+
+property_int (min_iter, "min iter", 3)
+ value_range (1, 512)
+
+property_double (chance_try, "try chance", 1.0)
+ value_range (0.0, 1.0)
+
+property_double (chance_retry, "retry chance", 0.33)
+ value_range (0.0, 1.0)
+
+property_double (scale, "scale", 4.0)
+ value_range (0.01, 16.0)
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME enlarge
+#define GEGL_OP_C_SOURCE enlarge.c
+
+#include "gegl-op.h"
+#include <stdio.h>
+#include "pixel-duster.h"
+
+static GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ 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
+prepare (GeglOperation *operation)
+{
+ const Babl *format = babl_format ("RGBA float");
+
+ gegl_operation_set_format (operation, "input", format);
+ gegl_operation_set_format (operation, "output", format);
+}
+
+static void scaled_copy (GeglBuffer *in,
+ GeglBuffer *out,
+ gfloat scale,
+ int mask_blank,
+ int mask_set)
+{
+ GeglRectangle rect;
+ const Babl *format = babl_format ("RGBA float");
+ gint x, y;
+
+ rect = *gegl_buffer_get_extent (out);
+ for (y = 0; y < rect.height; y++)
+ for (x = 0; x < rect.width; x++)
+ {
+ GeglRectangle r = {x, y, 1, 1};
+ gfloat rgba[4] = {0.0, 0.0, 0.0, 0.0};
+ int bit = 1<< ((y%2)*2+(x%2));
+ if (mask_blank & bit)
+ {
+ gegl_buffer_set (out, &r, 0, format, &rgba[0], 0);
+ }
+ else if (mask_set & bit)
+ {
+ gegl_buffer_sample (in, x / scale, y / scale, NULL,
+ &rgba[0], format,
+ GEGL_SAMPLER_NOHALO, 0);
+ gegl_buffer_set (out, &r, 0, format, &rgba[0], 0);
+ }
+ }
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle in_rect = *gegl_buffer_get_extent (input);
+ GeglRectangle out_rect = *gegl_buffer_get_extent (output);
+ PixelDuster *duster;
+
+ scaled_copy (input, output, o->scale, 1, 14);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ scaled_copy (input, output, o->scale, 2, 12);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ scaled_copy (input, output, o->scale, 4, 8);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ scaled_copy (input, output, o->scale, 8, 0);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ scaled_copy (input, output, o->scale, 1, 0);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ scaled_copy (input, output, o->scale, 4, 0);
+ duster = pixel_duster_new (input, output,
+ &in_rect, &out_rect,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ o->scale,
+ o->scale,
+ NULL);
+ pixel_duster_add_probes (duster);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
+
+ return TRUE;
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+ result.x = 0;
+ result.y = 0;
+ result.width *= o->scale;
+ result.height *= o->scale;
+
+ return result;
+}
+
+
+static GeglRectangle
+get_cached_region (GeglOperation *operation,
+ const GeglRectangle *roi)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+
+ if (gegl_rectangle_is_infinite_plane (&result))
+ return *roi;
+ result.x = 0;
+ result.y = 0;
+ result.width *= o->scale;
+ result.height *= o->scale;
+
+ return result;
+}
+
+static gboolean
+operation_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglOperationClass *operation_class;
+
+ const GeglRectangle *in_rect =
+ gegl_operation_source_get_bounding_box (operation, "input");
+
+ operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class);
+
+ if (in_rect && gegl_rectangle_is_infinite_plane (in_rect))
+ {
+ gpointer in = gegl_operation_context_get_object (context, "input");
+ gegl_operation_context_take_object (context, "output",
+ g_object_ref (G_OBJECT (in)));
+ return TRUE;
+ }
+
+ return operation_class->process (operation, context, output_prop, result,
+ gegl_operation_context_get_level (context));
+}
+
+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->prepare = prepare;
+ operation_class->process = operation_process;
+ operation_class->get_bounding_box = get_bounding_box;
+ 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;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:enlarge",
+ "title", "Smart enlarge",
+ "categories", "heal",
+ "description", "Enlarges an images based on pixel contents",
+ NULL);
+}
+
+#endif
diff --git a/operations/workshop/inpaint.c b/operations/workshop/inpaint.c
index 46639d8..472ba0c 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -23,19 +23,19 @@
#ifdef GEGL_PROPERTIES
-property_int (seek_distance, "seek radius", 16)
+property_int (seek_distance, "seek radius", 8)
value_range (4, 512)
-property_int (min_neigh, "min neigh", 7)
+property_int (min_neigh, "min neigh", 2)
value_range (1, 10)
-property_int (min_iter, "min iter", 96)
+property_int (min_iter, "min iter", 8)
value_range (1, 512)
-property_double (chance_try, "try chance", 0.66)
+property_double (chance_try, "try chance", 0.5)
value_range (0.0, 1.0)
-property_double (chance_retry, "retry chance", 0.33)
+property_double (chance_retry, "retry chance", 0.81)
value_range (0.0, 1.0)
#else
@@ -45,7 +45,6 @@ property_double (chance_retry, "retry chance", 0.33)
#define GEGL_OP_C_SOURCE inpaint.c
#include "gegl-op.h"
-#include <math.h>
#include <stdio.h>
#include "pixel-duster.h"
@@ -55,11 +54,8 @@ get_required_for_output (GeglOperation *operation,
const GeglRectangle *roi)
{
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
-
- /* Don't request an infinite plane */
if (gegl_rectangle_is_infinite_plane (&result))
return *roi;
-
return result;
}
@@ -81,12 +77,16 @@ process (GeglOperation *operation,
gint level)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
- PixelDuster *duster = pixel_duster_new (input, output, result,
+ GeglRectangle in_rect = *gegl_buffer_get_extent (input);
+ GeglRectangle out_rect = *gegl_buffer_get_extent (output);
+ PixelDuster *duster = pixel_duster_new (input, output, &in_rect, &out_rect,
o->seek_distance,
o->min_neigh,
o->min_iter,
o->chance_try,
o->chance_retry,
+ 1.0,
+ 1.0,
operation);
gegl_buffer_copy (input, NULL, GEGL_ABYSS_NONE, output, NULL);
diff --git a/operations/workshop/pixel-duster.h b/operations/workshop/pixel-duster.h
index c8965e6..69b8fb7 100644
--- a/operations/workshop/pixel-duster.h
+++ b/operations/workshop/pixel-duster.h
@@ -6,28 +6,44 @@
#define POW2(x) ((x)*(x))
#define INITIAL_SCORE 1200000000
-#define NEIGHBORHOOD 49
typedef struct
{
GeglOperation *op;
- GeglBuffer *input;
- GeglBuffer *output;
- GeglRectangle rect;
- int seek_radius;
- int minimum_neighbors;
- int minimum_iterations;
- float try_chance;
- float retry_chance;
- GHashTable *ht;
- GList *probes;
- int order[512][3];
+ GeglBuffer *input;
+ GeglBuffer *output;
+ GeglRectangle in_rect;
+ GeglRectangle out_rect;
+ int seek_radius;
+ int minimum_neighbors;
+ int minimum_iterations;
+ float try_chance;
+ float retry_chance;
+ float scale_x;
+ float scale_y;
+ GHashTable *ht;
+ GHashTable *probes_ht;
+ int order[512][3];
} PixelDuster;
+typedef struct Probe {
+ int target_x;
+ int target_y;
+ int score;
+ int age;
+ int source_x;
+ int source_y;
+} Probe;
+
+/* used for hash-table keys */
+#define xy2offset(x,y) GINT_TO_POINTER(((y) * 65536 + (x)))
+
+#define NEIGHBORHOOD 23
+
static void init_order(PixelDuster *duster)
{
int i, x, y;
-#if 1
+#if 0
int order_2d[][15]={
{ 0, 0, 0, 0, 0,142,111,112,126,128, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0,124,110, 86, 87, 88,113,129,143, 0, 0, 0},
@@ -84,12 +100,15 @@ static void init_order(PixelDuster *duster)
static PixelDuster * pixel_duster_new (GeglBuffer *input,
GeglBuffer *output,
- const GeglRectangle *rect,
+ const GeglRectangle *in_rect,
+ const GeglRectangle *out_rect,
int seek_radius,
int minimum_neighbors,
int minimum_iterations,
float try_chance,
float retry_chance,
+ float scale_x,
+ float scale_y,
GeglOperation *op)
{
PixelDuster *ret = g_malloc0 (sizeof (PixelDuster));
@@ -101,8 +120,12 @@ static PixelDuster * pixel_duster_new (GeglBuffer *input,
ret->try_chance = try_chance;
ret->retry_chance = retry_chance;
ret->op = op;
- ret->rect = *rect;
+ ret->in_rect = *in_rect;
+ ret->out_rect = *out_rect;
+ ret->scale_x = scale_x;
+ ret->scale_y = scale_y;
ret->ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ ret->probes_ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
init_order (ret);
return ret;
}
@@ -110,32 +133,88 @@ static PixelDuster * pixel_duster_new (GeglBuffer *input,
static void pixel_duster_destroy (PixelDuster *duster)
{
g_hash_table_destroy (duster->ht);
- while (duster->probes)
- {
- g_free (duster->probes->data);
- duster->probes = g_list_remove (duster->probes, duster->probes->data);
- }
+ g_hash_table_destroy (duster->probes_ht);
g_free (duster);
}
static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y, guchar *dst)
{
static const Babl *format = NULL;
- if (!format) format = babl_format ("R'G'B'A u8");
- for (int i = 0; i <= NEIGHBORHOOD; i++)
+ static const Babl *yformat = NULL;
+ guchar lum[8];
+ int bdir = 0;
+ if (!format){
+ format = babl_format ("R'G'B'A u8");
+ yformat = babl_format ("Y'aA u8");
+ }
+
+ /* figure out which of the up/down/left/right pixels are brightest,
+ using premultiplied alpha - do punish blank spots */
+
+ gegl_buffer_sample (input, x + 1, y + 0, NULL, &lum[0], yformat, GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_sample (input, x - 1, y + 0, NULL, &lum[2], yformat, GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_sample (input, x + 0, y + 1, NULL, &lum[3], yformat, GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_sample (input, x + 0, y - 1, NULL, &lum[4], yformat, GEGL_SAMPLER_NEAREST, 0);
+
+ for (int i = 1; i < 4; i++)
+ if (lum[i*2] > bdir)
+ bdir = i;
+
+ /* and orient our neighborhood fetching based on that */
+ switch (bdir)
{
- gegl_buffer_sample (input, x + duster->order[i][0], y + duster->order[i][1], NULL,
- &dst[i*4], format, GEGL_SAMPLER_NEAREST, 0);
+ case 0:
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ gegl_buffer_sample (input,
+ x + duster->order[i][0],
+ y + duster->order[i][1],
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ break;
+ case 1:
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ gegl_buffer_sample (input,
+ x - duster->order[i][0],
+ y - duster->order[i][1],
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ break;
+ case 2:
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ gegl_buffer_sample (input,
+ x + duster->order[i][1],
+ y + duster->order[i][0],
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ break;
+ case 3:
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ gegl_buffer_sample (input,
+ x - duster->order[i][1],
+ y - duster->order[i][0],
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ break;
+
+ break;
}
+
+#if 0
+ how to normalize,. go for max of up/down/left/
+#endif
+
}
-static int u8_rgb_diff (guchar *a, guchar *b)
+static inline int u8_rgb_diff (guchar *a, guchar *b)
{
- return POW2(a[0]-b[0]) * 2 + POW2(a[1]-b[1]) * 4 + POW2(a[2]-b[2]) * 1;
+ return POW2(a[0]-b[0]) * 2 + POW2(a[1]-b[1]) * 4 + POW2(a[2]-b[2]);
}
-
-static int inline score_site (PixelDuster *duster, guchar *needle, guchar *hay, int bail)
+static int inline
+score_site (PixelDuster *duster,
+ guchar *needle,
+ guchar *hay,
+ int bail)
{
int i;
int score = 0;
@@ -161,28 +240,21 @@ static int inline score_site (PixelDuster *duster, guchar *needle, guchar *hay,
return score;
}
-typedef struct Probe {
- int target_x;
- int target_y;
- int age;
- int score;
- int source_x;
- int source_y;
-} Probe;
-
-
-static void add_probe (PixelDuster *duster, int target_x, int target_y)
+static void
+add_probe (PixelDuster *duster, int target_x, int target_y)
{
Probe *probe = g_malloc0 (sizeof (Probe));
probe->target_x = target_x;
probe->target_y = target_y;
- probe->source_x = target_x;
- probe->source_y = target_y;
+ probe->source_x = target_x / duster->scale_x;
+ probe->source_y = target_y / duster->scale_y;
probe->score = INITIAL_SCORE;
- duster->probes = g_list_prepend (duster->probes, probe);
+ g_hash_table_insert (duster->probes_ht,
+ xy2offset(target_x, target_y), probe);
}
-static int probe_rel_is_set (GeglBuffer *output, Probe *probe, int rel_x, int rel_y)
+static int
+probe_rel_is_set (GeglBuffer *output, Probe *probe, int rel_x, int rel_y)
{
static const Babl *format = NULL;
guchar pix[4];
@@ -191,32 +263,79 @@ static int probe_rel_is_set (GeglBuffer *output, Probe *probe, int rel_x, int re
return pix[3] > 5;
}
+static int
+probe_neighbors (GeglBuffer *output, Probe *probe, int min)
+{
+ int found = 0;
+ if (probe_rel_is_set (output, probe, -1, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 1, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, 1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, -1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 1, 1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 2, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, 2)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, -2, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, -2)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, -1,-1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 1,-1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, -1, 1)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, -3, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 3, 0)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, 3)) found ++;
+ if (found >=min) return found;
+ if (probe_rel_is_set (output, probe, 0, -3)) found ++;
+ return found;
+}
-static int probe_neighbors (GeglBuffer *output, Probe *probe)
+static inline int
+spread_relative (PixelDuster *duster, Probe *probe, int dx, int dy)
{
- return probe_rel_is_set (output, probe, -1, 0) +
- probe_rel_is_set (output, probe, 1, 0) +
- probe_rel_is_set (output, probe, 0, 1) +
- probe_rel_is_set (output, probe, 0, -1)
-#if 1
- + probe_rel_is_set (output, probe, 1, 1)
- + probe_rel_is_set (output, probe, 2, 0)
- + probe_rel_is_set (output, probe, 0, 2)
- + probe_rel_is_set (output, probe, -2, 0)
- + probe_rel_is_set (output, probe, 0, -2)
- + probe_rel_is_set (output, probe, -1,-1)
- + probe_rel_is_set (output, probe, 1,-1)
- + probe_rel_is_set (output, probe, -1, 1)
- + probe_rel_is_set (output, probe, -3, 0)
- + probe_rel_is_set (output, probe, 3, 0)
- + probe_rel_is_set (output, probe, 0, 3)
- + probe_rel_is_set (output, probe, 0, -3)
-#endif
-;
+ static const Babl *format = NULL;
+
+ if (!format)
+ format = babl_format ("RGBA float");
+
+ /* spread our resulting neighborhodo to unset neighbors */
+ if (!probe_rel_is_set (duster->output, probe, dx, dy))
+ {
+ Probe *neighbor_probe = g_hash_table_lookup (duster->probes_ht,
+ xy2offset(probe->target_x + dx, probe->target_y + dy));
+ if (neighbor_probe)
+ {
+ gfloat rgba[4];
+ gegl_buffer_sample (duster->input, probe->source_x + dx, probe->source_y + dy, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
+ if (rgba[3] > 0.001)
+ {
+ neighbor_probe->source_x = probe->source_x + dx;
+ neighbor_probe->source_y = probe->source_y + dy;
+ neighbor_probe->score = INITIAL_SCORE - 1;
+ gegl_buffer_set (duster->output,
+ GEGL_RECTANGLE(neighbor_probe->target_x,
+ neighbor_probe->target_y, 1, 1),
+ 0, format, &rgba[0], 0);
+ return 1;
+ }
+ }
+ }
+ return 0;
}
-static int probe_improve (PixelDuster *duster,
- Probe *probe)
+static int probe_improve (PixelDuster *duster,
+ Probe *probe)
{
guchar needle[4 * NEIGHBORHOOD];
gint dst_x = probe->target_x;
@@ -239,28 +358,25 @@ static int probe_improve (PixelDuster *duster,
for (int dy = -duster->seek_radius; dy < duster->seek_radius; dy ++)
for (int dx = -duster->seek_radius ; dx < duster->seek_radius; dx ++)
{
-#define xy2offset(x,y) ((y) * duster->rect.width + (x))
- int offset = xy2offset(start_x + dx, start_y + dy);
int score;
guchar *hay = NULL;
- if (start_x + dx == dst_x &&
- start_y + dy == dst_y)
- continue;
-
- if (offset < 0 || offset >= duster->rect.width * duster->rect.height)
+ if (duster->scale_x == 1.0 && start_x + dx == dst_x &&
+ duster->scale_y == 1.0 && start_y + dy == dst_y)
continue;
+#if 1
if (start_x + dx < 5 || start_y + dy < 5 ||
- start_x + dx > duster->rect.width - 5 ||
- start_y + dy > duster->rect.height - 5)
+ start_x + dx > duster->in_rect.width - 5 ||
+ start_y + dy > duster->in_rect.height - 5)
continue;
-
- hay = g_hash_table_lookup (duster->ht, GINT_TO_POINTER(offset));
+#endif
+ hay = g_hash_table_lookup (duster->ht, xy2offset(start_x + dx, start_y + dy));
if (!hay)
{
hay = g_malloc (4 * NEIGHBORHOOD);
extract_site (duster, duster->input, start_x + dx, start_y + dy, hay);
- g_hash_table_insert (duster->ht, GINT_TO_POINTER(offset), hay);
+ g_hash_table_insert (duster->ht, xy2offset(start_x + dx, start_y + dy), hay);
+
}
score = score_site (duster, &needle[0], hay, probe->score);
@@ -272,102 +388,21 @@ static int probe_improve (PixelDuster *duster,
probe->score = score;
}
}
+ if (probe->score == old_score)
+ return -1;
+ spread_relative (duster, probe, -1, -1);
+ spread_relative (duster, probe, -1, 0);
+ spread_relative (duster, probe, 0, -1);
+ spread_relative (duster, probe, 1, 0);
+ spread_relative (duster, probe, 0, 1);
- if (old_score != probe->score && old_score != INITIAL_SCORE)
- {
- /* spread our resulting neighborhodo to unset neighbors */
- if (!probe_rel_is_set (duster->output, probe, -1, 0))
- {
- for (GList *l = duster->probes; l; l = l->next)
- {
- Probe *neighbor_probe = l->data;
- if ( (probe->target_y == neighbor_probe->target_y) &&
- ((probe->target_x - 1) == neighbor_probe->target_x))
- {
- gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x - 1, probe->source_y, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
- if (rgba[3] > 0.001)
- {
- neighbor_probe->source_x = probe->source_x - 1;
- neighbor_probe->source_y = probe->source_y;
- neighbor_probe->score --;
- gegl_buffer_set (duster->output, GEGL_RECTANGLE(neighbor_probe->target_x,
neighbor_probe->target_y, 1, 1), 0, format, &rgba[0], 0);
- neighbor_probe->age++;
- }
- }
- }
- }
-
- if (!probe_rel_is_set (duster->output, probe, 1, 0))
- {
- for (GList *l = duster->probes; l; l = l->next)
- {
- Probe *neighbor_probe = l->data;
- if ( (probe->target_y == neighbor_probe->target_y) &&
- ((probe->target_x + 1) == neighbor_probe->target_x))
- {
- gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x + 1, probe->source_y, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
- if (rgba[3] > 0.001)
- {
- neighbor_probe->source_x = probe->source_x + 1;
- neighbor_probe->source_y = probe->source_y;
- neighbor_probe->score --;
- gegl_buffer_set (duster->output, GEGL_RECTANGLE(neighbor_probe->target_x,
neighbor_probe->target_y, 1, 1), 0, format, &rgba[0], 0);
- neighbor_probe->age++;
- }
- }
- }
- }
-
- if (!probe_rel_is_set (duster->output, probe, 0, -1))
- {
- for (GList *l = duster->probes; l; l = l->next)
- {
- Probe *neighbor_probe = l->data;
- if ( (probe->target_y - 1 == neighbor_probe->target_y) &&
- ((probe->target_x ) == neighbor_probe->target_x))
- {
- gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x, probe->source_y - 1, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
- if (rgba[3] > 0.001)
- {
- neighbor_probe->source_x = probe->source_x;
- neighbor_probe->source_y = probe->source_y - 1;
- neighbor_probe->score --;
- gegl_buffer_set (duster->output, GEGL_RECTANGLE(neighbor_probe->target_x,
neighbor_probe->target_y, 1, 1), 0, format, &rgba[0], 0);
- neighbor_probe->age++;
- }
- }
- }
- }
-
- if (!probe_rel_is_set (duster->output, probe, 0, 1))
- {
- for (GList *l = duster->probes; l; l = l->next)
- {
- Probe *neighbor_probe = l->data;
- if ( (probe->target_y + 1 == neighbor_probe->target_y) &&
- ((probe->target_x ) == neighbor_probe->target_x))
- {
- gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x, probe->source_y + 1, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
- if (rgba[3] > 0.001)
- {
- neighbor_probe->source_x = probe->source_x;
- neighbor_probe->source_y = probe->source_y + 1;
- neighbor_probe->score --;
- gegl_buffer_set (duster->output, GEGL_RECTANGLE(neighbor_probe->target_x,
neighbor_probe->target_y, 1, 1), 0, format, &rgba[0], 0);
- neighbor_probe->age++;
- }
- }
- }
- }
-
+ probe->age++;
+ if (probe->age > 5)
+ {
+ g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
}
- if (probe->score == old_score)
- return -1;
+
return 0;
}
@@ -375,7 +410,7 @@ static void pixel_duster_add_probes (PixelDuster *duster)
{
const Babl *format = babl_format ("RGBA float");
GeglBufferIterator *i = gegl_buffer_iterator_new (duster->output,
- &duster->rect,
+ &duster->out_rect,
0,
format,
GEGL_ACCESS_WRITE,
@@ -406,19 +441,18 @@ static void pixel_duster_add_probes (PixelDuster *duster)
static void pixel_duster_fill (PixelDuster *duster)
{
- GeglProperties *o = GEGL_PROPERTIES (duster->op);
const Babl *format = babl_format ("RGBA float");
gint missing = 1;
gint old_missing = 3;
gint total = 0;
gint runs = 0;
- while (missing != old_missing || runs < o->min_iter)
+ while ( (missing >0 && missing != old_missing) || runs < duster->minimum_iterations)
{ runs++;
total = 0;
old_missing = missing;
missing = 0;
- for (GList *p= duster->probes; p; p= p->next)
+ for (GList *p= g_hash_table_get_values (duster->probes_ht); p; p= p->next)
{
Probe *probe = p->data;
gint try_replace;
@@ -430,22 +464,20 @@ static void pixel_duster_fill (PixelDuster *duster)
}
else
{
- try_replace = (probe->age < 8 &&
- ((rand()%100)/100.0) < duster->retry_chance);
+ try_replace = ((rand()%100)/100.0) < duster->retry_chance;
}
total ++;
- if ((probe->source_x == probe->target_x &&
- probe->source_y == probe->target_y) || try_replace)
+ if (probe->score == INITIAL_SCORE || try_replace)
{
if ((probe->source_x == probe->target_x &&
probe->source_y == probe->target_y))
try_replace = 0;
- if ((rand()%100)/100.0 < duster->try_chance && probe_neighbors (duster->output, probe) >=
duster->minimum_neighbors)
+ if ((rand()%100)/100.0 < duster->try_chance && probe_neighbors (duster->output, probe,
duster->minimum_neighbors) >= duster->minimum_neighbors)
{
if(try_replace)
- probe->score = INITIAL_SCORE;
+ probe->score = INITIAL_SCORE;
if (probe_improve (duster, probe) == 0)
{
gfloat rgba[4];
@@ -453,19 +485,18 @@ static void pixel_duster_fill (PixelDuster *duster)
if (rgba[3] <= 0.01)
fprintf (stderr, "eek %i,%i %f %f %f %f\n", probe->source_x, probe->source_y, rgba[0], rgba[1],
rgba[2], rgba[3]);
gegl_buffer_set (duster->output, GEGL_RECTANGLE(probe->target_x, probe->target_y, 1, 1), 0,
format, &rgba[0], 0);
- probe->age++;
}
}
}
}
- gegl_operation_progress (duster->op, (total-missing) * 1.0 / total,
- "finding suitable pixels");
-#if 0
+ if (duster->op)
+ gegl_operation_progress (duster->op, (total-missing) * 1.0 / total,
+ "finding suitable pixels");
+#if 1
fprintf (stderr, "\r%i/%i %2.2f run#:%i ", total-missing, total, (total-missing) * 100.0 / total, runs);
#endif
}
-#if 0
+#if 1
fprintf (stderr, "\n");
#endif
}
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]