saturation: add CIE Yuv and RGB interpolation methods, issue #171

All three methods are linear interpolations towards luminance desaturation of
the image, though in different color spaces - yielding slightly different
results. The default behavior remains the CIE Lab based interpolation for now.
Perhaps in a later release we will also change the default to be the
interpolation in linear native space, while adding CMYK support to desaturate
that does not lose the separation.
parent 158b9aea
......@@ -14,6 +14,7 @@
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2016 Red Hat, Inc.
* 2019 Øyvind Kolås
*/
#include "config.h"
......@@ -21,11 +22,23 @@
#ifdef GEGL_PROPERTIES
enum_start (gegl_saturation_type)
enum_value (GEGL_SATURATION_TYPE_CIE_LAB, "CIE-Lab", N_("CIE Lab / Lch"))
enum_value (GEGL_SATURATION_TYPE_NATIVE, "linear", N_("linear data, RGB"))
/* will also work on CMYK in the future */
enum_value (GEGL_SATURATION_TYPE_CIE_YUV, "CIE-Yuv", N_("CIE Yuv"))
enum_end (GeglSaturationType)
property_double (scale, _("Scale"), 1.0)
description(_("Scale, strength of effect"))
value_range (0.0, 10.0)
ui_range (0.0, 2.0)
property_enum (colorspace, _("Color Space"),
description(_("Which color space to do interpolation in."))
GeglSaturationType, gegl_saturation_type,
GEGL_SATURATION_TYPE_NATIVE)
#else
#define GEGL_OP_POINT_FILTER
......@@ -139,54 +152,137 @@ process_lch_alpha (GeglOperation *operation,
}
}
static void prepare (GeglOperation *operation)
static void
process_cie_yuv_alpha (GeglOperation *operation,
void *in_buf,
void *out_buf,
glong n_pixels,
const GeglRectangle *roi,
gint level)
{
const Babl *space = gegl_operation_get_source_space (operation, "input");
GeglProperties *o = GEGL_PROPERTIES (operation);
const Babl *format;
const Babl *input_format;
const Babl *input_model;
const Babl *lch_model;
gfloat *in = in_buf;
gfloat *out = out_buf;
glong i;
float scale = o->scale;
input_format = gegl_operation_get_source_format (operation, "input");
if (input_format == NULL)
#define CIE_u_origin (4/19.0f)
#define CIE_v_origin (9/19.0f)
for (i = 0; i < n_pixels; i++)
{
format = babl_format_with_space ("CIE Lab alpha float", space);
o->user_data = process_lab_alpha;
goto out;
out[0] = in[0];
out[1] = (in[1] - CIE_u_origin) * scale + CIE_u_origin;
out[2] = (in[2] - CIE_v_origin) * scale + CIE_v_origin;
out[3] = in[3];
in += 4;
out += 4;
}
}
input_model = babl_format_get_model (input_format);
static void
process_rgb_alpha (GeglOperation *operation,
void *in_buf,
void *out_buf,
glong n_pixels,
const GeglRectangle *roi,
gint level)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
const Babl *space = gegl_operation_get_source_space (operation, "input");
gfloat *in = in_buf;
gfloat *out = out_buf;
glong i;
float scale = o->scale;
float rscale = 1.0f - o->scale;
double luminance[3];
float luminance_f[3];
if (babl_format_has_alpha (input_format))
{
lch_model = babl_model_with_space ("CIE LCH(ab) alpha", space);
if (input_model == lch_model)
{
format = babl_format_with_space ("CIE LCH(ab) alpha float", space);
o->user_data = process_lch_alpha;
}
else
{
format = babl_format_with_space ("CIE Lab alpha float", space);
o->user_data = process_lab_alpha;
}
}
else
babl_space_get_rgb_luminance (space,
&luminance[0], &luminance[1], &luminance[2]);
for (int c = 0; c < 3; c ++)
luminance_f[c] = luminance[c];
for (i = 0; i < n_pixels; i++)
{
lch_model = babl_model_with_space ("CIE LCH(ab)", space);
if (input_model == lch_model)
{
format = babl_format_with_space ("CIE LCH(ab) float", space);
o->user_data = process_lch;
}
else
{
format = babl_format_with_space ("CIE Lab float", space);
o->user_data = process_lab;
}
gfloat desaturated = (in[0] * luminance_f[0] +
in[1] * luminance_f[1] +
in[2] * luminance_f[2]) * rscale;
for (int c = 0; c < 3; c ++)
out[c] = desaturated + in[c] * scale;
out[3] = in[3];
in += 4;
out += 4;
}
}
static void prepare (GeglOperation *operation)
{
const Babl *space = gegl_operation_get_source_space (operation, "input");
GeglProperties *o = GEGL_PROPERTIES (operation);
const Babl *format;
switch (o->colorspace)
{
case GEGL_SATURATION_TYPE_NATIVE:
format = babl_format_with_space ("RGBA float", space);
o->user_data = process_rgb_alpha;
break;
case GEGL_SATURATION_TYPE_CIE_YUV:
format = babl_format_with_space ("CIE Yuv alpha float", space);
o->user_data = process_cie_yuv_alpha;
break;
case GEGL_SATURATION_TYPE_CIE_LAB:
{
const Babl *input_format;
const Babl *input_model;
const Babl *lch_model;
input_format = gegl_operation_get_source_format (operation, "input");
if (input_format == NULL)
{
format = babl_format_with_space ("CIE Lab alpha float", space);
o->user_data = process_lab_alpha;
goto out;
}
input_model = babl_format_get_model (input_format);
if (babl_format_has_alpha (input_format))
{
lch_model = babl_model_with_space ("CIE LCH(ab) alpha", space);
if (input_model == lch_model)
{
format = babl_format_with_space ("CIE LCH(ab) alpha float", space);
o->user_data = process_lch_alpha;
}
else
{
format = babl_format_with_space ("CIE Lab alpha float", space);
o->user_data = process_lab_alpha;
}
}
else
{
lch_model = babl_model_with_space ("CIE LCH(ab)", space);
if (input_model == lch_model)
{
format = babl_format_with_space ("CIE LCH(ab) float", space);
o->user_data = process_lch;
}
else
{
format = babl_format_with_space ("CIE Lab float", space);
o->user_data = process_lab;
}
}
}
break;
}
out:
gegl_operation_set_format (operation, "input", format);
gegl_operation_set_format (operation, "output", format);
......
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