[gegl] pixel-duster: make more configurable with ifdefs
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] pixel-duster: make more configurable with ifdefs
- Date: Sat, 3 Mar 2018 16:39:14 +0000 (UTC)
commit 1a25b6a307b8ec7c9a9ca43a153c3e3f93352881
Author: Øyvind Kolås <pippin gimp org>
Date: Sun Feb 25 22:17:51 2018 +0100
pixel-duster: make more configurable with ifdefs
Adds support for more symmetries, unused experimental relative neighborhood
code and more.
operations/workshop/Makefile.am | 1 +
operations/workshop/enlarge.c | 55 +++++--
operations/workshop/enlarge2.c | 239 +++++++++++++++++++++++++++
operations/workshop/inpaint.c | 4 +-
operations/workshop/pixel-duster.h | 310 +++++++++++++++++++++++++++---------
5 files changed, 518 insertions(+), 91 deletions(-)
---
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index f6b4f8d..bc13f77 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -20,6 +20,7 @@ op_LTLIBRARIES = \
gradient-map.la \
hstack.la \
enlarge.la \
+ enlarge2.la \
inpaint.la \
integral-image.la \
linear-sinusoid.la \
diff --git a/operations/workshop/enlarge.c b/operations/workshop/enlarge.c
index f8a3f89..c7eb59f 100644
--- a/operations/workshop/enlarge.c
+++ b/operations/workshop/enlarge.c
@@ -77,19 +77,18 @@ static void scaled_copy (GeglBuffer *in,
GeglRectangle r = {x, y, 1, 1};
gegl_buffer_sample (in, x / scale, y / scale, NULL,
&rgba[0], format,
- GEGL_SAMPLER_NOHALO, 0);
+ GEGL_SAMPLER_NEAREST, 0);
gegl_buffer_set (out, &r, 0, format, &rgba[0], 0);
}
}
-
static void improve (PixelDuster *duster,
GeglBuffer *in,
GeglBuffer *out,
gfloat scale)
{
GeglRectangle rect;
- const Babl *format = babl_format ("RGBA float");
+ const Babl *format = babl_format ("R'G'B'A float");
gint x, y;
rect = *gegl_buffer_get_extent (out);
@@ -110,16 +109,52 @@ static void improve (PixelDuster *duster,
{
Probe *probe;
probe = add_probe (duster, x, y);
-#if 1
if (probe_improve (duster, probe) == 0)
{
- gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x, probe->source_y, NULL, &rgba[0], format,
GEGL_SAMPLER_NEAREST, 0);
+#if PIXDUST_REL_DIGEST==0
+ gfloat rgba[4*MAX_K];
+
+ for (int j = 0; j < MAX_K; j++)
+ gegl_buffer_sample (duster->input, probe->source_x[j], probe->source_y[j], NULL, &rgba[j*4],
format, GEGL_SAMPLER_NEAREST, 0);
+
+
+ for (int j = 1; j < probe->k; j++)
+ for (int c = 0; c < 4; c++)
+ {
+ rgba[0+c] += rgba[j*4+c];
+ }
+ for (int c = 0; c < 4; c++)
+ {
+ rgba[c] /= probe->k;
+ }
+
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]);
+ fprintf (stderr, "eek %i,%i %f %f %f %f\n", probe->source_x[MAX_K/2], probe->source_y[MAX_K/2],
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);
- }
+#else
+ gfloat rgba[4];
+ gfloat delta[4]={0,0,0,0};
+ {
+ int dx = 0, dy = 0;
+ duster_idx_to_x_y (duster, 1, probe->hay[0][0], &dx, &dy);
+ gegl_buffer_sample (duster->output, probe->target_x + dx, probe->target_y + dy, NULL, &rgba[0],
format, GEGL_SAMPLER_NEAREST, 0);
+ }
+
+ for (int k = 0; k < probe->k; k++)
+ {
+ for (int c = 0; c < 3; c ++)
+ delta[c] += ((probe->hay[k][4+c]-127.0) / 128);
+ }
+
+ for (int c = 0; c < 3; c ++)
+ rgba[c] = rgba[c] - delta[c] / probe->k;
+ rgba[3]=1.0;
+
+ gegl_buffer_set (duster->output, GEGL_RECTANGLE(probe->target_x, probe->target_y, 1, 1), 0,
format, &rgba[0], 0);
+
#endif
+ }
g_hash_table_remove (duster->probes_ht, xy2offset(probe->target_x, probe->target_y));
}
fprintf (stderr, "\r%2.2f ", y * 100.0 / rect.height);
@@ -127,7 +162,6 @@ static void improve (PixelDuster *duster,
fprintf (stderr, "\n");
}
-
static gboolean
process (GeglOperation *operation,
GeglBuffer *input,
@@ -143,7 +177,7 @@ process (GeglOperation *operation,
duster = pixel_duster_new (input, output,
&in_rect, &out_rect,
o->seek_distance,
- 1, 1, 1.0, 1.0,
+ 1, 1, 1.0, 0.3,
o->scale,
o->scale,
NULL);
@@ -170,7 +204,6 @@ get_bounding_box (GeglOperation *operation)
return result;
}
-
static GeglRectangle
get_cached_region (GeglOperation *operation,
const GeglRectangle *roi)
diff --git a/operations/workshop/enlarge2.c b/operations/workshop/enlarge2.c
new file mode 100644
index 0000000..a8d9318
--- /dev/null
+++ b/operations/workshop/enlarge2.c
@@ -0,0 +1,239 @@
+/* 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
+
+property_int (seek_distance, "seek radius", 8)
+ value_range (4, 512)
+
+property_double (scale, "scale", 2.0)
+ value_range (0.1, 20.0)
+
+property_int (min_neigh, "min neigh", 1)
+ value_range (1, 10)
+
+property_int (min_iter, "min iter", 512)
+ value_range (1, 512)
+
+property_double (chance_try, "try chance", 0.1)
+ value_range (0.0, 1.0)
+
+property_double (chance_retry, "retry chance", 0.0)
+ value_range (0.0, 1.0)
+
+#else
+
+#define GEGL_OP_FILTER
+#define GEGL_OP_NAME enlarge2
+#define GEGL_OP_C_SOURCE enlarge2.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)
+{
+ 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};
+ gegl_buffer_set (out, &r, 0, format, &rgba[0], 0);
+ }
+
+ rect = *gegl_buffer_get_extent (in);
+ for (y = 0; y < rect.height; y++)
+ for (x = 0; x < rect.width; x++)
+ {
+ GeglRectangle r = {x * scale , y * scale, 1, 1};
+ gfloat rgba[4];
+ gegl_buffer_sample (in, x, y, NULL, &rgba[0], format, GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_set (out, &r, 0, format, &rgba[0], 0);
+ }
+}
+
+static void remove_grid (GeglBuffer *in,
+ GeglBuffer *out,
+ gfloat scale)
+{
+ GeglRectangle rect;
+ const Babl *format = babl_format ("RGBA float");
+ gint x, y;
+ rect = *gegl_buffer_get_extent (in);
+ for (y = 0; y < rect.height; y++)
+ for (x = 0; x < rect.width; x++)
+ {
+ GeglRectangle r = {x * scale , y * scale, 1, 1};
+ gfloat rgba[4] = {0,0,0,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);
+ 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);
+ seed_db (duster);
+ pixel_duster_add_probes_for_transparent (duster);
+ pixel_duster_fill (duster);
+#if 1
+ remove_grid (input, output, o->scale);
+ pixel_duster_remove_probes (duster);
+ pixel_duster_add_probes_for_transparent (duster);
+ pixel_duster_fill (duster);
+#endif
+ pixel_duster_destroy (duster);
+
+ return TRUE;
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+ GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ 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)
+{
+ GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+
+ 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:enlarge2",
+ "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 84d721b..250eb01 100644
--- a/operations/workshop/inpaint.c
+++ b/operations/workshop/inpaint.c
@@ -32,10 +32,10 @@ property_int (min_neigh, "min neigh", 2)
property_int (min_iter, "min iter", 4)
value_range (1, 512)
-property_double (chance_try, "try chance", 0.55)
+property_double (chance_try, "try chance", 0.88)
value_range (0.0, 1.0)
-property_double (chance_retry, "retry chance", 0.2)
+property_double (chance_retry, "retry chance", 0.5)
value_range (0.0, 1.0)
#else
diff --git a/operations/workshop/pixel-duster.h b/operations/workshop/pixel-duster.h
index 403c806..1e7293a 100644
--- a/operations/workshop/pixel-duster.h
+++ b/operations/workshop/pixel-duster.h
@@ -1,12 +1,30 @@
/* 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
* 2018 (c) Øyvind Kolås pippin gimp org
*/
/*
todo:
- median/mean for noise redux
exclude identicals - when it is obvious
+
+ threading
+ create list of hashtables and to hashtable list per thread
+
+ adjust precision of matching
+
+ replace hashtables with just lists - and include coords in element - perhaps with count..
+ for identical entries - thus not losing accurate median computation capabilitiy..
+ do median instead of mean for matched pixel components
+
+ store values relative to center pixel instead of center pixel - thus
+ permitting a wider range of neighborhoods to produce valid data - thus will be
+ good at least for superresolution
+
+ add mirroring - thus doubling data
*/
#define POW2(x) ((x)*(x))
@@ -35,19 +53,40 @@ typedef struct
int order[512][3];
} PixelDuster;
+
+/* todo: create neighbor color histogram - that can
+ be used as neighborhood separation criteria
+ ideally low-enough bits that it can be used
+ as selector.
+ gray axis as separate entity.
+
+ 4x4x4
+
+*/
+
+#define MAX_K 4
+#define PIXDUST_REL_DIGEST 0
+#define NEIGHBORHOOD 32
+#define PIXDUST_ORDERED 1
+#define MAX_DIR 4
+
+//#define ONLY_DIR 0
+
typedef struct Probe {
int target_x;
int target_y;
- int score;
int age;
- int source_x;
- int source_y;
+ int k;
+ int score;
+ int k_score[MAX_K];
+ int source_x[MAX_K];
+ int source_y[MAX_K];
+ guchar *hay[MAX_K];
} Probe;
/* used for hash-table keys */
#define xy2offset(x,y) GINT_TO_POINTER(((y) * 65536 + (x)))
-#define NEIGHBORHOOD 23
/* when going through the image preparing the index - only look at the subset
* needed pixels - and later when fetching out hashed pixels - investigate
@@ -58,7 +97,7 @@ typedef struct Probe {
static void init_order(PixelDuster *duster)
{
int i, x, y;
-#if 0
+#if PIXDUST_ORDERED
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},
@@ -104,15 +143,40 @@ static void init_order(PixelDuster *duster)
for (y = -7; y <= 7; y ++)
for (x = -7; x <= 7; x ++)
{
- if (order_2d[x+7][y+7] == i)
+ if (order_2d[y+7][x+7] == i)
{
- duster->order[i][0] = x;
- duster->order[i][1] = y;
+ duster->order[i][0] = y;
+ duster->order[i][1] = x;
duster->order[i][2] = POW2(x)+POW2(y);
}
}
}
+static void duster_idx_to_x_y (PixelDuster *duster, int index, int dir, 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;
+ }
+}
+
+
static PixelDuster * pixel_duster_new (GeglBuffer *input,
GeglBuffer *output,
const GeglRectangle *in_rect,
@@ -127,18 +191,18 @@ static PixelDuster * pixel_duster_new (GeglBuffer *input,
GeglOperation *op)
{
PixelDuster *ret = g_malloc0 (sizeof (PixelDuster));
- ret->input = input;
- ret->output = output;
+ ret->input = input;
+ ret->output = output;
ret->seek_radius = seek_radius;
- ret->minimum_neighbors = minimum_neighbors;
+ ret->minimum_neighbors = minimum_neighbors;
ret->minimum_iterations = minimum_iterations;
- ret->try_chance = try_chance;
+ ret->try_chance = try_chance;
ret->retry_chance = retry_chance;
ret->op = op;
- ret->in_rect = *in_rect;
+ ret->in_rect = *in_rect;
ret->out_rect = *out_rect;
- ret->scale_x = scale_x;
- ret->scale_y = scale_y;
+ ret->scale_x = scale_x;
+ ret->scale_y = scale_y;
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);
@@ -160,80 +224,100 @@ static void pixel_duster_destroy (PixelDuster *duster)
pixel_duster_remove_probes (duster);
for (int i = 0; i < 4096; i++)
{
+#if 0
if (g_hash_table_size (duster->ht[i]))
fprintf (stderr, "%i:%i ", i, g_hash_table_size (duster->ht[i]));
+#endif
g_hash_table_destroy (duster->ht[i]);
}
fprintf (stderr, "\n");
g_free (duster);
}
+
static void extract_site (PixelDuster *duster, GeglBuffer *input, int x, int y, guchar *dst)
{
static const Babl *format = NULL;
static const Babl *yformat = NULL;
guchar lum[8];
- int bdir = 0;
+ int bdir, maxlum;
+
if (!format){
format = babl_format ("R'G'B'A u8");
yformat = babl_format ("Y'aA u8");
}
-#if 1
+#define PIXDUST_DIR_INVARIANT 1
+#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_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);
+ 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[4], yformat, GEGL_SAMPLER_NEAREST, 0);
+ gegl_buffer_sample (input, x + 0, y - 1, NULL, &lum[6], yformat, GEGL_SAMPLER_NEAREST, 0);
+
+ bdir = 0;
- for (int i = 1; i < 4; i++)
- if (lum[i*2] > bdir)
- bdir = i;
+ maxlum = lum[0*2];
+ for (int i = 1; i < MAX_DIR; i++)
+ if (lum[i*2] > maxlum)
+ {
+ bdir = i;
+ maxlum = lum[i*2];
+ }
+
+#ifdef ONLY_DIR
+ bdir = ONLY_DIR;
+#endif
#endif
- /* and orient our neighborhood fetching based on that */
- switch (bdir)
- {
- 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 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_buffer_sample (input,
+ x + dx,
+ y + dy,
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ }
+#else
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ {
+ guchar tmp[4];
+ gegl_buffer_sample (input,
+ x,
+ y,
+ NULL, &tmp[0], format,
+ GEGL_SAMPLER_NEAREST, 0);
+ for (int i = 0; i <= NEIGHBORHOOD; i++)
+ {
+ int dx, dy;
+ duster_idx_to_x_y (duster, i, bdir, &dx, &dy);
+ gegl_buffer_sample (input,
+ x + dx,
+ y + dy,
+ NULL, &dst[i*4], format,
+ GEGL_SAMPLER_NEAREST, 0);
+
+ if (i==0)
+ for (int j = 0; j < 3; j++)
+ dst[i*4+j]=tmp[j];
+ else
+ for (int j = 0; j < 3; j++)
+ dst[i*4+j]= (dst[i*4+j] - tmp[j])/2 + 127;
+ dst[i*4+3]= dst[3];
}
+ }
+#endif
+ dst[0] = bdir;
}
static inline int u8_rgb_diff (guchar *a, guchar *b)
{
- return POW2(a[0]-b[0]) + POW2(a[1]-b[1]) * 2 + POW2(a[2]-b[2]);
+ return POW2(a[0]-b[0]) * 2 + POW2(a[1]-b[1]) * 3 + POW2(a[2]-b[2]);
}
static int inline
@@ -260,7 +344,11 @@ score_site (PixelDuster *duster,
else
{
/* we score missing cells as if it is a big diff */
- score += ((POW2(36))*3) * 40 / duster->order[i][2];
+#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
}
}
return score;
@@ -272,9 +360,11 @@ 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;//target_x / duster->scale_x;
- probe->source_y = 0;//target_y / duster->scale_y;
- probe->score = INITIAL_SCORE;
+ probe->source_x[0] = 0;//target_x / duster->scale_x;
+ probe->source_y[0] = 0;//target_y / duster->scale_y;
+ probe->k_score[0] = INITIAL_SCORE;
+ probe->k = 0;
+ probe->score = INITIAL_SCORE;
g_hash_table_insert (duster->probes_ht,
xy2offset(target_x, target_y), probe);
return probe;
@@ -310,6 +400,7 @@ probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, 0, -1)) found ++;
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 ++;
@@ -318,7 +409,6 @@ probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, -1, 1)) found ++;
if (found >=min) return found;
-#if 0
if (probe_rel_is_set (duster, output, probe, 2, 0)) found ++;
if (found >=min) return found;
if (probe_rel_is_set (duster, output, probe, 0, 2)) found ++;
@@ -338,6 +428,7 @@ probe_neighbors (PixelDuster *duster, GeglBuffer *output, Probe *probe, int min)
return found;
}
+#if 0
static inline int
spread_relative (PixelDuster *duster, Probe *probe, int dx, int dy)
{
@@ -370,6 +461,7 @@ spread_relative (PixelDuster *duster, Probe *probe, int dx, int dy)
}
return 0;
}
+#endif
static int site_subset (guchar *site)
{
@@ -407,6 +499,27 @@ static void site_subset2 (guchar *site, gint *min, gint *max)
}
}
+static void inline compare_needle_exact (gpointer key, gpointer value, gpointer data)
+{
+ void **ptr = data;
+ //PixelDuster *duster = ptr[0];
+ guchar *new_hay;
+ guchar *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)++;
+}
static guchar *ensure_hay (PixelDuster *duster, int x, int y, int subset)
{
@@ -428,12 +541,27 @@ static guchar *ensure_hay (PixelDuster *duster, int x, int y, int subset)
return NULL;
}
}
- g_hash_table_insert (duster->ht[subset], xy2offset(x, y), hay);
+ {
+#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);
+ }
+ }
}
return hay;
}
+
static void compare_needle (gpointer key, gpointer value, gpointer data)
{
void **ptr = data;
@@ -446,17 +574,31 @@ static void compare_needle (gpointer key, gpointer value, gpointer data)
gint y = offset / 65536;
int score;
+#if 1
if (duster->scale_x == 1.0 && x == probe->target_x &&
- duster->scale_y == 1.0 && y == probe->target_y )
return;
+#endif
score = score_site (duster, &needle[0], hay, probe->score);
- if (score < probe->score)
+ if (score <= probe->score)
{
- probe->source_x = x;
- probe->source_y = y;
- probe->score = score;
+ int j;
+ for (j = MAX_K-1; j >= 1; j --)
+ {
+ probe->source_x[j] = probe->source_x[j-1];
+ probe->source_y[j] = probe->source_y[j-1];
+ probe->hay[j] = probe->hay[j-1];
+ probe->k_score[j] = probe->k_score[j-1];
+ }
+ probe->k++;
+ if (probe->k > MAX_K)
+ probe->k = MAX_K;
+ probe->source_x[0] = x;
+ probe->source_y[0] = y;
+ probe->hay[0] = hay;
+ probe->score = probe->k_score[0] = score;
}
}
@@ -541,7 +683,10 @@ static inline void pixel_duster_add_probes_for_transparent (PixelDuster *duster)
float *out_pix = i->data[0];
while (n_pixels--)
{
- if (out_pix[3] <= 0.001)
+ if (out_pix[3] <= 0.001 ||
+ (out_pix[0] <= 0.01 &&
+ out_pix[1] <= 0.01 &&
+ out_pix[2] <= 0.01))
{
add_probe (duster, x, y);
}
@@ -588,8 +733,8 @@ static inline void pixel_duster_fill (PixelDuster *duster)
if (probe->score == INITIAL_SCORE || try_replace)
{
- if ((probe->source_x == probe->target_x &&
- probe->source_y == probe->target_y))
+ 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 &&
@@ -600,11 +745,20 @@ static inline void pixel_duster_fill (PixelDuster *duster)
probe->score = INITIAL_SCORE;
if (probe_improve (duster, probe) == 0)
{
+ gfloat sum_rgba[4]={0.0,0.0,0.0,0.0};
gfloat rgba[4];
- gegl_buffer_sample (duster->input, probe->source_x, probe->source_y,
- NULL, &rgba[0], format, GEGL_SAMPLER_NEAREST, 0);
+
+ for (gint i = 0; i < probe->k; i++)
+ {
+ gegl_buffer_sample (duster->input, probe->source_x[i], probe->source_y[i],
+ NULL, &rgba[0], format, GEGL_SAMPLER_NEAREST, 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;
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]);
+ fprintf (stderr, "eek %i,%i %f %f %f %f\n", probe->source_x[MAX_K/2], probe->source_y[MAX_K/2],
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);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]