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



commit 93c0fe7f5b56eafac051eb9dc9cefc3cbaafceaf
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Jul 4 14:38:38 2019 +0200

    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.

 operations/common/saturation.c | 172 ++++++++++++++++++++++++++++++++---------
 1 file changed, 134 insertions(+), 38 deletions(-)
---
diff --git a/operations/common/saturation.c b/operations/common/saturation.c
index 6c712717f..205ce6299 100644
--- a/operations/common/saturation.c
+++ b/operations/common/saturation.c
@@ -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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]