[gegl] operations/common/exposure: Add a property for adjusting blacks



commit ae868a721fd51caedc7f876c2a746e5ed551c309
Author: Debarshi Ray <debarshir gnome org>
Date:   Wed Feb 8 22:47:08 2017 +0100

    operations/common/exposure: Add a property for adjusting blacks
    
    If we only consider the 'exposure' property, then this operation is the
    same as dt:exposure. One desirable thing about Darktable's version is
    that it let's us adjust the black level - the threshold at which dark
    grey values are cut off to pure black [1].
    
    Let's add a property to offer the same feature.
    
    If we leave black at its default value of 0.0, the behaviour of the
    operation should remain largely unchanged. The only difference is that
    the value of 'gain' won't exceed 100, while in the past it used to be
    unbounded. This seems like an acceptable compromise.
    
    [1] https://www.darktable.org/usermanual/ch03s04.html.php
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778366

 operations/common/exposure.c |   48 ++++++++++++++++++++++++++++++-----------
 1 files changed, 35 insertions(+), 13 deletions(-)
---
diff --git a/operations/common/exposure.c b/operations/common/exposure.c
index d45db11..9e4128e 100644
--- a/operations/common/exposure.c
+++ b/operations/common/exposure.c
@@ -15,6 +15,7 @@
  *
  * Copyright 2012,2013 Felix Ulber <felix ulber gmx de>
  *           2013 Øyvind Kolås <pippin gimp org>
+ *           2017 Red Hat, Inc.
  */
 
 #include "config.h"
@@ -22,6 +23,10 @@
 
 #ifdef GEGL_PROPERTIES
 
+property_double (black, _("Black"), 0.0)
+    description (_("Adjust the black level"))
+    value_range (-0.1, 0.1)
+
 property_double (exposure, _("Exposure"), 0.0)
     description (_("Relative brightness change in stops"))
     ui_range    (-10.0, 10.0)
@@ -68,9 +73,12 @@ process (GeglOperation       *op,
   GeglProperties *o = GEGL_PROPERTIES (op);
   gfloat     *in_pixel;
   gfloat     *out_pixel;
-
-  gfloat      gain = exp2f (o->exposure);
+  gfloat      black = (gfloat) o->black;
+  gfloat      diff;
+  gfloat      exposure_negated = (gfloat) -o->exposure;
+  gfloat      gain;
   gfloat      offset = o->offset;
+  gfloat      white;
   gfloat      gamma = 1.0 / o->gamma;
   
   glong       i;
@@ -78,12 +86,16 @@ process (GeglOperation       *op,
   in_pixel = in_buf;
   out_pixel = out_buf;
   
+  white = exp2f (exposure_negated);
+  diff = MAX (white - black, 0.01);
+  gain = 1.0f / diff;
+
   if (gamma == 1.0)
     for (i=0; i<n_pixels; i++)
       {
-        out_pixel[0] = (in_pixel[0] * gain + offset);
-        out_pixel[1] = (in_pixel[1] * gain + offset);
-        out_pixel[2] = (in_pixel[2] * gain + offset);
+        out_pixel[0] = (in_pixel[0] - black) * gain + offset;
+        out_pixel[1] = (in_pixel[1] - black) * gain + offset;
+        out_pixel[2] = (in_pixel[2] - black) * gain + offset;
         out_pixel[3] = in_pixel[3];
         
         out_pixel += 4;
@@ -92,9 +104,9 @@ process (GeglOperation       *op,
   else
     for (i=0; i<n_pixels; i++)
       {
-        out_pixel[0] = powf(in_pixel[0] * gain + offset, gamma);
-        out_pixel[1] = powf(in_pixel[1] * gain + offset, gamma);
-        out_pixel[2] = powf(in_pixel[2] * gain + offset, gamma);
+        out_pixel[0] = powf ((in_pixel[0] - black) * gain + offset, gamma);
+        out_pixel[1] = powf ((in_pixel[1] - black) * gain + offset, gamma);
+        out_pixel[2] = powf ((in_pixel[2] - black) * gain + offset, gamma);
         out_pixel[3] = in_pixel[3];
         
         out_pixel += 4;
@@ -109,6 +121,7 @@ process (GeglOperation       *op,
 static const char* kernel_source =
 "__kernel void kernel_exposure(__global const float4 *in,     \n"
 "                              __global       float4 *out,    \n"
+"                              float                  black,  \n"
 "                              float                  gain,   \n"
 "                              float                  offset, \n"
 "                              float                  gamma)  \n"
@@ -116,7 +129,7 @@ static const char* kernel_source =
 "  int gid = get_global_id(0);                                \n"
 "  float4 in_v  = in[gid];                                    \n"
 "  float4 out_v;                                              \n"
-"  out_v.xyz = pow((in_v.xyz * gain) + offset, 1.0/gamma);    \n"
+"  out_v.xyz = pow(((in_v.xyz - black) * gain) + offset, 1.0/gamma);    \n"
 "  out_v.w   =  in_v.w;                                       \n"
 "  out[gid]  =  out_v;                                        \n"
 "}                                                            \n";
@@ -138,8 +151,12 @@ cl_process (GeglOperation       *op,
 
   GeglProperties *o = GEGL_PROPERTIES (op);
 
-  gfloat      gain = exp2f (o->exposure);
+  gfloat      black = (gfloat) o->black;
+  gfloat      diff;
+  gfloat      exposure_negated = (gfloat) -o->exposure;
+  gfloat      gain;
   gfloat      offset = o->offset;
+  gfloat      white;
   gfloat      gamma = 1.0 / o->gamma;
   
   cl_int cl_err = 0;
@@ -151,11 +168,16 @@ cl_process (GeglOperation       *op,
     }
   if (!cl_data) return 1;
 
+  white = exp2f (exposure_negated);
+  diff = MAX (white - black, 0.01);
+  gain = 1.0f / diff;
+
   cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 0, sizeof(cl_mem),   (void*)&in_tex);
   cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 1, sizeof(cl_mem),   (void*)&out_tex);
-  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 2, sizeof(cl_float), (void*)&gain);
-  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 3, sizeof(cl_float), (void*)&offset);
-  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 4, sizeof(cl_float), (void*)&gamma);
+  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 2, sizeof(cl_float), (void*)&black);
+  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 3, sizeof(cl_float), (void*)&gain);
+  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 4, sizeof(cl_float), (void*)&offset);
+  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 5, sizeof(cl_float), (void*)&gamma);
   if (cl_err != CL_SUCCESS) return cl_err;
 
   cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),


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