[gegl] workshop: implement rotational invariance for inpainting neighborhoods
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] workshop: implement rotational invariance for inpainting neighborhoods
- Date: Fri, 28 Jun 2019 14:03:30 +0000 (UTC)
commit a7630491f29be479c70148c7f8346d0f2df11998
Author: Øyvind Kolås <pippin gimp org>
Date: Fri Jun 28 16:02:36 2019 +0200
workshop: implement rotational invariance for inpainting neighborhoods
operations/common/Makefile.am | 1 +
operations/workshop/Makefile.am | 1 -
operations/workshop/enlarge.c | 358 -------------------------------------
operations/workshop/inpaint.c | 6 +-
operations/workshop/pixel-duster.h | 202 +++++++--------------
5 files changed, 64 insertions(+), 504 deletions(-)
---
diff --git a/operations/common/Makefile.am b/operations/common/Makefile.am
index 924ceca24..95e43430f 100644
--- a/operations/common/Makefile.am
+++ b/operations/common/Makefile.am
@@ -101,6 +101,7 @@ gegl_common_la_SOURCES =\
remap.c \
rgb-clip.c \
saturation.c \
+ saturation2.c \
save.c \
sepia.c \
slic.c \
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index f9513a12c..60ee21296 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -20,7 +20,6 @@ ops = \
gradient-map.la \
gcr.la \
hstack.la \
- enlarge.la \
aces-rrt.la \
inpaint.la \
integral-image.la \
diff --git a/operations/workshop/inpaint.c b/operations/workshop/inpaint.c
index 8700430f3..d65a49ec5 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -29,16 +29,16 @@
property_int (seek_distance, "seek radius", 30)
value_range (4, 512)
-property_int (min_neigh, "min neigh", 4)
+property_int (min_neigh, "min neigh", 2)
value_range (1, 10)
property_int (min_iter, "min iter", 100)
value_range (1, 512)
-property_double (chance_try, "try chance", 1.0)
+property_double (chance_try, "try chance", 0.5)
value_range (0.0, 1.0)
-property_double (chance_retry, "retry chance", 0.75)
+property_double (chance_retry, "retry chance", 0.4)
value_range (0.0, 1.0)
#else
diff --git a/operations/workshop/pixel-duster.h b/operations/workshop/pixel-duster.h
index 9fad400df..4cfb5b190 100644
--- a/operations/workshop/pixel-duster.h
+++ b/operations/workshop/pixel-duster.h
@@ -88,21 +88,13 @@ typedef struct
#define MAX_K 4
#define RINGS 3
-#define RAYS 16
-#define GAP 1.1
-#define RINGGAMMA 1.45
-#define TWIST 0.03
-
+#define IMPROVEMENT_ITERATIONS 2
+#define RAYS 12
+#define GAP 1.3
+#define RINGGAMMA 1.2
+#define TWIST 0.0
#define NEIGHBORHOOD (RINGS*RAYS+1)
-#define MAX_DIR 4
-
-// safe to leave always on since only really used when epplies
-#define PIXDUST_DIR_INVARIANT 1
-
-
-//#define ONLY_DIR 1
-
typedef struct Probe {
int target_x;
int target_y;
@@ -143,15 +135,15 @@ static void init_order(PixelDuster *duster)
i = 1;
{
- for (float angleno = 0; angleno < RAYS; angleno++)
for (int circleno = 0; circleno < RINGS; circleno++)
+ for (float angleno = 0; angleno < RAYS; angleno++)
{
float mag = pow(GAP * (circleno + 1), RINGGAMMA);
float x = cosf ((angleno / RAYS + TWIST*circleno) * M_PI * 2) * mag;
float y = sinf ((angleno / RAYS + TWIST*circleno) * M_PI * 2) * mag;
duster->order[i][0] = x;
duster->order[i][1] = y;
- duster->order[i][2] = powf (1.0 / (POW2(x)+POW2(y)), 0.8);
+ duster->order[i][2] = powf (1.0 / (POW2(x)+POW2(y)), 1.0);
i++;
}
}
@@ -170,45 +162,10 @@ static void init_order(PixelDuster *duster)
#endif
}
-static void duster_idx_to_x_y (PixelDuster *duster, int index, int dir, int *x, int *y)
+static void duster_idx_to_x_y (PixelDuster *duster, int index, int *x, int *y)
{
- switch (dir)
- {
- default:
- case 0: /* right */
- *x = -duster->order[index][0];
- *y = -duster->order[index][1];
- break;
- case 1: /* left */
- *x = duster->order[index][0];
- *y = duster->order[index][1];
- break;
- case 2: /* down */
- *x = -duster->order[index][1];
- *y = -duster->order[index][0];
- break;
- case 3: /* up */
- *x = duster->order[index][1];
- *y = duster->order[index][0];
- break;
-
- case 4: /* right */
- *x = -duster->order[index][0];
- *y = duster->order[index][1];
- break;
- case 5: /* left */
- *x = duster->order[index][0];
- *y = -duster->order[index][1];
- break;
- case 6: /* down */
- *x = -duster->order[index][1];
- *y = duster->order[index][0];
- break;
- case 7: /* up */
- *x = duster->order[index][1];
- *y = -duster->order[index][0];
- break;
- }
+ *x = duster->order[index][0];
+ *y = duster->order[index][1];
}
@@ -241,7 +198,7 @@ static PixelDuster * pixel_duster_new (GeglBuffer *reference,
ret->max_y = 0;
ret->min_x = 10000;
ret->min_y = 10000;
- ret->max_age = 5;
+ ret->max_age = IMPROVEMENT_ITERATIONS;
if (max_k < 1) max_k = 1;
if (max_k > MAX_K) max_k = MAX_K;
@@ -316,9 +273,6 @@ void gegl_sampler_prepare (GeglSampler *sampler);
static void extract_site (PixelDuster *duster, GeglBuffer *buffer, double x, double y, float scale, gfloat
*dst)
{
static const Babl *format = NULL;
- guchar lum[8];
- int bdir, maxlum;
- //uint64_t hist3dmask=0;
GeglSampler *sampler_yu8;
GeglSampler *sampler_f;
@@ -333,75 +287,62 @@ static void extract_site (PixelDuster *duster, GeglBuffer *buffer, double x, dou
else if (buffer == duster->reference)
{
sampler_yu8 = duster->ref_sampler_yu8;
- sampler_f = duster->ref_sampler_f;
+ sampler_f = duster->ref_sampler_f;
}
else if (buffer == duster->input)
{
sampler_yu8 = duster->in_sampler_yu8;
- sampler_f = duster->in_sampler_f;
+ sampler_f = duster->in_sampler_f;
}
if (!format){
format = babl_format ("RGBA float");
}
-#if PIXDUST_DIR_INVARIANT==1
- /* figure out which of the up/down/left/right pixels are brightest,
- using premultiplied alpha - do punish blank spots */
-
- gegl_sampler_get (sampler_yu8, x + 1 *scale, y + 0, NULL, &lum[0], 0);
- gegl_sampler_get (sampler_yu8, x - 1 *scale, y + 0, NULL, &lum[2], 0);
- gegl_sampler_get (sampler_yu8, x + 0, y + 1 * scale, NULL, &lum[4], 0);
- gegl_sampler_get (sampler_yu8, x + 0, y - 1 * scale, NULL, &lum[6], 0);
-
- bdir = 0;
-
- maxlum = lum[0*2];
- for (int i = 1; i < MIN(4,MAX_DIR); i++)
- if (lum[i*2] > maxlum)
- {
- bdir = i;
- maxlum = lum[i*2];
- }
-
- if (MAX_DIR > 4)
- {
- switch (bdir)
- {
- case 0: if (lum[4] > lum[6]) bdir += 4; break;
- case 1: if (lum[6] > lum[4]) bdir += 4; break;
- case 2: if (lum[0] > lum[2]) bdir += 4; break;
- case 3: if (lum[2] > lum[0]) bdir += 4; break;
- }
- }
-
-#ifdef ONLY_DIR
- bdir = ONLY_DIR;
-#endif
-#endif
-
#if 1
for (int i = 0; i <= NEIGHBORHOOD; i++)
{
int dx, dy;
- duster_idx_to_x_y (duster, i, bdir, &dx, &dy);
+ duster_idx_to_x_y (duster, i, &dx, &dy);
gegl_sampler_get (sampler_f, x + dx * scale, y + dy * scale, NULL, &dst[i*4], 0);
-#if 0
+ }
+
+ {
+ int warmest_ray = 0;
+ float warmest_ray_energy = 0;
+ gfloat tmp[4 * NEIGHBORHOOD + 8];
+
+ for (int ray = 0; ray < RAYS; ray ++)
{
- int hist_r = dst[i*4+0]/80;
- int hist_g = dst[i*4+1]/80;
- int hist_b = dst[i*4+2]/80;
- int hist_bit = hist_r * 4 * 4 + hist_g * 4 + hist_b;
- hist3dmask |= (1 << hist_bit);
+ float energy = 0.0;
+ for (int circle = 0; circle < RINGS; circle++)
+ for (int c = 0; c < 3; c++)
+ energy += dst[ ( circle * RAYS + ray )*4 + c];
+ if (energy > warmest_ray_energy)
+ {
+ warmest_ray = ray;
+ warmest_ray_energy = energy;
+ }
+ }
+
+ if (warmest_ray)
+ {
+ for (int i = 0; i <= NEIGHBORHOOD*4; i++)
+ tmp[i] = dst[i];
+
+ for (int ray = 0; ray < RAYS; ray ++)
+ {
+ int swapped_ray = ray + warmest_ray_energy;
+ if (swapped_ray >= RAYS) swapped_ray -= RAYS;
+
+ for (int circle = 0; circle < RINGS; circle++)
+ for (int c = 0; c < 4; c++)
+ dst[ ( circle * RAYS + ray )*4 + c] =
+ tmp[ ( circle * RAYS + swapped_ray )*4 + c];
+ }
}
-#endif
}
- dst[0] = bdir;
-#if 0
- *((uint64_t*)(&dst[4*NEIGHBORHOOD])) = hist3dmask;
-#endif
#endif
-
}
static inline int u8_rgb_diff (guchar *a, guchar *b)
@@ -430,33 +371,16 @@ 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];
- uint64_t diff_hist = *needle_hist ^ *hay_hist;
- int missing = 0;
- for (i = 0; i < 64; i ++)
- {
- if ((diff_hist & (1 << i)) &&
- (*needle_hist & ( 1 <<i)))
- missing ++;
- //else if ( *needle_hist & (i<<i)) missing ++;
- }
- if (missing > 23)
- return INITIAL_SCORE;
- }
-#endif
-
- for (i = 1; i < NEIGHBORHOOD && score < bail; i++)
+ for (i = 0; i < NEIGHBORHOOD && score < bail; i++)
{
- if (needle[i*4 + 3]>0.001 && hay[i*4 + 3]>0.001)
+ if (needle[i*4 + 3]<1.0 && hay[i*4 + 3]>0.001)
{
score += f_rgb_diff (&needle[i*4 + 0], &hay[i*4 + 0]) * duster->order[i][2];
}
else
{
- score += 10;//256;// * duster->order[i][2];
+ /* transparent hay or needle - give bad score */
+ score += 5;
}
}
return score;
@@ -707,6 +631,12 @@ static int probe_improve (PixelDuster *duster,
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));
+ return -1;
+ }
+
if (!format)
format = babl_format ("RGBA float");
@@ -721,18 +651,6 @@ static int probe_improve (PixelDuster *duster,
probe->age++;
-#if 0
- 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);
-#endif
-
- if (probe->age > duster->max_age)
- {
- g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
- }
if (probe->score == old_score)
return -1;
@@ -830,8 +748,8 @@ static inline void pixel_duster_fill (PixelDuster *duster)
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)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]