[gegl] quite ok enlarge
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] quite ok enlarge
- Date: Fri, 28 Jun 2019 13:55:19 +0000 (UTC)
commit 9dce5e6df53f110228a55d9852e4eddcc1460d78
Author: Øyvind Kolås <pippin gimp org>
Date: Wed Jun 26 15:43:42 2019 +0200
quite ok enlarge
operations/workshop/enlarge.c | 15 +++-
operations/workshop/inpaint.c | 20 +++--
operations/workshop/pixel-duster.h | 153 ++++++++++++++++++++++++-------------
3 files changed, 125 insertions(+), 63 deletions(-)
---
diff --git a/operations/workshop/enlarge.c b/operations/workshop/enlarge.c
index f9cb587c8..7695d81a8 100644
--- a/operations/workshop/enlarge.c
+++ b/operations/workshop/enlarge.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
- * Copyright 2018 Øyvind Kolås <pippin gimp org>
+ * Copyright 2018, 2019 Øyvind Kolås <pippin gimp org>
*
*/
@@ -112,7 +112,7 @@ static void improve (PixelDuster *duster,
{
Probe *probe;
probe = add_probe (duster, x, y);
- if (probe_improve (duster, probe) == 0)
+ if (probes_improve (duster) == 0)
{
#if PIXDUST_REL_DIGEST==0
gfloat rgba[4*MAX_K];
@@ -166,6 +166,9 @@ static void improve (PixelDuster *duster,
fprintf (stderr, "\n");
}
+// rgba x y scale score
+//
+
static gboolean
process (GeglOperation *operation,
GeglBuffer *input,
@@ -177,17 +180,21 @@ process (GeglOperation *operation,
GeglRectangle in_rect = *gegl_buffer_get_extent (input);
GeglRectangle out_rect = *gegl_buffer_get_extent (output);
PixelDuster *duster;
- duster = pixel_duster_new (input, output,
+ duster = pixel_duster_new (input, input, output,
&in_rect, &out_rect,
o->seek_distance,
o->max_k,
- 1, 1, 1.0, 0.3,
+ 1, // min neighbors
+ 1, // min iterations
+ 0.8, // try chance
+ 0.2, // re-try chance
o->scale,
o->scale,
NULL);
scaled_copy (duster, input, output, o->scale);
seed_db (duster);
improve (duster, input, output, o->scale);
+ improve (duster, input, output, o->scale);
pixel_duster_destroy (duster);
return TRUE;
diff --git a/operations/workshop/inpaint.c b/operations/workshop/inpaint.c
index 26a860665..8ba8b3446 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -21,21 +21,24 @@
#include "config.h"
#include <glib/gi18n-lib.h>
+//retire propes after given set of completed re-runs
+
+
#ifdef GEGL_PROPERTIES
property_int (seek_distance, "seek radius", 128)
value_range (4, 512)
-property_int (min_neigh, "min neigh", 2)
- value_range (1, 10)
+property_int (min_neigh, "min neigh", 3)
+ value_range (3, 10)
-property_int (min_iter, "min iter", 4)
+property_int (min_iter, "min iter", 20)
value_range (1, 512)
-property_double (chance_try, "try chance", 0.88)
+property_double (chance_try, "try chance", 0.5)
value_range (0.0, 1.0)
-property_double (chance_retry, "retry chance", 0.5)
+property_double (chance_retry, "retry chance", 0.6)
value_range (0.0, 1.0)
#else
@@ -79,7 +82,7 @@ process (GeglOperation *operation,
GeglProperties *o = GEGL_PROPERTIES (operation);
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,
+ PixelDuster *duster = pixel_duster_new (input, input, output, &in_rect, &out_rect,
o->seek_distance,
1,
o->min_neigh,
@@ -125,9 +128,10 @@ operation_process (GeglOperation *operation,
gegl_operation_source_get_bounding_box (operation, "input");
operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class);
+fprintf (stderr, "a\n");
// XXX: hack to force nop, many people are enabling as many things as possible when configuring gegl not
realising that they shouldn't enable the workshop
- if (TRUE || (in_rect && gegl_rectangle_is_infinite_plane (in_rect)))
+ 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",
@@ -160,7 +164,7 @@ gegl_op_class_init (GeglOpClass *klass)
"name", "gegl:alpha-inpaint",
"title", "Heal transparent",
"categories", "heal",
- "description", "Replaces fully transparent pixels with good candidate pixels found in the
neighbourhood of the hole",
+ "description", "Replaces fully transparent pixels with good candidate pixels found in the whole image",
NULL);
}
diff --git a/operations/workshop/pixel-duster.h b/operations/workshop/pixel-duster.h
index da8f82850..18ff6eb5d 100644
--- a/operations/workshop/pixel-duster.h
+++ b/operations/workshop/pixel-duster.h
@@ -1,9 +1,24 @@
+//if 0
/* pixel-duster
*
* the pixel duster data structures and functions are used by multiple ops,
* but kept in one place since they share so much implementation
*
- * a context aware pixel inpainting algorithm
+ * a context aware pixel inpainting framework..
+
+ avoid building a database of puzzle pieces - since the puzzle pieces are
+ pixels samples we condense search space by rectifying rotation - only keep a
+ cache.
+
+ (the puzzle pieces are stored by prefix match in a large continuous
+ memory region,)
+
+ seed database with used spots and immediate neighbors, for faster
+ subsequent lookup
+
+ keep bloom filter - or perhaps even bitmap in GeglBuffer!! for knowing
+ contained in db or not.
+
* 2018 (c) Øyvind Kolås pippin gimp org
*/
@@ -24,7 +39,8 @@
thus permitting a wider range of neighborhoods to produce valid data - thus
will be good at least for superresolution
- add more symmetries mirroring each doubling data
+ add more symmetries mirroring each doubling data - add full rotation
+ invariance
*/
#define POW2(x) ((x)*(x))
@@ -34,6 +50,7 @@
typedef struct
{
GeglOperation *op;
+ GeglBuffer *reference;
GeglBuffer *input;
GeglBuffer *output;
GeglRectangle in_rect;
@@ -54,25 +71,28 @@ typedef struct
GHashTable *probes_ht;
- int order[512][3];
+ float order[512][3];
} PixelDuster;
-#define MAX_K 4
+#define MAX_K 2
#define PIXDUST_REL_DIGEST 0
#define NEIGHBORHOOD 23
#define PIXDUST_ORDERED 0
-#define MAX_DIR 4
+#define MAX_DIR 1
//#define ONLY_DIR 1
typedef struct Probe {
int target_x;
int target_y;
+ /* the only real datamembers are above should be float*/
+
int age;
int k;
- int score;
+ float score;
int k_score[MAX_K];
+ /* should store sampled coordinates instead */
int source_x[MAX_K];
int source_y[MAX_K];
guchar *hay[MAX_K];
@@ -85,6 +105,11 @@ typedef struct Probe {
/* when going through the image preparing the index - only look at the subset
* needed pixels - and later when fetching out hashed pixels - investigate
* these ones in particular. would only be win for limited inpainting..
+ *
+ * making the pixel duster scale invariant on a subpixel level would be neat
+ * especially for supersampling, taking the reverse jacobian into account
+ * would be even neater.
+ *
*/
@@ -131,7 +156,7 @@ static void init_order(PixelDuster *duster)
duster->order[0][0] = 0;
duster->order[0][1] = 0;
- duster->order[0][2] = 1;
+ duster->order[0][2] = 1.0;
for (i = 1; i < 159; i++)
for (y = -7; y <= 7; y ++)
@@ -141,7 +166,7 @@ static void init_order(PixelDuster *duster)
{
duster->order[i][0] = y;
duster->order[i][1] = x;
- duster->order[i][2] = POW2(x)+POW2(y);
+ duster->order[i][2] = 1.0;//POW2(x)+POW2(y);
}
}
}
@@ -188,7 +213,8 @@ static void duster_idx_to_x_y (PixelDuster *duster, int index, int dir, int *x,
}
-static PixelDuster * pixel_duster_new (GeglBuffer *input,
+static PixelDuster * pixel_duster_new (GeglBuffer *reference,
+ GeglBuffer *input,
GeglBuffer *output,
const GeglRectangle *in_rect,
const GeglRectangle *out_rect,
@@ -203,6 +229,7 @@ static PixelDuster * pixel_duster_new (GeglBuffer *input,
GeglOperation *op)
{
PixelDuster *ret = g_malloc0 (sizeof (PixelDuster));
+ ret->reference = reference;
ret->input = input;
ret->output = output;
ret->seek_radius = seek_radius;
@@ -220,13 +247,13 @@ static PixelDuster * pixel_duster_new (GeglBuffer *input,
ret->scale_y = scale_y;
ret->in_sampler_yu8 = gegl_buffer_sampler_new (input, babl_format ("Y'aA u8"),
- GEGL_SAMPLER_NEAREST);
+ GEGL_SAMPLER_CUBIC);
ret->in_sampler_u8 = gegl_buffer_sampler_new (input,
babl_format ("R'G'B'A u8"),
- GEGL_SAMPLER_NEAREST);
+ GEGL_SAMPLER_CUBIC);
ret->in_sampler_f = gegl_buffer_sampler_new (input,
babl_format ("RGBA float"),
- GEGL_SAMPLER_NEAREST);
+ GEGL_SAMPLER_CUBIC);
for (int i = 0; i < 4096; i++)
ret->ht[i] = 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);
@@ -264,7 +291,10 @@ static void pixel_duster_destroy (PixelDuster *duster)
}
-static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y, guchar *dst)
+/* extend with scale factor/matrix
+ *
+ */
+static void extract_site (PixelDuster *duster, GeglBuffer *input, double x, double y, float scale, guchar
*dst)
{
static const Babl *format = NULL;
guchar lum[8];
@@ -280,10 +310,10 @@ static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y,
/* figure out which of the up/down/left/right pixels are brightest,
using premultiplied alpha - do punish blank spots */
- gegl_sampler_get (duster->in_sampler_yu8, x + 1, y + 0, NULL, &lum[0], 0);
- gegl_sampler_get (duster->in_sampler_yu8, x - 1, y + 0, NULL, &lum[2], 0);
- gegl_sampler_get (duster->in_sampler_yu8, x + 0, y + 1, NULL, &lum[4], 0);
- gegl_sampler_get (duster->in_sampler_yu8, x + 0, y - 1, NULL, &lum[6], 0);
+ gegl_sampler_get (duster->in_sampler_yu8, x + 1 *scale, y + 0, NULL, &lum[0], 0);
+ gegl_sampler_get (duster->in_sampler_yu8, x - 1 *scale, y + 0, NULL, &lum[2], 0);
+ gegl_sampler_get (duster->in_sampler_yu8, x + 0, y + 1 * scale, NULL, &lum[4], 0);
+ gegl_sampler_get (duster->in_sampler_yu8, x + 0, y - 1 * scale, NULL, &lum[6], 0);
bdir = 0;
@@ -312,12 +342,11 @@ static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y,
#endif
#if PIXDUST_REL_DIGEST==0
-
for (int i = 0; i <= NEIGHBORHOOD; i++)
{
int dx, dy;
duster_idx_to_x_y (duster, i, bdir, &dx, &dy);
- gegl_sampler_get (duster->in_sampler_u8, x + dx, y + dy, NULL, &dst[i*4], 0);
+ gegl_sampler_get (duster->in_sampler_u8, x + dx * scale, y + dy * scale, NULL, &dst[i*4], 0);
{
int hist_r = dst[i*4+0]/80;
int hist_g = dst[i*4+1]/80;
@@ -335,7 +364,7 @@ static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y,
{
int dx, dy;
duster_idx_to_x_y (duster, i, bdir, &dx, &dy);
- gegl_sampler_get (duster->in_sampler_u8, x + dx, y + dy, NULL, &dst[i*4], 0);
+ gegl_sampler_get (duster->in_sampler_u8, x + dx * scale, y + dy * scale, NULL, &dst[i*4], 0);
if (i==0)
for (int j = 0; j < 3; j++)
@@ -357,14 +386,14 @@ static inline int u8_rgb_diff (guchar *a, guchar *b)
return POW2(a[0]-b[0]) * 2 + POW2(a[1]-b[1]) * 3 + POW2(a[2]-b[2]);
}
-static int inline
+static float inline
score_site (PixelDuster *duster,
guchar *needle,
guchar *hay,
- int bail)
+ float bail)
{
int i;
- int score = 0;
+ float score = 0;
/* bail early with really bad score - the target site doesnt have opacity */
if (hay[3] < 2)
@@ -372,6 +401,7 @@ score_site (PixelDuster *duster,
return INITIAL_SCORE;
}
+#if 0
{
uint64_t *needle_hist = (void*)&needle[NEIGHBORHOOD * 4];
uint64_t *hay_hist = (void*)&hay[NEIGHBORHOOD * 4];
@@ -382,24 +412,20 @@ score_site (PixelDuster *duster,
if (diff_hist & (1 << i)) missing ++;
//else if ( *needle_hist & (i<<i)) missing ++;
}
- if (missing > 32)
+ if (missing > 23)
return INITIAL_SCORE;
}
+#endif
for (i = 1; i < NEIGHBORHOOD && score < bail; i++)
{
if (needle[i*4 + 3] && hay[i*4 + 3])
{
- score += u8_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * 10 / duster->order[i][2];
+ score += u8_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * duster->order[i][2];
}
else
{
- /* we score missing cells as if it is a big diff */
-#if PIXDUST_REL_DIGEST==0
- score += ((POW2(1))*3) * 40 / duster->order[i][2];
-#else
- score += ((POW2(3))*3) * 40 / duster->order[i][2];
-#endif
+ score += 256 * duster->order[i][2];
}
}
return score;
@@ -411,8 +437,8 @@ 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[0] = 0;//target_x / duster->scale_x;
- probe->source_y[0] = 0;//target_y / duster->scale_y;
+ probe->source_x[0] = target_x / duster->scale_x;
+ probe->source_y[0] = target_y / duster->scale_y;
probe->k_score[0] = INITIAL_SCORE;
probe->k = 0;
probe->score = INITIAL_SCORE;
@@ -450,8 +476,8 @@ probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
if (probe_rel_is_set (duster, output, probe, 0, 1)) found ++;
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, 0, -1)) found ++;
+#if 1
if (found >=min) return found;
-#if 0
if (probe_rel_is_set (duster, output, probe, 1, 1)) found ++;
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, -1,-1)) found ++;
@@ -459,6 +485,8 @@ probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
if (probe_rel_is_set (duster, output, probe, 1,-1)) found ++;
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, -1, 1)) found ++;
+#endif
+#if 0
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, 2, 0)) found ++;
if (found >=min) return found;
@@ -582,7 +610,7 @@ static guchar *ensure_hay (PixelDuster *duster, int x, int y, int subset)
if (!hay)
{
hay = g_malloc (4 * NEIGHBORHOOD + 8);
- extract_site (duster, duster->input, x, y, hay);
+ extract_site (duster, duster->input, x, y, 1.0, hay);
if (subset < 0)
{
subset = site_subset (hay);
@@ -592,6 +620,7 @@ static guchar *ensure_hay (PixelDuster *duster, int x, int y, int subset)
return NULL;
}
}
+ subset = 0;
{
#if 0
gint found_count = 0;
@@ -612,7 +641,7 @@ static guchar *ensure_hay (PixelDuster *duster, int x, int y, int subset)
return hay;
}
-
+/* XXX : replace with compare_needles */
static void compare_needle (gpointer key, gpointer value, gpointer data)
{
void **ptr = data;
@@ -623,7 +652,7 @@ static void compare_needle (gpointer key, gpointer value, gpointer data)
gint offset = GPOINTER_TO_INT (key);
gint x = offset % 65536;
gint y = offset / 65536;
- int score;
+ float score;
#if 0
#define pow2(a) ((a)*(a))
@@ -642,7 +671,7 @@ static void compare_needle (gpointer key, gpointer value, gpointer data)
score = score_site (duster, &needle[0], hay, probe->score);
- if (score <= probe->score)
+ if (score < probe->score)
{
int j;
for (j = duster->max_k-1; j >= 1; j --)
@@ -669,7 +698,7 @@ static int probe_improve (PixelDuster *duster,
gint dst_x = probe->target_x;
gint dst_y = probe->target_y;
void *ptr[3] = {duster, probe, &needle[0]};
- int old_score = probe->score;
+ float old_score = probe->score;
static const Babl *format = NULL;
int set_start[3];
int set_end[3];
@@ -677,9 +706,11 @@ static int probe_improve (PixelDuster *duster,
if (!format)
format = babl_format ("RGBA float");
- extract_site (duster, duster->output, dst_x, dst_y, &needle[0]);
- site_subset2 (&needle[0], set_start, set_end);
+ extract_site (duster, duster->output, dst_x, dst_y, 1.0, &needle[0]);
+ //site_subset2 (&needle[0], set_start, set_end);
+ g_hash_table_foreach (duster->ht[0], compare_needle, ptr);
+#if 0
if (set_end[0] == set_start[0] &&
set_end[1] == set_start[1] &&
set_end[2] == set_start[2])
@@ -706,9 +737,9 @@ static int probe_improve (PixelDuster *duster,
g_hash_table_foreach (duster->ht[subset], compare_needle, ptr);
}
}
+#endif
+ probe->age++;
- if (probe->score == old_score)
- return -1;
#if 0
spread_relative (duster, probe, -1, -1);
spread_relative (duster, probe, -1, 0);
@@ -716,16 +747,32 @@ static int probe_improve (PixelDuster *duster,
spread_relative (duster, probe, 1, 0);
spread_relative (duster, probe, 0, 1);
#endif
- probe->age++;
- if (probe->age > 15)
+ if (probe->age > 6)
{
g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
}
+ if (probe->score == old_score)
+ return -1;
return 0;
}
+static inline int probes_improve (PixelDuster *duster)
+{
+ int ret = -1;
+
+ for (GList *p= g_hash_table_get_values (duster->probes_ht); p; p= p->next)
+ {
+ Probe *probe = p->data;
+ probe_improve (duster, probe);
+ if (ret == 0)
+ ret = 0;
+ }
+ return ret;
+}
+
+
static inline void pixel_duster_add_probes_for_transparent (PixelDuster *duster)
{
const Babl *format = babl_format ("RGBA float");
@@ -770,7 +817,8 @@ static inline void pixel_duster_fill (PixelDuster *duster)
gint total = 0;
gint runs = 0;
- while ( (missing >0 && missing != old_missing) || runs < duster->minimum_iterations)
+ while ( ((missing >0) && (missing != old_missing)) ||
+ (runs < duster->minimum_iterations))
{ runs++;
total = 0;
old_missing = missing;
@@ -790,19 +838,20 @@ static inline void pixel_duster_fill (PixelDuster *duster)
try_replace = ((rand()%100)/100.0) < duster->retry_chance;
}
total ++;
+ if ((probe->source_x[0] == probe->target_x &&
+ probe->source_y[0] == probe->target_y))
+ try_replace = 0;
if (probe->score == INITIAL_SCORE || try_replace)
{
- if ((probe->source_x[0] == probe->target_x &&
- probe->source_y[0] == probe->target_y))
- try_replace = 0;
if ((rand()%100)/100.0 < duster->try_chance &&
probe_neighbors (duster, duster->output, probe, duster->minimum_neighbors) >=
duster->minimum_neighbors)
{
- if(try_replace)
- probe->score = INITIAL_SCORE;
+ //if(try_replace)
+ //probe->score = INITIAL_SCORE;
+
if (probe_improve (duster, probe) == 0)
{
gfloat sum_rgba[4]={0.0,0.0,0.0,0.0};
@@ -828,6 +877,8 @@ static inline void pixel_duster_fill (PixelDuster *duster)
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
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]