[gegl/soc-2012-ops] Photocopy Operation: Create and use histogram
- From: Hans Shu Lo <hanslo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/soc-2012-ops] Photocopy Operation: Create and use histogram
- Date: Wed, 27 Jun 2012 00:32:11 +0000 (UTC)
commit 0702d8f1687f6c81fed3d57a878397299bbd3185
Author: Hans Lo <hansshulo gmail com>
Date: Tue Jun 26 20:26:47 2012 -0400
Photocopy Operation: Create and use histogram
operations/common/photocopy.c | 262 ++++++++++++++++++++++++++++++-----------
1 files changed, 193 insertions(+), 69 deletions(-)
---
diff --git a/operations/common/photocopy.c b/operations/common/photocopy.c
index 293fcf0..871ce49 100644
--- a/operations/common/photocopy.c
+++ b/operations/common/photocopy.c
@@ -46,18 +46,159 @@ gegl_chant_double (white, _("Percent White"), 0.0, 1.0, 0.2,
#define THRESHOLD 0.75
+typedef struct {
+ gdouble black;
+ gdouble white;
+} Ramps;
+
+static gdouble
+compute_ramp (GeglBuffer *input,
+ GeglOperation *operation,
+ gdouble pct,
+ gint under_threshold)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+
+ GeglRectangle *whole_region = gegl_operation_source_get_bounding_box (operation, "input");
+ GeglNode *gegl, *image, *write1, *write2, *grey, *blur1, *blur2;
+ GeglBuffer *dest1 = gegl_buffer_new(whole_region, babl_format ("Y float"));
+ GeglBuffer *dest2 = gegl_buffer_new(whole_region, babl_format ("Y float"));
+
+ gegl = gegl_node_new();
+ image = gegl_node_new_child(gegl,
+ "operation", "gegl:buffer-source",
+ "buffer", input,
+ NULL);
+
+ grey = gegl_node_new_child(gegl,
+ "operation", "gegl:grey",
+ NULL);
+
+ blur1 = gegl_node_new_child(gegl,
+ "operation", "gegl:gaussian-blur",
+ "std_dev_x", (MAX(1.0, 10*(1.0 - o->sharpness)) + 1.0)/sqrt(2.0),
+ "std_dev_y", (MAX(1.0, 10*(1.0 - o->sharpness)) + 1.0)/sqrt(2.0),
+ NULL);
+
+ blur2 = gegl_node_new_child(gegl,
+ "operation", "gegl:gaussian-blur",
+ "std_dev_x", (o->mask_radius + 1.0)/sqrt(2.0),
+ "std_dev_y", (o->mask_radius + 1.0)/sqrt(2.0),
+ NULL);
+
+ write1 = gegl_node_new_child(gegl,
+ "operation", "gegl:buffer-sink",
+ "buffer", &dest1, NULL);
+
+ write2 = gegl_node_new_child(gegl,
+ "operation", "gegl:buffer-sink",
+ "buffer", &dest2, NULL);
+
+
+ gegl_node_link_many (image, grey, blur1, write1, NULL);
+ gegl_node_process (write1);
+
+ gegl_node_link_many (image, grey, blur2, write2, NULL);
+ gegl_node_process (write2);
+
+ GeglSampler *sampler1 = gegl_buffer_sampler_new (dest1,
+ babl_format ("Y float"),
+ GEGL_SAMPLER_CUBIC);
+ GeglSampler *sampler2 = gegl_buffer_sampler_new (dest2,
+ babl_format ("Y float"),
+ GEGL_SAMPLER_CUBIC);
+ gint n_pixels = whole_region->width * whole_region->height;
+ gint hist[2000];
+ gdouble diff;
+ gint count;
+ gint sum;
+
+ memset (hist, 0, sizeof (int) * 2000);
+ count = 0;
+ gfloat pixel1, pixel2;
+ gint x = whole_region->x;
+ gint y = whole_region->y;
+ gint i;
+ while (n_pixels--)
+ {
+ gegl_sampler_get (sampler1,
+ x,
+ y,
+ NULL,
+ &pixel1);
+
+ gegl_sampler_get (sampler2,
+ x,
+ y,
+ NULL,
+ &pixel2);
+ diff = pixel1/pixel2;
+ if (under_threshold)
+ {
+ if (diff < THRESHOLD)
+ {
+ hist[(int) (diff * 1000)] += 1;
+ count += 1;
+ }
+ }
+ else
+ {
+ if (diff >= THRESHOLD && diff < 2.0)
+ {
+ hist[(int) (diff * 1000)] += 1;
+ count += 1;
+ }
+ }
+ /* update x and y coordinates */
+ x++;
+ if (x>=whole_region->x + whole_region->width)
+ {
+ x=whole_region->x;
+ y++;
+ }
+ }
+
+ g_object_unref (sampler1);
+ g_object_unref (sampler2);
+
+ g_object_unref (gegl);
+ g_object_unref (dest1);
+ g_object_unref (dest2);
+
+ if (pct == 0.0 || count == 0)
+ return (under_threshold ? 1.0 : 0.0);
+
+ sum = 0;
+ for (i = 0; i < 2000; i++)
+ {
+ sum += hist[i];
+ if (((gdouble) sum / (gdouble) count) > pct)
+ {
+ if (under_threshold)
+ return (THRESHOLD - (gdouble) i / 1000.0);
+ else
+ return ((gdouble) i / 1000.0 - THRESHOLD);
+ }
+ }
+
+ return (under_threshold ? 0.0 : 1.0);
+}
+
static void prepare (GeglOperation *operation)
{
GeglChantO *o;
- GeglOperationAreaFilter *op_area;
-
- op_area = GEGL_OPERATION_AREA_FILTER (operation);
+
o = GEGL_CHANT_PROPERTIES (operation);
-
+
gegl_operation_set_format (operation, "input",
- babl_format ("RGBA float"));
+ babl_format ("Y float"));
gegl_operation_set_format (operation, "output",
- babl_format ("RGBA float"));
+ babl_format ("Y float"));
+ if(o->chant_data)
+ {
+ g_slice_free (Ramps, o->chant_data);
+ }
+ o->chant_data = NULL;
}
static gboolean
@@ -73,6 +214,17 @@ process (GeglOperation *operation,
GeglBuffer *dest1 = gegl_buffer_new(result, babl_format ("Y float"));
GeglBuffer *dest2 = gegl_buffer_new(result, babl_format ("Y float"));
+ Ramps* ramps;
+
+ // needs mutex
+ if(o->chant_data == NULL) {
+ o->chant_data = g_slice_new (Ramps);
+
+ ramps = (Ramps*) o->chant_data;
+ ramps->black = compute_ramp(input,operation,o->black,1);
+ ramps->white = compute_ramp(input,operation,1.0-o->white,0);
+ }
+
gegl = gegl_node_new();
image = gegl_node_new_child(gegl,
"operation", "gegl:buffer-source",
@@ -85,14 +237,14 @@ process (GeglOperation *operation,
blur1 = gegl_node_new_child(gegl,
"operation", "gegl:gaussian-blur",
- "std_dev_x", 1.0 - o->sharpness,
- "std_dev_y", 1.0 - o->sharpness,
+ "std_dev_x", (MAX(1.0, 10*(1.0 - o->sharpness)) + 1.0)/sqrt(2.0),
+ "std_dev_y", (MAX(1.0, 10*(1.0 - o->sharpness)) + 1.0)/sqrt(2.0),
NULL);
blur2 = gegl_node_new_child(gegl,
"operation", "gegl:gaussian-blur",
- "std_dev_x", o->mask_radius,
- "std_dev_y", o->mask_radius,
+ "std_dev_x", (o->mask_radius + 1.0)/sqrt(2.0),
+ "std_dev_y", (o->mask_radius + 1.0)/sqrt(2.0),
NULL);
write1 = gegl_node_new_child(gegl,
@@ -129,7 +281,10 @@ process (GeglOperation *operation,
gint y = result->y; /* and y coordinates */
gdouble diff;
-
+ Ramps *get_ramps = (Ramps*) o->chant_data;
+ gdouble ramp_down = get_ramps->black;
+ gdouble ramp_up = get_ramps->white;
+ gdouble mult;
while (n_pixels--)
{
gegl_sampler_get (sampler1,
@@ -146,11 +301,22 @@ process (GeglOperation *operation,
diff = pixel1/pixel2;
if (diff < THRESHOLD)
{
- *out_pixel = 1.0;
+ if (ramp_down == 0.0)
+ mult = 0.0;
+ else
+ mult = (ramp_down - MIN (ramp_down,
+ (THRESHOLD - diff))) / ramp_down;
+ *out_pixel = pixel1 * mult;
}
else
{
- *out_pixel = pixel1;
+ if (ramp_up == 0.0)
+ mult = 1.0;
+ else
+ mult = MIN (ramp_up,
+ (diff - THRESHOLD)) / ramp_up;
+
+ *out_pixel = 1.0 - (1.0 - mult) * (1.0 - pixel1);
}
out_pixel += 1;
@@ -169,81 +335,39 @@ process (GeglOperation *operation,
g_object_unref (sampler2);
g_object_unref (gegl);
+ g_object_unref (dest1);
+ g_object_unref (dest2);
+
return TRUE;
}
-static gdouble
-compute_ramp (guchar *dest1,
- guchar *dest2,
- gint length,
- gdouble pct,
- gint under_threshold)
+static void
+finalize (GObject *object)
{
- gint hist[2000];
- gdouble diff;
- gint count;
- gint i;
- gint sum;
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
- memset (hist, 0, sizeof (int) * 2000);
- count = 0;
-
- for (i = 0; i < length; i++)
+ if (o->chant_data)
{
- if (*dest2 != 0)
- {
- diff = (gdouble) *dest1 / (gdouble) *dest2;
-
- if (under_threshold)
- {
- if (diff < THRESHOLD)
- {
- hist[(int) (diff * 1000)] += 1;
- count += 1;
- }
- }
- else
- {
- if (diff >= THRESHOLD && diff < 2.0)
- {
- hist[(int) (diff * 1000)] += 1;
- count += 1;
- }
- }
- }
-
- dest1++;
- dest2++;
+ g_slice_free (Ramps, o->chant_data);
+ o->chant_data = NULL;
}
- if (pct == 0.0 || count == 0)
- return (under_threshold ? 1.0 : 0.0);
-
- sum = 0;
- for (i = 0; i < 2000; i++)
- {
- sum += hist[i];
- if (((gdouble) sum / (gdouble) count) > pct)
- {
- if (under_threshold)
- return (THRESHOLD - (gdouble) i / 1000.0);
- else
- return ((gdouble) i / 1000.0 - THRESHOLD);
- }
- }
-
- return (under_threshold ? 0.0 : 1.0);
+ G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
}
static void
gegl_chant_class_init (GeglChantClass *klass)
{
+ GObjectClass *object_class;
GeglOperationClass *operation_class;
GeglOperationFilterClass *filter_class;
+
+ object_class = G_OBJECT_CLASS (klass);
operation_class = GEGL_OPERATION_CLASS (klass);
filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
+ object_class->finalize = finalize;
operation_class->prepare = prepare;
filter_class->process = process;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]