[gegl] workshop: refactor alpha-inpaint to not have global state
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] workshop: refactor alpha-inpaint to not have global state
- Date: Thu, 8 Feb 2018 13:48:03 +0000 (UTC)
commit 5cd716e88ed2a0bcc5cc47200df2b789f2691402
Author: Øyvind Kolås <pippin gimp org>
Date: Thu Feb 8 12:44:20 2018 +0100
workshop: refactor alpha-inpaint to not have global state
operations/workshop/inpaint.c | 256 +++++++++++++++++++++++------------------
1 files changed, 144 insertions(+), 112 deletions(-)
---
diff --git a/operations/workshop/inpaint.c b/operations/workshop/inpaint.c
index 11af44d..6366cd3 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -52,8 +52,28 @@ property_double (chance_retry, "retry chance", 0.33)
#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];
+} PixelDuster;
+
+static void init_order(PixelDuster *duster)
+{
+ int i, x, y;
#if 1
-int order_2d[][15]={
+ 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},
{ 0, 0, 0,125,109, 85, 58, 59, 60, 89, 90,114, 0, 0, 0},
@@ -71,7 +91,7 @@ int order_2d[][15]={
{ 0, 0, 0, 0,144,138,136,134,135,137,141, 0, 0, 0, 0},
};
#else
-int order_2d[][15]={
+ int order_2d[][15]={
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
@@ -90,20 +110,9 @@ int order_2d[][15]={
};
#endif
-static int order[512][3];
-static GHashTable *ht = NULL;
-static GList *probes = NULL;
-
-static void init_order(void)
-{
- static int inited = 0;
- int i, x, y;
- if (inited)
- return;
-
- order[0][0] = 0;
- order[0][1] = 0;
- order[0][2] = 1;
+ duster->order[0][0] = 0;
+ duster->order[0][1] = 0;
+ duster->order[0][2] = 1;
for (i = 1; i < 159; i++)
for (y = -7; y <= 7; y ++)
@@ -111,46 +120,56 @@ static void init_order(void)
{
if (order_2d[x+7][y+7] == i)
{
- order[i][0] = x;
- order[i][1] = y;
- order[i][2] = POW2(x)+POW2(y);
+ duster->order[i][0] = x;
+ duster->order[i][1] = y;
+ duster->order[i][2] = POW2(x)+POW2(y);
}
}
- inited = 1;
}
-
-static void
-prepare (GeglOperation *operation)
+static PixelDuster * pixel_duster_new (GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *rect,
+ int seek_radius,
+ int minimum_neighbors,
+ int minimum_iterations,
+ float try_chance,
+ float retry_chance,
+ GeglOperation *op)
{
- const Babl *format = babl_format ("RGBA float");
-
- gegl_operation_set_format (operation, "input", format);
- gegl_operation_set_format (operation, "output", format);
+ PixelDuster *ret = g_malloc0 (sizeof (PixelDuster));
+ ret->input = input;
+ ret->output = output;
+ ret->seek_radius = seek_radius;
+ ret->minimum_neighbors = minimum_neighbors;
+ ret->minimum_iterations = minimum_iterations;
+ ret->try_chance = try_chance;
+ ret->retry_chance = retry_chance;
+ ret->op = op;
+ ret->rect = *rect;
+ ret->ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ init_order (ret);
+ return ret;
}
-static GeglRectangle
-get_required_for_output (GeglOperation *operation,
- const gchar *input_pad,
- const GeglRectangle *roi)
+static void pixel_duster_destroy (PixelDuster *duster)
{
- 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;
+ 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_free (duster);
}
-
-static void extract_site (GeglBuffer *input, int x, int y, guchar *dst)
+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++)
{
- gegl_buffer_sample (input, x + order[i][0], y + order[i][1], NULL,
+ gegl_buffer_sample (input, x + duster->order[i][0], y + duster->order[i][1], NULL,
&dst[i*4], format, GEGL_SAMPLER_NEAREST, 0);
}
}
@@ -161,7 +180,7 @@ static int u8_rgb_diff (guchar *a, guchar *b)
}
-static int inline score_site (guchar *needle, guchar *hay, int bail)
+static int inline score_site (PixelDuster *duster, guchar *needle, guchar *hay, int bail)
{
int i;
int score = 0;
@@ -176,12 +195,12 @@ static int inline score_site (guchar *needle, guchar *hay, int bail)
{
if (needle[i*4 + 3] && hay[i*4 + 3])
{
- score += u8_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * 10 / order[i][2];
+ score += u8_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * 10 / duster->order[i][2];
}
else
{
/* we score missing cells as if it is a big diff */
- score += ((POW2(36))*3) * 70 / order[i][2];
+ score += ((POW2(36))*3) * 70 / duster->order[i][2];
}
}
return score;
@@ -197,7 +216,7 @@ typedef struct Probe {
} Probe;
-static void add_probe (GeglOperation *operation, 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;
@@ -205,7 +224,7 @@ static void add_probe (GeglOperation *operation, int target_x, int target_y)
probe->source_x = target_x;
probe->source_y = target_y;
probe->score = INITIAL_SCORE;
- probes = g_list_prepend (probes, probe);
+ duster->probes = g_list_prepend (duster->probes, probe);
}
static int probe_rel_is_set (GeglBuffer *output, Probe *probe, int rel_x, int rel_y)
@@ -241,14 +260,9 @@ static int probe_neighbors (GeglBuffer *output, Probe *probe)
;
}
-static int probe_improve (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *output,
- const GeglRectangle *result,
- Probe *probe,
- int min_neighbours)
+static int probe_improve (PixelDuster *duster,
+ Probe *probe)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
guchar needle[4 * NEIGHBORHOOD];
gint dst_x = probe->target_x;
gint dst_y = probe->target_y;
@@ -260,22 +274,17 @@ static int probe_improve (GeglOperation *operation,
static const Babl *format = NULL;
if (!format)
format = babl_format ("RGBA float");
- extract_site (output, dst_x, dst_y, &needle[0]);
+ extract_site (duster, duster->output, dst_x, dst_y, &needle[0]);
#if 0
if (probe->score < 10000)
return 0;
#endif
-#if 0
- for (int dy = -o->seek_distance; dy < o->seek_distance; dy += (dy*dy < 64 ? 1 : 3))
- for (int dx = -o->seek_distance ; dx < o->seek_distance; dx += (dx*dx < 64 ? 1 : 3))
-#else
- for (int dy = -o->seek_distance; dy < o->seek_distance; dy ++)
- for (int dx = -o->seek_distance ; dx < o->seek_distance; dx ++)
-#endif
+ 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) * result->width + (x))
+#define xy2offset(x,y) ((y) * duster->rect.width + (x))
int offset = xy2offset(start_x + dx, start_y + dy);
int score;
guchar *hay = NULL;
@@ -284,22 +293,22 @@ static int probe_improve (GeglOperation *operation,
start_y + dy == dst_y)
continue;
- if (offset < 0 || offset >= result->width * result->height)
+ if (offset < 0 || offset >= duster->rect.width * duster->rect.height)
continue;
if (start_x + dx < 5 || start_y + dy < 5 ||
- start_x + dx > result->width - 5 ||
- start_y + dy > result->height - 5)
+ start_x + dx > duster->rect.width - 5 ||
+ start_y + dy > duster->rect.height - 5)
continue;
- hay = g_hash_table_lookup (ht, GINT_TO_POINTER(offset));
+ hay = g_hash_table_lookup (duster->ht, GINT_TO_POINTER(offset));
if (!hay)
{
hay = g_malloc (4 * NEIGHBORHOOD);
- extract_site (input, start_x + dx, start_y + dy, hay);
- g_hash_table_insert (ht, GINT_TO_POINTER(offset), hay);
+ extract_site (duster, duster->input, start_x + dx, start_y + dy, hay);
+ g_hash_table_insert (duster->ht, GINT_TO_POINTER(offset), hay);
}
- score = score_site (&needle[0], hay, probe->score);
+ score = score_site (duster, &needle[0], hay, probe->score);
if (score < probe->score)
{
@@ -312,88 +321,88 @@ static int probe_improve (GeglOperation *operation,
if (old_score != probe->score && old_score != INITIAL_SCORE)
{
/* spread our resulting neighborhodo to unset neighbors */
- if (!probe_rel_is_set (output, probe, -1, 0))
+ if (!probe_rel_is_set (duster->output, probe, -1, 0))
{
- for (GList *l = probes; l; l = l->next)
+ 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 (input, probe->source_x - 1, probe->source_y, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+ 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 (output, GEGL_RECTANGLE(neighbor_probe->target_x, neighbor_probe->target_y,
1, 1), 0, format, &rgba[0], 0);
+ 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 (output, probe, 1, 0))
+ if (!probe_rel_is_set (duster->output, probe, 1, 0))
{
- for (GList *l = probes; l; l = l->next)
+ 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 (input, probe->source_x + 1, probe->source_y, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+ 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 (output, GEGL_RECTANGLE(neighbor_probe->target_x, neighbor_probe->target_y,
1, 1), 0, format, &rgba[0], 0);
+ 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 (output, probe, 0, -1))
+ if (!probe_rel_is_set (duster->output, probe, 0, -1))
{
- for (GList *l = probes; l; l = l->next)
+ 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 (input, probe->source_x, probe->source_y - 1, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+ 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 (output, GEGL_RECTANGLE(neighbor_probe->target_x, neighbor_probe->target_y,
1, 1), 0, format, &rgba[0], 0);
+ 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 (output, probe, 0, 1))
+ if (!probe_rel_is_set (duster->output, probe, 0, 1))
{
- for (GList *l = probes; l; l = l->next)
+ 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 (input, probe->source_x, probe->source_y + 1, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+ 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 (output, GEGL_RECTANGLE(neighbor_probe->target_x, neighbor_probe->target_y,
1, 1), 0, format, &rgba[0], 0);
+ 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++;
}
}
@@ -407,7 +416,7 @@ static int probe_improve (GeglOperation *operation,
return 0;
}
-static void copy_buf (GeglOperation *operation,
+static void copy_buf (PixelDuster *duster,
GeglBuffer *input,
GeglBuffer *output,
const GeglRectangle *result)
@@ -436,7 +445,7 @@ static void copy_buf (GeglOperation *operation,
out_pix[1] = 0;
out_pix[2] = 0;
out_pix[3] = 0;
- add_probe (operation, x, y);
+ add_probe (duster, x, y);
}
else
{
@@ -459,12 +468,34 @@ static void copy_buf (GeglOperation *operation,
}
}
-static void do_inpaint (GeglOperation *operation,
- GeglBuffer *input,
- GeglBuffer *output,
- const GeglRectangle *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 GeglRectangle
+get_required_for_output (GeglOperation *operation,
+ const gchar *input_pad,
+ 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;
+}
+
+
+
+static void pixel_duster_fill (PixelDuster *duster)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglProperties *o = GEGL_PROPERTIES (duster->op);
const Babl *format = babl_format ("RGBA float");
gint missing = 1;
gint old_missing = 3;
@@ -476,7 +507,7 @@ static void do_inpaint (GeglOperation *operation,
total = 0;
old_missing = missing;
missing = 0;
- for (GList *p= probes; p; p= p->next)
+ for (GList *p= duster->probes; p; p= p->next)
{
Probe *probe = p->data;
gint try_replace;
@@ -489,7 +520,7 @@ static void do_inpaint (GeglOperation *operation,
else
{
try_replace = (probe->age < 8 &&
- ((rand()%100)/100.0) < o->chance_retry);
+ ((rand()%100)/100.0) < duster->retry_chance);
}
total ++;
@@ -500,29 +531,31 @@ static void do_inpaint (GeglOperation *operation,
probe->source_y == probe->target_y))
try_replace = 0;
- if ((rand()%100)/100.0 < o->chance_try && probe_neighbors (output, probe) >= o->min_neigh)
+ if ((rand()%100)/100.0 < duster->try_chance && probe_neighbors (duster->output, probe) >=
duster->minimum_neighbors)
{
if(try_replace)
probe->score = INITIAL_SCORE;
- if (probe_improve (operation, input, output, result, probe, 1) == 0)
+ if (probe_improve (duster, probe) == 0)
{
gfloat rgba[4];
- gegl_buffer_sample (input, probe->source_x, probe->source_y, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_sample (duster->input, probe->source_x, probe->source_y, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
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 (output, GEGL_RECTANGLE(probe->target_x, probe->target_y, 1, 1), 0, format,
&rgba[0], 0);
+ 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 (operation, (total-missing) * 1.0 / total,
+ gegl_operation_progress (duster->op, (total-missing) * 1.0 / total,
"finding suitable pixels");
#if 0
fprintf (stderr, "\r%i/%i %2.2f run#:%i ", total-missing, total, (total-missing) * 100.0 / total, runs);
#endif
}
+#if 0
fprintf (stderr, "\n");
+#endif
}
@@ -533,19 +566,18 @@ process (GeglOperation *operation,
const GeglRectangle *result,
gint level)
{
- init_order ();
- ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
-
- copy_buf (operation, input, output, result);
- do_inpaint (operation, input, output, result);
-
- while (probes)
- {
- g_free (probes->data);
- probes = g_list_remove (probes, probes->data);
- }
-
- g_hash_table_destroy (ht);
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ PixelDuster *duster = pixel_duster_new (input, output, result,
+ o->seek_distance,
+ o->min_neigh,
+ o->min_iter,
+ o->chance_try,
+ o->chance_retry,
+ operation);
+
+ copy_buf (duster, input, output, result);
+ pixel_duster_fill (duster);
+ pixel_duster_destroy (duster);
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]