1/* 2 This file is part of darktable, 3 copyright (c) 2016 johannes hanika. 4 copyright (c) 2016 Ulrich Pegelow. 5 6 darktable is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 darktable is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with darktable. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "color_conversion.h" 21#include "rgb_norms.h" 22 23/* we use this exp approximation to maintain full identity with cpu path */ 24float 25fast_expf(const float x) 26{ 27 // meant for the range [-100.0f, 0.0f]. largest error ~ -0.06 at 0.0f. 28 // will get _a_lot_ worse for x > 0.0f (9000 at 10.0f).. 29 const int i1 = 0x3f800000u; 30 // e^x, the comment would be 2^x 31 const int i2 = 0x402DF854u;//0x40000000u; 32 // const int k = CLAMPS(i1 + x * (i2 - i1), 0x0u, 0x7fffffffu); 33 // without max clamping (doesn't work for large x, but is faster): 34 const int k0 = i1 + x * (i2 - i1); 35 union { 36 float f; 37 int k; 38 } u; 39 u.k = k0 > 0 ? k0 : 0; 40 return u.f; 41} 42 43/* 44 Primary LUT lookup. Measures the luminance of a given pixel using a selectable function, looks up that 45 luminance in the configured basecurve, and then scales each channel by the result. 46 47 Doing it this way avoids the color shifts documented as being possible in the legacy basecurve approach. 48 49 Also applies a multiplier prior to lookup in order to support fusion. The idea of doing this here is to 50 emulate the original use case of enfuse, which was to fuse multiple JPEGs from a camera that was set up 51 for exposure bracketing, and which may have had a camera-specific base curve applied. 52*/ 53kernel void 54basecurve_lut(read_only image2d_t in, write_only image2d_t out, const int width, const int height, 55 const float mul, read_only image2d_t table, constant float *a, const int preserve_colors, 56 constant dt_colorspaces_iccprofile_info_cl_t *profile_info, read_only image2d_t lut, 57 const int use_work_profile) 58{ 59 const int x = get_global_id(0); 60 const int y = get_global_id(1); 61 62 if(x >= width || y >= height) return; 63 64 float4 pixel = read_imagef(in, sampleri, (int2)(x, y)); 65 66 float ratio = 1.f; 67 const float lum = mul * dt_rgb_norm(pixel, preserve_colors, use_work_profile, profile_info, lut); 68 if(lum > 0.f) 69 { 70 const float curve_lum = lookup_unbounded(table, lum, a); 71 ratio = mul * curve_lum / lum; 72 } 73 pixel.xyz *= ratio; 74 pixel = fmax(pixel, 0.f); 75 76 write_imagef (out, (int2)(x, y), pixel); 77} 78 79 80kernel void 81basecurve_zero(write_only image2d_t out, const int width, const int height) 82{ 83 const int x = get_global_id(0); 84 const int y = get_global_id(1); 85 86 if(x >= width || y >= height) return; 87 88 write_imagef (out, (int2)(x, y), (float4)0.0f); 89} 90 91/* 92 Original basecurve implementation. Applies a LUT on a per-channel basis which can cause color shifts. 93 94 These can be undesirable (skin tone shifts), or sometimes may be desired (fiery sunset). Continue to allow 95 the "old" method but don't make it the default, both for backwards compatibility and for those who are willing 96 to take the risks of "artistic" impacts on their image. 97*/ 98kernel void 99basecurve_legacy_lut(read_only image2d_t in, write_only image2d_t out, const int width, const int height, 100 const float mul, read_only image2d_t table, constant float *a) 101{ 102 const int x = get_global_id(0); 103 const int y = get_global_id(1); 104 105 if(x >= width || y >= height) return; 106 107 float4 pixel = read_imagef(in, sampleri, (int2)(x, y)); 108 109 // apply ev multiplier and use lut or extrapolation: 110 pixel.x = lookup_unbounded(table, mul * pixel.x, a); 111 pixel.y = lookup_unbounded(table, mul * pixel.y, a); 112 pixel.z = lookup_unbounded(table, mul * pixel.z, a); 113 pixel = fmax(pixel, 0.f); 114 write_imagef (out, (int2)(x, y), pixel); 115} 116 117kernel void 118basecurve_compute_features(read_only image2d_t in, write_only image2d_t out, const int width, const int height) 119{ 120 const int x = get_global_id(0); 121 const int y = get_global_id(1); 122 123 if(x >= width || y >= height) return; 124 125 float4 value = read_imagef(in, sampleri, (int2)(x, y)); 126 127 const float ma = max(value.x, max(value.y, value.z)); 128 const float mi = min(value.x, min(value.y, value.z)); 129 130 const float sat = 0.1f + 0.1f * (ma - mi) / max(1.0e-4f, ma); 131 value.w = sat; 132 133 const float c = 0.54f; 134 135 float v = fabs(value.x - c); 136 v = max(fabs(value.y - c), v); 137 v = max(fabs(value.z - c), v); 138 139 const float var = 0.5f; 140 const float e = 0.2f + fast_expf(-v * v / (var * var)); 141 142 value.w *= e; 143 144 write_imagef (out, (int2)(x, y), value); 145} 146 147constant float gw[5] = { 1.0f/16.0f, 4.0f/16.0f, 6.0f/16.0f, 4.0f/16.0f, 1.0f/16.0f }; 148 149kernel void 150basecurve_blur_h(read_only image2d_t in, write_only image2d_t out, 151 const int width, const int height) 152{ 153 const int x = get_global_id(0); 154 const int y = get_global_id(1); 155 156 if(x >= width || y >= height) return; 157 158 const int rad = 2; 159 constant float *w = gw + rad; 160 161 float4 sum = (float4)0.0f; 162 163 for (int i = -rad; i <= rad; i++) 164 { 165 const int xx = min(max(-x - i, x + i), width - (x + i - width + 1)); 166 sum += read_imagef(in, sampleri, (int2)(xx, y)) * w[i]; 167 } 168 169 write_imagef (out, (int2)(x, y), sum); 170} 171 172 173kernel void 174basecurve_blur_v(read_only image2d_t in, write_only image2d_t out, 175 const int width, const int height) 176{ 177 const int x = get_global_id(0); 178 const int y = get_global_id(1); 179 180 181 if(x >= width || y >= height) return; 182 183 const int rad = 2; 184 constant float *w = gw + rad; 185 186 float4 sum = (float4)0.0f; 187 188 for (int i = -rad; i <= rad; i++) 189 { 190 const int yy = min(max(-y - i, y + i), height - (y + i - height + 1)); 191 sum += read_imagef(in, sampleri, (int2)(x, yy)) * w[i]; 192 } 193 194 write_imagef (out, (int2)(x, y), sum); 195} 196 197kernel void 198basecurve_expand(read_only image2d_t in, write_only image2d_t out, const int width, const int height) 199{ 200 const int x = get_global_id(0); 201 const int y = get_global_id(1); 202 203 if(x >= width || y >= height) return; 204 205 // fill numbers in even pixels, zero odd ones 206 float4 pixel = (x % 2 == 0 && y % 2 == 0) ? 4.0f * read_imagef(in, sampleri, (int2)(x / 2, y / 2)) : (float4)0.0f; 207 208 write_imagef (out, (int2)(x, y), pixel); 209} 210 211kernel void 212basecurve_reduce(read_only image2d_t in, write_only image2d_t out, const int width, const int height) 213{ 214 const int x = get_global_id(0); 215 const int y = get_global_id(1); 216 217 if(x >= width || y >= height) return; 218 219 float4 pixel = read_imagef(in, sampleri, (int2)(2 * x, 2 * y)); 220 221 write_imagef (out, (int2)(x, y), pixel); 222} 223 224kernel void 225basecurve_detail(read_only image2d_t in, read_only image2d_t det, write_only image2d_t out, const int width, const int height) 226{ 227 const int x = get_global_id(0); 228 const int y = get_global_id(1); 229 230 if(x >= width || y >= height) return; 231 232 float4 input = read_imagef(in, sampleri, (int2)(x, y)); 233 float4 detail = read_imagef(det, sampleri, (int2)(x, y)); 234 235 write_imagef (out, (int2)(x, y), input - detail); 236} 237 238kernel void 239basecurve_adjust_features(read_only image2d_t in, read_only image2d_t det, write_only image2d_t out, const int width, const int height) 240{ 241 const int x = get_global_id(0); 242 const int y = get_global_id(1); 243 244 if(x >= width || y >= height) return; 245 246 float4 input = read_imagef(in, sampleri, (int2)(x, y)); 247 float4 detail = read_imagef(det, sampleri, (int2)(x, y)); 248 249 input.w *= 0.1f + sqrt(detail.x * detail.x + detail.y * detail.y + detail.z * detail.z); 250 251 write_imagef (out, (int2)(x, y), input); 252} 253 254kernel void 255basecurve_blend_gaussian(read_only image2d_t in, read_only image2d_t col, write_only image2d_t out, const int width, const int height) 256{ 257 const int x = get_global_id(0); 258 const int y = get_global_id(1); 259 260 if(x >= width || y >= height) return; 261 262 float4 comb = read_imagef(in, sampleri, (int2)(x, y)); 263 float4 collect = read_imagef(col, sampleri, (int2)(x, y)); 264 265 comb.xyz += collect.xyz * collect.w; 266 comb.w += collect.w; 267 268 write_imagef (out, (int2)(x, y), comb); 269} 270 271kernel void 272basecurve_blend_laplacian(read_only image2d_t in, read_only image2d_t col, read_only image2d_t tmp, write_only image2d_t out, 273 const int width, const int height) 274{ 275 const int x = get_global_id(0); 276 const int y = get_global_id(1); 277 278 if(x >= width || y >= height) return; 279 280 float4 comb = read_imagef(in, sampleri, (int2)(x, y)); 281 float4 collect = read_imagef(col, sampleri, (int2)(x, y)); 282 float4 temp = read_imagef(tmp, sampleri, (int2)(x, y)); 283 284 comb.xyz += (collect.xyz - temp.xyz) * collect.w; 285 comb.w += collect.w; 286 287 write_imagef (out, (int2)(x, y), comb); 288} 289 290kernel void 291basecurve_normalize(read_only image2d_t in, write_only image2d_t out, const int width, const int height) 292{ 293 const int x = get_global_id(0); 294 const int y = get_global_id(1); 295 296 if(x >= width || y >= height) return; 297 298 float4 comb = read_imagef(in, sampleri, (int2)(x, y)); 299 300 comb.xyz /= (comb.w > 1.0e-8f) ? comb.w : 1.0f; 301 302 write_imagef (out, (int2)(x, y), comb); 303} 304 305kernel void 306basecurve_reconstruct(read_only image2d_t in, read_only image2d_t tmp, write_only image2d_t out, const int width, const int height) 307{ 308 const int x = get_global_id(0); 309 const int y = get_global_id(1); 310 311 if(x >= width || y >= height) return; 312 313 float4 comb = read_imagef(in, sampleri, (int2)(x, y)); 314 float4 temp = read_imagef(tmp, sampleri, (int2)(x, y)); 315 316 comb += temp; 317 318 write_imagef (out, (int2)(x, y), comb); 319} 320 321kernel void 322basecurve_finalize(read_only image2d_t in, read_only image2d_t comb, write_only image2d_t out, const int width, const int height) 323{ 324 const int x = get_global_id(0); 325 const int y = get_global_id(1); 326 327 if(x >= width || y >= height) return; 328 329 float4 pixel = fmax(read_imagef(comb, sampleri, (int2)(x, y)), 0.f); 330 pixel.w = read_imagef(in, sampleri, (int2)(x, y)).w; 331 332 write_imagef (out, (int2)(x, y), pixel); 333} 334