[gegl] workshop: inpaint, implement batching of probes
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] workshop: inpaint, implement batching of probes
- Date: Sun, 30 Jun 2019 00:41:31 +0000 (UTC)
commit 910c859ef2c839c03d2ee3729264c42fd876d7d5
Author: Øyvind Kolås <pippin gimp org>
Date: Sat Jun 29 21:10:46 2019 +0200
workshop: inpaint, implement batching of probes
operations/workshop/inpaint.c | 4 +-
operations/workshop/pixel-duster.h | 341 ++++++++++++++++++++++---------------
2 files changed, 201 insertions(+), 144 deletions(-)
---
diff --git a/operations/workshop/inpaint.c b/operations/workshop/inpaint.c
index 38a1c4b25..176523f2d 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -60,8 +60,8 @@ property_double (metric_dist_powk, "metric dist powk", 1.35)
ui_steps (0.1, 1.0)
property_double (metric_empty_score, "metric empty score", 0.25)
- value_range (0.0, 100.0)
- ui_steps (0.25, 1.0)
+ value_range (0.1, 100.0)
+ ui_steps (0.1, 0.1)
#else
diff --git a/operations/workshop/pixel-duster.h b/operations/workshop/pixel-duster.h
index 0e5e84c86..82f521176 100644
--- a/operations/workshop/pixel-duster.h
+++ b/operations/workshop/pixel-duster.h
@@ -82,28 +82,34 @@ typedef struct
#define MAX_K 4
-#define RINGS 4 // increments works up to 7-8 with no adver
+#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 NEIGHBORHOOD (RINGS*RAYS+1)
#define N_SCALE_NEEDLES 1
-typedef struct Probe {
- float needles[N_SCALE_NEEDLES][4 * NEIGHBORHOOD ];
+#define BATCH_PROBES 64 // batch this many probes to process concurently
+ // it is slightly faster than doing a full ht
+ // iteration per probe on single core
+
+typedef struct _Probe Probe;
+
+struct _Probe {
+ float needles[N_SCALE_NEEDLES][4 * NEIGHBORHOOD ];
int target_x;
int target_y;
int neighbors;
int age;
int k;
float score;
+ float old_score;
+ Probe *n1;
float k_score[MAX_K];
- /* should store sampled coordinates instead */
- /* the only real datamembers are below and should be float*/
float source_x[MAX_K];
float source_y[MAX_K];
gfloat *hay[MAX_K];
-} Probe;
+};
/* used for hash-table keys */
#define xy2offset(x,y) GINT_TO_POINTER(((y) * 65536 + (x)))
@@ -301,7 +307,7 @@ static void extract_site (PixelDuster *duster, GeglBuffer *buffer, double x, dou
if (warmest_ray)
{
- for (int i = 0; i <= NEIGHBORHOOD*4; i++)
+ for (int i = 0; i < NEIGHBORHOOD*4; i++)
tmp[i] = dst[i];
for (int ray = 0; ray < RAYS; ray ++)
@@ -340,14 +346,14 @@ score_site (PixelDuster *duster,
float score = 0;
/* bail early with really bad score - the target site doesnt have opacity */
- if (hay[3] < 0.001)
+ if (hay[3] < 0.001f)
{
return INITIAL_SCORE;
}
- for (i = 0; i < NEIGHBORHOOD && score < bail; i++)
+ for (i = 1; i < NEIGHBORHOOD && score < bail; i++)
{
- if (needle[i*4 + 3]<1.0 && hay[i*4 + 3]>0.001)
+ if (needle[i*4 + 3]<1.0f && hay[i*4 + 3]>0.001f)
{
score += f_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * duster->order[i][2];
}
@@ -356,7 +362,7 @@ score_site (PixelDuster *duster,
score += duster->metric_empty_score * duster->order[i][2];
}
}
- return score;
+ return sqrtf (score);
}
static Probe *
@@ -403,7 +409,6 @@ probe_rel_is_set (PixelDuster *duster, GeglBuffer *output, Probe *probe, int rel
}
#define ret_if_good if (found >=min) goto ret;
-
static int
probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
@@ -436,96 +441,67 @@ ret:
return found;
}
-#if 0
-static void inline compare_needle_exact (gpointer key, gpointer value, gpointer data)
-{
- void **ptr = data;
- //PixelDuster *duster = ptr[0];
- gfloat *new_hay;
- gfloat *val_hay;
- gint *found_count = ptr[2];
- if (*found_count)
- return;
-
- new_hay = ptr[1];
- val_hay = value;
-
- for (int i = 4; i < 4 * NEIGHBORHOOD; i++)
- {
- int diff = ((int)(new_hay[i])) - ((int)(val_hay[i]));
- if ( (diff <= -2) || (diff >= 2))
- return;
- }
- (*found_count)++;
-}
-#endif
-
-static gfloat *ensure_hay (PixelDuster *duster, int x, int y, int subset)
+static gfloat *ensure_hay (PixelDuster *duster, int x, int y)
{
gfloat *hay = NULL;
- if (subset >= 0)
- hay = g_hash_table_lookup (duster->ht[subset], xy2offset(x, y));
+ hay = g_hash_table_lookup (duster->ht[0], xy2offset(x, y));
if (!hay)
{
hay = g_malloc ((4 * NEIGHBORHOOD) * 4);
extract_site (duster, duster->reference, x, y, 1.0, hay);
- if (subset < 0)
- {
- if (hay[3] == 0)
- {
- g_free (hay);
- return NULL;
- }
- }
- subset = 0;
- {
-#if 0
- gint found_count = 0;
- void *ptr[3] = {duster, &hay[0], &found_count};
- g_hash_table_foreach (duster->ht[subset], compare_needle_exact, ptr);
- if (found_count)
- {
- g_free (hay);
- }
- else
-#endif
- {
- g_hash_table_insert (duster->ht[subset], xy2offset(x, y), hay);
- }
- }
+ g_hash_table_insert (duster->ht[0], xy2offset(x, y), hay);
}
return hay;
}
-/* XXX : replace with compare_needles */
-static void compare_needle (gpointer key, gpointer value, gpointer data)
+static inline void
+probe_prep (PixelDuster *duster,
+ Probe *probe)
{
- void **ptr = data;
- PixelDuster *duster = ptr[0];
- Probe *probe = ptr[1];
- gfloat *hay = value;
- gint offset = GPOINTER_TO_INT (key);
- gint x = offset % 65536;
- gint y = offset / 65536;
+ gint dst_x = probe->target_x;
+ gint dst_y = probe->target_y;
+ extract_site (duster, duster->output, dst_x, dst_y, 1.0, &probe->needles[0][0]);
+ if (N_SCALE_NEEDLES > 1)
+ extract_site (duster, duster->output, dst_x, dst_y, 0.9, &probe->needles[1][0]);
+ if (N_SCALE_NEEDLES > 2)
+ extract_site (duster, duster->output, dst_x, dst_y, 1.1, &probe->needles[2][0]);
+ if (N_SCALE_NEEDLES > 3)
+ extract_site (duster, duster->output, dst_x, dst_y, 0.8, &probe->needles[3][0]);
+ if (N_SCALE_NEEDLES > 4)
+ extract_site (duster, duster->output, dst_x, dst_y, 1.2, &probe->needles[4][0]);
+ if (N_SCALE_NEEDLES > 5)
+ extract_site (duster, duster->output, dst_x, dst_y, 0.66, &probe->needles[5][0]);
+ if (N_SCALE_NEEDLES > 6)
+ extract_site (duster, duster->output, dst_x, dst_y, 1.5, &probe->needles[6][0]);
+ probe->old_score = probe->score;
+}
+
+static void probe_compare_hay (PixelDuster *duster,
+ Probe *probe,
+ gfloat *hay,
+ gint x, gint y)
+{
+
float score;
-#if 1
#define pow2(a) ((a)*(a))
+
if ( duster->seek_radius > 1 &&
pow2 (probe->target_x / duster->scale_x - x) +
pow2 (probe->target_y / duster->scale_y - y) >
pow2 (duster->seek_radius))
- return;
-#endif
-
#if 0
if (duster->scale_x == 1.0 && x == probe->target_x &&
- duster->scale_y == 1.0 && y == probe->target_y )
return;
#endif
+ {
+ }
+ else
+ {
for (int n = 0; n < N_SCALE_NEEDLES; n++)
{
@@ -550,68 +526,145 @@ static void compare_needle (gpointer key, gpointer value, gpointer data)
probe->score = probe->k_score[0] = score;
}
}
+
+ }
+}
+
+static void compare_needle (gpointer key, gpointer value, gpointer data)
+{
+ void **ptr = data;
+ PixelDuster *duster = ptr[0];
+ Probe *probe = ptr[1];
+ gfloat *hay = value;
+ gint offset = GPOINTER_TO_INT (key);
+ gint x = offset % 65536;
+ gint y = offset / 65536;
+
+ probe_compare_hay (duster, probe, hay, x, y);
+}
+
+static void
+probe_post_search (PixelDuster *duster, Probe *probe)
+{
+ static const Babl *format = NULL;
+ if (!format)
+ format = babl_format ("RGBA float");
+ probe->age++;
+
+ if (probe->score != probe->old_score)
+ {
+ gfloat sum_rgba[4]={0.0,0.0,0.0,0.0};
+ gfloat rgba[4];
+
+ if (probe->k>1)
+ {
+ for (gint i = 0; i < probe->k; i++)
+ {
+ gegl_sampler_get (duster->in_sampler_f,
+ probe->source_x[i], probe->source_y[i],
+ NULL, &rgba[0], 0);
+ for (gint c = 0; c < 4; c++)
+ sum_rgba[c] += rgba[c];
+ }
+ for (gint c = 0; c < 4; c++)
+ rgba[c] = sum_rgba[c] / probe->k;
+ }
+ else
+ {
+ gegl_sampler_get (duster->in_sampler_f,
+ probe->source_x[0], probe->source_y[0], NULL,
+ &rgba[0], 0);
+ }
+
+ gegl_buffer_set (duster->output,
+ GEGL_RECTANGLE(probe->target_x, probe->target_y, 1, 1),
+ 0, format, &rgba[0], 0);
+ }
}
static int probe_improve (PixelDuster *duster,
Probe *probe)
{
- gint dst_x = probe->target_x;
- gint dst_y = probe->target_y;
void *ptr[2] = {duster, probe};
- float old_score = probe->score;
static const Babl *format = NULL;
if (probe->age >= duster->max_age)
{
- g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
+ g_hash_table_remove (duster->probes_ht,
+ xy2offset(probe->target_x, probe->target_y));
return -1;
}
if (!format)
format = babl_format ("RGBA float");
- extract_site (duster, duster->output, dst_x, dst_y, 1.0, &probe->needles[0][0]);
- if (N_SCALE_NEEDLES > 1)
- extract_site (duster, duster->output, dst_x, dst_y, 0.9, &probe->needles[1][0]);
- if (N_SCALE_NEEDLES > 2)
- extract_site (duster, duster->output, dst_x, dst_y, 1.1, &probe->needles[2][0]);
- if (N_SCALE_NEEDLES > 3)
- extract_site (duster, duster->output, dst_x, dst_y, 0.8, &probe->needles[3][0]);
- if (N_SCALE_NEEDLES > 4)
- extract_site (duster, duster->output, dst_x, dst_y, 1.2, &probe->needles[4][0]);
- if (N_SCALE_NEEDLES > 5)
- extract_site (duster, duster->output, dst_x, dst_y, 0.66, &probe->needles[5][0]);
- if (N_SCALE_NEEDLES > 6)
- extract_site (duster, duster->output, dst_x, dst_y, 1.5, &probe->needles[6][0]);
-
+ probe_prep (duster, probe);
g_hash_table_foreach (duster->ht[0], compare_needle, ptr);
-
-
- probe->age++;
-
- if (probe->score == old_score)
- return -1;
+ probe_post_search (duster, probe);
return 0;
}
-#if 0
-static inline int probes_improve (PixelDuster *duster)
+static inline void compare_probes (gpointer key, gpointer value, gpointer data)
{
- int ret = -1;
+ void **ptr = data;
+ PixelDuster *duster = ptr[0];
+ Probe **probes = ptr[1];
+ int n_probes = GPOINTER_TO_INT (ptr[2]);
+ gfloat *hay = value;
+ gint offset = GPOINTER_TO_INT (key);
+ gint x = offset % 65536;
+ gint y = offset / 65536;
- for (GList *p= g_hash_table_get_values (duster->probes_ht); p; p= p->next)
+ for (int p = 0; p < n_probes; p++)
+ if (probes[p])
{
- Probe *probe = p->data;
- probe_improve (duster, probe);
- if (ret == 0)
- ret = 0;
+ Probe *probe = probes[p];
+ if (probe)
+ probe_compare_hay (duster, probe, hay, x, y);
}
- return ret;
}
+
+
+static int probes_improve (PixelDuster *duster,
+ Probe **probes,
+ int n_probes)
+{
+#ifdef BATCH_PROBES
+ void *ptr[3] = {duster, probes, GINT_TO_POINTER (n_probes)};
+
+ for (int i = 0; i < n_probes; i++)
+ {
+ Probe *probe = probes[i];
+
+ if (probe->age >= duster->max_age)
+ {
+ g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
+ probes[i] = NULL;
+ }
+ else
+ {
+ probe_prep (duster, probe);
+ }
+ }
+ g_hash_table_foreach (duster->ht[0], compare_probes, ptr);
+
+ for (int i = 0; i < n_probes; i++)
+ {
+ if (probes[i])
+ probe_post_search (duster, probes[i]);
+ }
+#else
+ for (int i = 0; i < n_probes; i++)
+ {
+ if (probes[i])
+ probe_improve (duster, probes[i]);
+ }
#endif
+ return 0;
+}
static inline void pixel_duster_add_probes_for_transparent (PixelDuster *duster)
{
@@ -653,16 +706,22 @@ static inline void pixel_duster_add_probes_for_transparent (PixelDuster *duster)
static inline void pixel_duster_fill (PixelDuster *duster)
{
- const Babl *format = babl_format ("RGBA float");
gint missing = 1;
gint total = 0;
gint runs = 0;
while ( ((missing >0) /* && (missing != old_missing) */) ||
(runs < duster->minimum_iterations))
- { runs++;
+ {
+#ifdef BATCH_PROBES
+ Probe *probes[BATCH_PROBES];
+ int n_probes = 0;
+#endif
+
+ runs++;
total = 0;
missing = 0;
+
for (GList *p= g_hash_table_get_values (duster->probes_ht); p; p= p->next)
{
Probe *probe = p->data;
@@ -685,47 +744,37 @@ static inline void pixel_duster_fill (PixelDuster *duster)
try_replace = 0;
#endif
-
if (probe->score == INITIAL_SCORE || try_replace)
{
-
if ((rand()%100)/100.0 < duster->try_chance &&
probe_neighbors (duster, duster->output, probe, duster->minimum_neighbors) >=
duster->minimum_neighbors)
{
- if (probe_improve (duster, probe) == 0)
- {
- gfloat sum_rgba[4]={0.0,0.0,0.0,0.0};
- gfloat rgba[4];
-
- if (probe->k>1)
- {
- for (gint i = 0; i < probe->k; i++)
- {
- gegl_sampler_get (duster->in_sampler_f, probe->source_x[i], probe->source_y[i],
- NULL, &rgba[0], 0);
- for (gint c = 0; c < 4; c++)
- sum_rgba[c] += rgba[c];
- }
- for (gint c = 0; c < 4; c++)
- rgba[c] = sum_rgba[c] / probe->k;
- }
- else
- {
- gegl_sampler_get (duster->in_sampler_f, probe->source_x[0], probe->source_y[0], NULL, &rgba[0],
0);
- }
-
- gegl_buffer_set (duster->output, GEGL_RECTANGLE(probe->target_x, probe->target_y, 1, 1), 0,
format, &rgba[0], 0);
- }
+#ifdef BATCH_PROBES
+ probes[n_probes++] = probe;
+#else
+ probe_improve (duster, probe);
+#endif
}
}
+#ifdef BATCH_PROBES
+ if (n_probes>=BATCH_PROBES)
+ {
+ probes_improve (duster, probes, n_probes);
+ n_probes = 0;
+ }
+#endif
}
+#ifdef BATCH_PROBES
+ if (n_probes)
+ probes_improve (duster, probes, n_probes);
+#endif
+
if (duster->op)
- gegl_operation_progress (duster->op, (total-missing) * 1.0 / total,
+ gegl_operation_progress (duster->op, 0.2 + (total-missing) * 0.8 / 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
}
@@ -747,10 +796,19 @@ static void seed_db (PixelDuster *duster)
for (gint x = duster->min_x - duster->seek_radius;
x < duster->max_x + duster->seek_radius; x++)
{
- ensure_hay (duster, x, y, -1);
+ ensure_hay (duster, x, y);
}
+
+
if (y % 13 == 0)
{
+ if (duster->op)
+ gegl_operation_progress (duster->op,
+
+ (y - duster->min_y + duster->seek_radius) * 0.2 / (duster->seek_radius * 2 +
duster->max_y-duster->min_y),
+ "generating neighborhood db");
+
+
fprintf (stderr, "\rdb seeding %s (%.2f%%)", y%4==0?"-":y%4==1?"/":y%4==2?"\\":"|",
(y - duster->min_y + duster->seek_radius) * 100.0 / (duster->seek_radius * 2 +
duster->max_y-duster->min_y));
}
@@ -763,9 +821,8 @@ static void seed_db (PixelDuster *duster)
for (gint y = 0; y < duster->in_rect.height; y++)
for (gint x = 0; x < duster->in_rect.width; x++)
{
- ensure_hay (duster, x, y, -1);
+ ensure_hay (duster, x, y);
}
fprintf (stderr, "ed\n");
}
-
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]