Blame operations/common/color-temperature.c

Packit Service 2781ba
/* This file is an image processing operation for GEGL
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is free software; you can redistribute it and/or
Packit Service 2781ba
 * modify it under the terms of the GNU Lesser General Public
Packit Service 2781ba
 * License as published by the Free Software Foundation; either
Packit Service 2781ba
 * version 3 of the License, or (at your option) any later version.
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is distributed in the hope that it will be useful,
Packit Service 2781ba
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2781ba
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2781ba
 * Lesser General Public License for more details.
Packit Service 2781ba
 *
Packit Service 2781ba
 * You should have received a copy of the GNU Lesser General Public
Packit Service 2781ba
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Copyright 2008 Jan Heller <jan.heller (at) matfyz.cz>
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
#include "config.h"
Packit Service 2781ba
#include <glib/gi18n-lib.h>
Packit Service 2781ba
Packit Service 2781ba
#define LOWEST_TEMPERATURE     1000
Packit Service 2781ba
#define HIGHEST_TEMPERATURE   12000
Packit Service 2781ba
Packit Service 2781ba
#ifdef GEGL_CHANT_PROPERTIES
Packit Service 2781ba
Packit Service 2781ba
gegl_chant_double (original_temperature, _("Original temperature"), LOWEST_TEMPERATURE, HIGHEST_TEMPERATURE, 6500, _("Estimated temperature of the light source in Kelvin the image was taken with."))
Packit Service 2781ba
gegl_chant_double (intended_temperature, _("Intended temperature"), LOWEST_TEMPERATURE, HIGHEST_TEMPERATURE, 6500, _("Corrected estimation of the temperature of the light source in Kelvin."))
Packit Service 2781ba
Packit Service 2781ba
#else
Packit Service 2781ba
Packit Service 2781ba
#define GEGL_CHANT_TYPE_POINT_FILTER
Packit Service 2781ba
#define GEGL_CHANT_C_FILE       "color-temperature.c"
Packit Service 2781ba
Packit Service 2781ba
#include "gegl-chant.h"
Packit Service 2781ba
Packit Service 2781ba
static const gfloat rgb_r55[3][12];
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
convert_k_to_rgb (gfloat  temperature,
Packit Service 2781ba
                  gfloat *rgb)
Packit Service 2781ba
{
Packit Service 2781ba
  gint channel;
Packit Service 2781ba
Packit Service 2781ba
  if (temperature < LOWEST_TEMPERATURE)
Packit Service 2781ba
    temperature = LOWEST_TEMPERATURE;
Packit Service 2781ba
Packit Service 2781ba
  if (temperature > HIGHEST_TEMPERATURE)
Packit Service 2781ba
    temperature = HIGHEST_TEMPERATURE;
Packit Service 2781ba
Packit Service 2781ba
  /* Evaluation of an approximation of the Planckian locus in linear RGB space
Packit Service 2781ba
   * by rational functions of degree 5 using Horner's scheme
Packit Service 2781ba
   * f(x) =  (p1*x^5 + p2*x^4 + p3*x^3 + p4*x^2 + p5*x + p6) /
Packit Service 2781ba
   *            (x^5 + q1*x^4 + q2*x^3 + q3*x^2 + q4*x + q5)
Packit Service 2781ba
   */
Packit Service 2781ba
  for (channel = 0; channel < 3; channel++)
