Commit ea168f85 authored by Téo Mazars's avatar Téo Mazars

operations: deep cleanup of image-compare

- use iterators instead of allocating the whole input
- iterate only once
- implement get_cached_region to avoid any chunking
- use CIELab alpha instead of CIELab + RGBA
- try to stay in 80 columns and other format fixes
- add myself to the authors list
parent b0009d05
......@@ -15,6 +15,7 @@
*
* Copyright 2010 Øyvind Kolås <pippin@gimp.org>
* 2012 Ville Sokk <ville.sokk@gmail.com>
* 2013 Téo Mazars <teo.mazars@ensimag.fr>
*/
#include "config.h"
......@@ -23,10 +24,21 @@
#ifdef GEGL_CHANT_PROPERTIES
gegl_chant_int (wrong_pixels, _("Wrong pixels"), G_MININT, G_MAXINT, 0, _("Number of differing pixels."))
gegl_chant_double (max_diff, _("Maximum difference"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, _("Maximum difference between two pixels."))
gegl_chant_double (avg_diff_wrong, _("Average difference (wrong)"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, _("Average difference between wrong pixels."))
gegl_chant_double (avg_diff_total, _("Average difference (total)"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, _("Average difference between all pixels."))
gegl_chant_int (wrong_pixels, _("Wrong pixels"),
G_MININT, G_MAXINT, 0,
_("Number of differing pixels."))
gegl_chant_double (max_diff, _("Maximum difference"),
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
_("Maximum difference between two pixels."))
gegl_chant_double (avg_diff_wrong, _("Average difference (wrong)"),
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
_("Average difference between wrong pixels."))
gegl_chant_double (avg_diff_total, _("Average difference (total)"),
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
_("Average difference between all pixels."))
#else
......@@ -35,12 +47,14 @@ gegl_chant_double (avg_diff_total, _("Average difference (total)"), -G_MAXDOUBLE
#include "gegl-chant.h"
#define ERROR_TOLERANCE 0.01
#define SQR(x) ((x) * (x))
static void
prepare (GeglOperation *self)
{
gegl_operation_set_format (self, "input", babl_format ("CIE Lab float"));
gegl_operation_set_format (self, "aux", babl_format ("CIE Lab float"));
gegl_operation_set_format (self, "input", babl_format ("CIE Lab alpha float"));
gegl_operation_set_format (self, "aux", babl_format ("CIE Lab alpha float"));
gegl_operation_set_format (self, "output", babl_format ("R'G'B' u8"));
}
......@@ -49,12 +63,15 @@ get_required_for_output (GeglOperation *operation,
const gchar *input_pad,
const GeglRectangle *region)
{
GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input");
return result;
return *gegl_operation_source_get_bounding_box (operation, "input");
}
#define SQR(x) ((x) * (x))
static GeglRectangle
get_cached_region (GeglOperation *operation,
const GeglRectangle *roi)
{
return *gegl_operation_source_get_bounding_box (operation, "input");
}
static gboolean
process (GeglOperation *operation,
......@@ -64,129 +81,78 @@ process (GeglOperation *operation,
const GeglRectangle *result,
gint level)
{
GeglChantO *props = GEGL_CHANT_PROPERTIES (operation);
gdouble max_diff = 0.0;
gdouble diffsum = 0.0;
gint wrong_pixels = 0;
const Babl* cielab = babl_format ("CIE Lab float");
const Babl* rgbaf = babl_format ("RGBA float");
const Babl* srgb = babl_format ("R'G'B' u8");
gint pixels, i;
gfloat *in_buf, *aux_buf, *a, *b;
gfloat *in_buf_rgba, *aux_buf_rgba, *aalpha, *balpha;
guchar *out_buf, *out;
GeglChantO *props = GEGL_CHANT_PROPERTIES (operation);
gdouble max_diff = 0.0;
gdouble diffsum = 0.0;
gint wrong_pixels = 0;
const Babl *cielab = babl_format ("CIE Lab alpha float");
const Babl *srgb = babl_format ("R'G'B' u8");
GeglBufferIterator *gi;
gint index_iter, index_iter2;
if (aux == NULL)
return TRUE;
in_buf = g_malloc (result->height * result->width * babl_format_get_bytes_per_pixel (cielab));
aux_buf = g_malloc (result->height * result->width * babl_format_get_bytes_per_pixel (cielab));
in_buf_rgba = g_malloc (result->height * result->width * babl_format_get_bytes_per_pixel (rgbaf));
aux_buf_rgba = g_malloc (result->height * result->width * babl_format_get_bytes_per_pixel (rgbaf));
gi = gegl_buffer_iterator_new (output, result, 0, srgb,
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
out_buf = g_malloc (result->height * result->width * babl_format_get_bytes_per_pixel (srgb));
index_iter = gegl_buffer_iterator_add (gi, input, result, 0, cielab,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
gegl_buffer_get (input, result, 1.0, cielab, in_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (aux, result, 1.0, cielab, aux_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
index_iter2 = gegl_buffer_iterator_add (gi, aux, result, 0, cielab,
GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
gegl_buffer_get (input, result, 1.0, rgbaf, in_buf_rgba, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (aux, result, 1.0, rgbaf, aux_buf_rgba, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
a = in_buf;
b = aux_buf;
out = out_buf;
aalpha = in_buf_rgba;
balpha = aux_buf_rgba;
pixels = result->width * result->height;
for (i = 0; i < pixels; i++)
while (gegl_buffer_iterator_next (gi))
{
gdouble diff = sqrt (SQR(a[0] - b[0])+
SQR(a[1] - b[1])+
SQR(a[2] - b[2]));
guint k;
guchar *data_out;
gfloat *data_in1;
gfloat *data_in2;
gdouble alpha_diff = abs(aalpha[3] - balpha[3]) * 100.0;
data_out = (guchar*) gi->data[0];
data_in1 = (gfloat*) gi->data[index_iter];
data_in2 = (gfloat*) gi->data[index_iter2];
if (alpha_diff > diff)
diff = alpha_diff;
if (diff >= 0.01)
{
wrong_pixels++;
diffsum += diff;
if (diff > max_diff)
max_diff = diff;
out[0] = (diff / 100.0 * 255);
out[1] = 0;
out[2] = a[0] / 100.0 * 255;
}
else
for (k = 0; k < gi->length; k++)
{
out[0] = a[0] / 100.0 * 255;
out[1] = a[0] / 100.0 * 255;
out[2] = a[0] / 100.0 * 255;
gdouble diff = sqrt (SQR (data_in1[0] - data_in2[0]) +
SQR (data_in1[1] - data_in2[1]) +
SQR (data_in1[2] - data_in2[2]));
gdouble alpha_diff = abs (data_in1[3] - data_in2[3]) * 100.0;
diff = MAX (diff, alpha_diff);
if (diff >= ERROR_TOLERANCE)
{
wrong_pixels++;
diffsum += diff;
if (diff > max_diff)
max_diff = diff;
data_out[0] = CLAMP ((100 - data_in1[0]) / 100.0 * 64 + 32,
0, 255);
data_out[1] = CLAMP (diff / max_diff * 255, 0, 255);
data_out[2] = 0;
}
else
{
data_out[0] = CLAMP (data_in1[0] / 100.0 * 255, 0, 255);
data_out[1] = CLAMP (data_in1[0] / 100.0 * 255, 0, 255);
data_out[2] = CLAMP (data_in1[0] / 100.0 * 255, 0, 255);
}
data_out += 3;
data_in1 += 4;
data_in2 += 4;
}
a += 3;
aalpha += 4;
b += 3;
balpha += 4;
out += 3;
}
a = in_buf;
b = aux_buf;
out = out_buf;
aalpha = in_buf_rgba;
balpha = aux_buf_rgba;
if (wrong_pixels)
for (i = 0; i < pixels; i++)
{
gdouble diff = sqrt (SQR(a[0] - b[0])+
SQR(a[1] - b[1])+
SQR(a[2] - b[2]));
gdouble alpha_diff = abs(aalpha[3] - balpha[3]) * 100.0;
if (alpha_diff > diff)
diff = alpha_diff;
if (diff >= 0.01)
{
out[0] = (100 - a[0]) / 100.0 * 64 + 32;
out[1] = (diff / max_diff * 255);
out[2] = 0;
}
else
{
out[0] = a[0] / 100.0 * 255;
out[1] = a[0] / 100.0 * 255;
out[2] = a[0] / 100.0 * 255;
}
a += 3;
aalpha += 4;
b += 3;
balpha += 4;
out += 3;
}
gegl_buffer_set (output, result, 1.0, srgb, out_buf, GEGL_AUTO_ROWSTRIDE);
g_free (in_buf);
g_free (aux_buf);
g_free (out_buf);
g_free (in_buf_rgba);
g_free (aux_buf_rgba);
props->wrong_pixels = wrong_pixels;
props->max_diff = max_diff;
props->avg_diff_wrong = diffsum / wrong_pixels;
props->avg_diff_total = diffsum / pixels;
props->avg_diff_total = diffsum / (result->width * result->height);
return TRUE;
}
......@@ -202,15 +168,16 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->prepare = prepare;
operation_class->get_required_for_output = get_required_for_output;
operation_class->get_cached_region = get_cached_region;
composer_class->process = process;
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:image-compare",
"categories" , "programming",
"description", _("Compares if input and aux buffers are "
"different. Results are saved in the "
"properties."),
NULL);
"name" , "gegl:image-compare",
"categories" , "programming",
"description", _("Compares if input and aux buffers are "
"different. Results are saved in the "
"properties."),
NULL);
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment