|
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
|