Packit Service 2781ba
    {
Packit Service 2781ba
      gfloat nomin, denom;
Packit Service 2781ba
      gint   deg;
Packit Service 2781ba
Packit Service 2781ba
      nomin = rgb_r55[channel][0];
Packit Service 2781ba
      for (deg = 1; deg < 6; deg++)
Packit Service 2781ba
        nomin = nomin * temperature + rgb_r55[channel][deg];
Packit Service 2781ba
Packit Service 2781ba
      denom = rgb_r55[channel][6];
Packit Service 2781ba
      for (deg = 1; deg < 6; deg++)
Packit Service 2781ba
        denom = denom * temperature + rgb_r55[channel][6 + deg];
Packit Service 2781ba
Packit Service 2781ba
      rgb[channel] = nomin / denom;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void prepare (GeglOperation *operation)
Packit Service 2781ba
{
Packit Service 2781ba
  const Babl *format = babl_format ("RGBA float");
Packit Service 2781ba
  gegl_operation_set_format (operation, "input", format);
Packit Service 2781ba
  gegl_operation_set_format (operation, "output", format);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
finalize (GObject *object)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
Packit Service 2781ba
Packit Service 2781ba
  if (o->chant_data)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_free (o->chant_data);
Packit Service 2781ba
      o->chant_data = NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
notify (GObject    *object,
Packit Service 2781ba
        GParamSpec *pspec)
Packit Service 2781ba
{
Packit Service 2781ba
  if (strcmp (pspec->name, "original-temperature") == 0 ||
Packit Service 2781ba
      strcmp (pspec->name, "intended-temperature") == 0)
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
Packit Service 2781ba
Packit Service 2781ba
      /* one of the properties has changed,
Packit Service 2781ba
       * invalidate the preprocessed coefficients
Packit Service 2781ba
       */
Packit Service 2781ba
      if (o->chant_data)
Packit Service 2781ba
        {
Packit Service 2781ba
          g_free (o->chant_data);
Packit Service 2781ba
          o->chant_data = NULL;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (G_OBJECT_CLASS (gegl_chant_parent_class)->notify)
Packit Service 2781ba
    G_OBJECT_CLASS (gegl_chant_parent_class)->notify (object, pspec);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static gfloat *
Packit Service 2781ba
preprocess (GeglChantO *o)
Packit Service 2781ba
{
Packit Service 2781ba
  gfloat *coeffs = g_new (gfloat, 3);
Packit Service 2781ba
  gfloat  original_temperature_rgb[3];
Packit Service 2781ba
  gfloat  intended_temperature_rgb[3];
Packit Service 2781ba
Packit Service 2781ba
  convert_k_to_rgb (o->original_temperature, original_temperature_rgb);
Packit Service 2781ba
  convert_k_to_rgb (o->intended_temperature, intended_temperature_rgb);
Packit Service 2781ba
Packit Service 2781ba
  coeffs[0] = original_temperature_rgb[0] / intended_temperature_rgb[0];
Packit Service 2781ba
  coeffs[1] = original_temperature_rgb[1] / intended_temperature_rgb[1];
Packit Service 2781ba
  coeffs[2] = original_temperature_rgb[2] / intended_temperature_rgb[2];
Packit Service 2781ba
Packit Service 2781ba
  return coeffs;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* GeglOperationPointFilter gives us a linear buffer to operate on
Packit Service 2781ba
 * in our requested pixel format
Packit Service 2781ba
 */
Packit Service 2781ba
static gboolean
Packit Service 2781ba
process (GeglOperation       *op,
Packit Service 2781ba
         void                *in_buf,
Packit Service 2781ba
         void                *out_buf,
Packit Service 2781ba
         glong                n_pixels,
Packit Service 2781ba
         const GeglRectangle *roi,
Packit Service 2781ba
         gint                 level)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglChantO   *o         = GEGL_CHANT_PROPERTIES (op);
Packit Service 2781ba
  gfloat       *in_pixel  = in_buf;
Packit Service 2781ba
  gfloat       *out_pixel = out_buf;
Packit Service 2781ba
  const gfloat *coeffs    = o->chant_data;
Packit Service 2781ba
Packit Service 2781ba
  in_pixel = in_buf;
Packit Service 2781ba
  out_pixel = out_buf;
Packit Service 2781ba
Packit Service 2781ba
  if (! coeffs)
Packit Service 2781ba
    {
Packit Service 2781ba
      coeffs = o->chant_data = preprocess (o);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  while (n_pixels--)
Packit Service 2781ba
    {
Packit Service 2781ba
      out_pixel[0] = in_pixel[0] * coeffs[0];
Packit Service 2781ba
      out_pixel[1] = in_pixel[1] * coeffs[1];
Packit Service 2781ba
      out_pixel[2] = in_pixel[2] * coeffs[2];
Packit Service 2781ba
      out_pixel[3] = in_pixel[3];
Packit Service 2781ba
Packit Service 2781ba
      in_pixel += 4;
Packit Service 2781ba
      out_pixel += 4;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  return TRUE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#include "opencl/gegl-cl.h"
Packit Service 2781ba
Packit Service 2781ba
static const char* kernel_source =
Packit Service 2781ba
"__kernel void kernel_temp(__global const float4     *in,       \n"
Packit Service 2781ba
"                          __global       float4     *out,      \n"
Packit Service 2781ba
"                          float coeff1,                        \n"
Packit Service 2781ba
"                          float coeff2,                        \n"
Packit Service 2781ba
"                          float coeff3)                        \n"
Packit Service 2781ba
"{                                                              \n"
Packit Service 2781ba
"  int gid = get_global_id(0);                                  \n"
Packit Service 2781ba
"  float4 in_v  = in[gid];                                      \n"
Packit Service 2781ba
"  float4 out_v;                                                \n"
Packit Service 2781ba
"  out_v.xyz = in_v.xyz * (float3) (coeff1, coeff2, coeff3);    \n"
Packit Service 2781ba
"  out_v.w   = in_v.w;                                          \n"
Packit Service 2781ba
"  out[gid]  =  out_v;                                          \n"
Packit Service 2781ba
"}                                                              \n";
Packit Service 2781ba
Packit Service 2781ba
static gegl_cl_run_data *cl_data = NULL;
Packit Service 2781ba
Packit Service 2781ba
/* OpenCL processing function */
Packit Service 2781ba
static cl_int
Packit Service 2781ba
cl_process (GeglOperation       *op,
Packit Service 2781ba
            cl_mem               in_tex,
Packit Service 2781ba
            cl_mem               out_tex,
Packit Service 2781ba
            size_t               global_worksize,
Packit Service 2781ba
            const GeglRectangle *roi,
Packit Service 2781ba
            int                  level)
Packit Service 2781ba
{
Packit Service 2781ba
  /* Retrieve a pointer to GeglChantO structure which contains all the
Packit Service 2781ba
   * chanted properties
Packit Service 2781ba
   */
Packit Service 2781ba
Packit Service 2781ba
  GeglChantO   *o         = GEGL_CHANT_PROPERTIES (op);
Packit Service 2781ba
  const gfloat *coeffs    = o->chant_data;
Packit Service 2781ba
Packit Service 2781ba
  cl_int cl_err = 0;
Packit Service 2781ba
Packit Service 2781ba
  if (! coeffs)
Packit Service 2781ba
    {
Packit Service 2781ba
      coeffs = o->chant_data = preprocess (o);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (!cl_data)
Packit Service 2781ba
    {
Packit Service 2781ba
      const char *kernel_name[] = {"kernel_temp", NULL};
Packit Service 2781ba
      cl_data = gegl_cl_compile_and_build (kernel_source, kernel_name);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (!cl_data) return 1;
Packit Service 2781ba
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 0, sizeof(cl_mem),    (void*)&in_tex);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 1, sizeof(cl_mem),    (void*)&out_tex);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 2, sizeof(cl_float),  (void*)&coeffs[0]);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 3, sizeof(cl_float),  (void*)&coeffs[1]);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 4, sizeof(cl_float),  (void*)&coeffs[2]);
Packit Service 2781ba
  if (cl_err != CL_SUCCESS) return cl_err;
Packit Service 2781ba
Packit Service 2781ba
  cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
Packit Service 2781ba
                                        cl_data->kernel[0], 1,
Packit Service 2781ba
                                        NULL, &global_worksize, NULL,
Packit Service 2781ba
                                        0, NULL, NULL);
Packit Service 2781ba
  if (cl_err != CL_SUCCESS) return cl_err;
Packit Service 2781ba
Packit Service 2781ba
  return cl_err;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_chant_class_init (GeglChantClass *klass)
Packit Service 2781ba
{
Packit Service 2781ba
  GObjectClass                  *object_class;
Packit Service 2781ba
  GeglOperationClass            *operation_class;
Packit Service 2781ba
  GeglOperationPointFilterClass *point_filter_class;
Packit Service 2781ba
Packit Service 2781ba
  object_class       = G_OBJECT_CLASS (klass);
Packit Service 2781ba
  operation_class    = GEGL_OPERATION_CLASS (klass);
Packit Service 2781ba
  point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
Packit Service 2781ba
Packit Service 2781ba
  object_class->finalize = finalize;
Packit Service 2781ba
  object_class->notify   = notify;
Packit Service 2781ba
Packit Service 2781ba
  operation_class->prepare = prepare;
Packit Service 2781ba
Packit Service 2781ba
  point_filter_class->process = process;
Packit Service 2781ba
  point_filter_class->cl_process = cl_process;
Packit Service 2781ba
Packit Service 2781ba
  operation_class->opencl_support = TRUE;
Packit Service 2781ba
Packit Service 2781ba
  gegl_operation_class_set_keys (operation_class,
Packit Service 2781ba
    "name"       , "gegl:color-temperature",
Packit Service 2781ba
    "categories" , "color",
Packit Service 2781ba
    "description",
Packit Service 2781ba
          _("Allows changing the color temperature of an image."),
Packit Service 2781ba
    NULL);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* Coefficients of rational functions of degree 5 fitted per color channel to
Packit Service 2781ba
 * the linear RGB coordinates of the range 1000K-12000K of the Planckian locus
Packit Service 2781ba
 * with the 20K step. Original CIE-xy data from
Packit Service 2781ba
 *
Packit Service 2781ba
 * http://www.aim-dtp.net/aim/technology/cie_xyz/k2xy.txt
Packit Service 2781ba
 *
Packit Service 2781ba
 * converted to the linear RGB space assuming the ITU-R BT.709-5/sRGB primaries
Packit Service 2781ba
 */
Packit Service 2781ba
static const gfloat rgb_r55[3][12] =
Packit Service 2781ba
{
Packit Service 2781ba
  {
Packit Service 2781ba
     6.9389923563552169e-01,  2.7719388100974670e+03,
Packit Service 2781ba
     2.0999316761104289e+07, -4.8889434162208414e+09,
Packit Service 2781ba
    -1.1899785506796783e+07, -4.7418427686099203e+04,
Packit Service 2781ba
     1.0000000000000000e+00,  3.5434394338546258e+03,
Packit Service 2781ba
    -5.6159353379127791e+05,  2.7369467137870544e+08,
Packit Service 2781ba
     1.6295814912940913e+08,  4.3975072422421846e+05
Packit Service 2781ba
  },
Packit Service 2781ba
  {
Packit Service 2781ba
     9.5417426141210926e-01,  2.2041043287098860e+03,
Packit Service 2781ba
    -3.0142332673634286e+06, -3.5111986367681120e+03,
Packit Service 2781ba
    -5.7030969525354260e+00,  6.1810926909962016e-01,
Packit Service 2781ba
     1.0000000000000000e+00,  1.3728609973644000e+03,
Packit Service 2781ba
     1.3099184987576159e+06, -2.1757404458816318e+03,
Packit Service 2781ba
    -2.3892456292510311e+00,  8.1079012401293249e-01
Packit Service 2781ba
  },
Packit Service 2781ba
  {
Packit Service 2781ba
    -7.1151622540856201e+10,  3.3728185802339764e+16,
Packit Service 2781ba
    -7.9396187338868539e+19,  2.9699115135330123e+22,
Packit Service 2781ba
    -9.7520399221734228e+22, -2.9250107732225114e+20,
Packit Service 2781ba
     1.0000000000000000e+00,  1.3888666482167408e+16,
Packit Service 2781ba
     2.3899765140914549e+19,  1.4583606312383295e+23,
Packit Service 2781ba
     1.9766018324502894e+22,  2.9395068478016189e+18
Packit Service 2781ba
  }
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
#endif