1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/*
This file is part of darktable,
copyright (c) 2019 edgardo hoszowski.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
darktable is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with darktable. If not, see <http://www.gnu.org/licenses/>.
*/
#include "color_conversion.h"
#include "rgb_norms.h"
float get_gamma(const float x, const float gamma)
{
return dtcl_pow(x, gamma);
}
float get_lut_gamma(const float x, const float gamma, read_only image2d_t lut)
{
if(x > 1.0f)
{
return get_gamma(x, gamma);
}
else
{
const int xi = clamp((int)(x * 0x10000ul), 0, 0xffff);
const int2 p = (int2)((xi & 0xff), (xi >> 8));
return read_imagef(lut, sampleri, p).x;
}
}
float get_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey)
{
return dtcl_pow(x * inv_middle_grey, contrast) * middle_grey;
}
float get_lut_contrast(const float x, const float contrast, const float middle_grey, const float inv_middle_grey, read_only image2d_t lut)
{
if(x > 1.0f)
{
return get_contrast(x, contrast, middle_grey, inv_middle_grey);
}
else
{
const int xi = clamp((int)(x * 0x10000ul), 0, 0xffff);
const int2 p = (int2)((xi & 0xff), (xi >> 8));
return read_imagef(lut, sampleri, p).x;
}
}
float hlcurve(const float level, const float hlcomp, const float hlrange)
{
if(hlcomp > 0.0f)
{
float val = level + (hlrange - 1.f);
// to avoid division by zero
if(val == 0.0f)
{
val = 0.000001f;
}
float Y = val / hlrange;
Y *= hlcomp;
// to avoid log(<=0)
if(Y <= -1.0f)
{
Y = -.999999f;
}
float R = hlrange / (val * hlcomp);
return log1p(Y) * R;
}
else
{
return 1.f;
}
}
kernel void
basicadj(read_only image2d_t in, write_only image2d_t out, const int width, const int height,
read_only image2d_t lut_gamma, read_only image2d_t lut_contrast,
const float black_point, const float scale,
const int process_gamma, const float gamma,
const int plain_contrast, const int preserve_colors, const float contrast,
const int process_saturation_vibrance, const float saturation, const float vibrance,
const int process_hlcompr, const float hlcomp, const float hlrange,
const float middle_grey, const float inv_middle_grey,
constant dt_colorspaces_iccprofile_info_cl_t *profile_info, read_only image2d_t lut,
const int use_work_profile)
{
const int x = get_global_id(0);
const int y = get_global_id(1);
if(x >= width || y >= height) return;
float4 pixel = read_imagef(in, sampleri, (int2)(x, y));
const float w = pixel.w;
// exposure
pixel = (pixel - black_point) * scale;
// highlight compression
if(process_hlcompr)
{
const float lum = (use_work_profile == 0) ? dt_camera_rgb_luminance(pixel): get_rgb_matrix_luminance(pixel, profile_info, profile_info->matrix_in, lut);
if(lum > 0.f)
{
const float ratio = hlcurve(lum, hlcomp, hlrange);
pixel *= ratio;
}
}
// gamma
if(process_gamma)
{
if(pixel.x > 0.f) pixel.x = get_lut_gamma(pixel.x, gamma, lut_gamma);
if(pixel.y > 0.f) pixel.y = get_lut_gamma(pixel.y, gamma, lut_gamma);
if(pixel.z > 0.f) pixel.z = get_lut_gamma(pixel.z, gamma, lut_gamma);
}
// contrast
if(plain_contrast)
{
if(pixel.x > 0.f) pixel.x = get_lut_contrast(pixel.x, contrast, middle_grey, inv_middle_grey, lut_contrast);
if(pixel.y > 0.f) pixel.y = get_lut_contrast(pixel.y, contrast, middle_grey, inv_middle_grey, lut_contrast);
if(pixel.z > 0.f) pixel.z = get_lut_contrast(pixel.z, contrast, middle_grey, inv_middle_grey, lut_contrast);
}
// contrast (with preserve colors)
if(preserve_colors != DT_RGB_NORM_NONE)
{
float ratio = 1.f;
const float lum = dt_rgb_norm(pixel, preserve_colors, use_work_profile, profile_info, lut);
if(lum > 0.f)
{
const float contrast_lum = dtcl_pow(lum / middle_grey, contrast) * middle_grey;
ratio = contrast_lum / lum;
}
pixel *= ratio;
}
// saturation
if(process_saturation_vibrance)
{
const float average = (pixel.x + pixel.y + pixel.z) / 3;
const float delta = fast_length(pixel - average);
const float P = vibrance * (1 - dtcl_pow(delta, fabs(vibrance)));
pixel = average + (saturation + P) * (pixel - average);
}
pixel.w = w;
write_imagef(out, (int2)(x, y), pixel);
}
|