[gegl] operations/common/exposure: Add a property for adjusting blacks
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations/common/exposure: Add a property for adjusting blacks
- Date: Thu, 9 Feb 2017 11:47:50 +0000 (UTC)
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]