1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : LDR ToneMapper <http://zynaddsubfx.sourceforge.net/other/tonemapping>.
9
* Copyright (C) 2009 by Nasca Octavian Paul <zynaddsubfx at yahoo dot com>
10
* Copyright (C) 2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
12
* This program is free software; you can redistribute it
13
* and/or modify it under the terms of the GNU General
14
* Public License as published by the Free Software Foundation;
15
* either version 2, or (at your option)
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* ============================================================ */
33
#include "ToneMappingFloat.h"
35
namespace DigikamLocalContrastImagesPlugin
38
ToneMappingFloat::ToneMappingFloat()
41
par.info_fast_mode = false;
44
ToneMappingFloat::~ToneMappingFloat()
48
void ToneMappingFloat::process_rgb_image(REALTYPE *img, int sizex, int sizey)
50
update_preprocessed_values();
52
int size = sizex*sizey;
53
REALTYPE *blurimage = new REALTYPE[size];
54
REALTYPE *srcimg = new REALTYPE[size*3];
56
for (int i=0 ; i < (size*3) ; i++)
59
if (par.stretch_contrast)
61
stretch_contrast(img,size*3);
66
for (int nstage=0 ; !par.cancel() && (nstage < TONEMAPPING_MAX_STAGES) ; nstage++)
68
if (par.stage[nstage].enabled)
70
// compute the desatured image
74
for (int i=0 ; !par.cancel() && (i < size) ; i++)
76
blurimage[i] = (REALTYPE)((img[pos]+img[pos+1]+img[pos+2])/3.0);
80
current_process_power_value = par.get_power(nstage);
84
inplace_blur(blurimage, sizex,sizey, par.get_blur(nstage));
88
for (int i=0 ; !par.cancel() && (i<size) ; i++)
90
REALTYPE src_r = img[pos];
91
REALTYPE src_g = img[pos+1];
92
REALTYPE src_b = img[pos+2];
94
REALTYPE blur = blurimage[i];
96
REALTYPE dest_r = func(src_r,blur);
97
REALTYPE dest_g = func(src_g,blur);
98
REALTYPE dest_b = func(src_b,blur);
107
par.postProgress(30 + nstage*10);
110
int high_saturation_value = 100-par.high_saturation;
111
int low_saturation_value = 100-par.low_saturation;
113
if ((par.high_saturation != 100) || (par.low_saturation != 100))
117
for (int i=0 ; !par.cancel() && (i < size) ; i++)
119
REALTYPE src_h, src_s, src_v;
120
REALTYPE dest_h, dest_s, dest_v;
121
rgb2hsv(srcimg[pos], srcimg[pos+1], srcimg[pos+2], src_h, src_s, src_v);
122
rgb2hsv(img[pos], img[pos+1], img[pos+2], dest_h, dest_s, dest_v);
124
REALTYPE dest_saturation = (REALTYPE)((src_s*high_saturation_value+dest_s*(100.0-high_saturation_value))*0.01);
127
REALTYPE s1 = (REALTYPE)(dest_saturation*src_v/(dest_v+1.0/255.0));
128
dest_saturation = (REALTYPE)((low_saturation_value*s1+par.low_saturation*dest_saturation)*0.01);
131
hsv2rgb(dest_h, dest_saturation, dest_v, img[pos], img[pos+1], img[pos+2]);
137
par.postProgress(70);
139
// Unsharp Mask filter
141
if (par.unsharp_mask.enabled)
143
REALTYPE *val = new REALTYPE[size];
145
// compute the desatured image
149
for (int i=0 ; !par.cancel() && (i < size) ; i++)
151
val[i] = blurimage[i] = (REALTYPE)((img[pos]+img[pos+1]+img[pos+2])/3.0);
152
//val[i] = blurimage[i] = (REALTYPE)(max3(img[pos],img[pos+1],img[pos+2]));
156
REALTYPE blur_value = par.get_unsharp_mask_blur();
157
inplace_blur(blurimage, sizex, sizey, blur_value);
160
REALTYPE pow = (REALTYPE)(2.5*par.get_unsharp_mask_power());
161
REALTYPE threshold = (REALTYPE)(par.unsharp_mask.threshold*pow/250.0);
162
REALTYPE threshold2 = threshold/2;
164
for (int i=0 ; !par.cancel() && (i < size) ; i++)
166
REALTYPE dval = (val[i]-blurimage[i])*pow;
167
REALTYPE abs_dval = fabs(dval);
168
if (abs_dval < threshold)
170
if (abs_dval > threshold2)
172
bool sign = (dval < 0.0);
173
dval = (REALTYPE)((abs_dval-threshold2)*2.0);
174
if (sign) dval =- dval;
182
REALTYPE r = img[pos] +dval;
183
REALTYPE g = img[pos+1]+dval;
184
REALTYPE b = img[pos+2]+dval;
206
par.postProgress(80);
209
void ToneMappingFloat::update_preprocessed_values()
211
par.postProgress(20);
214
void ToneMappingFloat::process_16bit_rgb_image(unsigned short int *img, int sizex, int sizey)
216
int size = sizex*sizey;
217
REALTYPE *tmpimage = new REALTYPE[size*3];
218
const float inv_65536 = 1.0/65536.0;
220
for (int i=0 ; !par.cancel() && (i < size*3) ; i++)
222
//convert to floating point
223
tmpimage[i] = (REALTYPE)(img[i]/65535.0);
226
process_rgb_image(tmpimage, sizex, sizey);
228
//convert back to 8 bits (with dithering)
231
for (int i=0 ; !par.cancel() && (i < size) ; i++)
233
REALTYPE dither = ((rand()/65536)%65536)*inv_65536;
234
img[pos] = (int)(tmpimage[pos] *65535.0+dither);
235
img[pos+1] = (int)(tmpimage[pos+1]*65535.0+dither);
236
img[pos+2] = (int)(tmpimage[pos+2]*65535.0+dither);
242
par.postProgress(90);
245
void ToneMappingFloat::process_8bit_rgb_image(unsigned char *img, int sizex, int sizey)
247
int size = sizex*sizey;
248
REALTYPE *tmpimage = new REALTYPE[size*3];
249
const float inv_256 = 1.0/256.0;
251
for (int i=0 ; !par.cancel() && (i < size*3) ; i++)
253
//convert to floating point
254
tmpimage[i] = (REALTYPE)(img[i]/255.0);
257
process_rgb_image(tmpimage, sizex, sizey);
259
//convert back to 8 bits (with dithering)
262
for (int i=0 ; !par.cancel() && (i < size) ; i++)
264
REALTYPE dither = ((rand()/256)%256)*inv_256;
265
img[pos] = (int)(tmpimage[pos] *255.0+dither);
266
img[pos+1] = (int)(tmpimage[pos+1]*255.0+dither);
267
img[pos+2] = (int)(tmpimage[pos+2]*255.0+dither);
272
par.postProgress(90);
275
void ToneMappingFloat::inplace_blur(REALTYPE *data, int sizex, int sizey, REALTYPE blur)
277
blur /= preview_zoom;
279
if (blur < 0.3) return;
281
REALTYPE a = (REALTYPE)(exp(log(0.25)/blur));
283
if ((a <= 0.0) || (a >= 1.0)) return;
286
REALTYPE denormal_remove = (REALTYPE)(1e-15);
288
for (int stage=0 ; !par.cancel() && (stage < 2) ; stage++)
290
for (int y=0 ; !par.cancel() && (y < sizey) ; y++)
293
REALTYPE old = data[pos];
296
for (int x=1 ; !par.cancel() && (x < sizex) ; x++)
298
old = (data[pos]*(1-a)+old*a)+denormal_remove;
303
pos = y*sizex+sizex-1;
305
for (int x=1 ; !par.cancel() && (x < sizex) ; x++)
307
old = (data[pos]*(1-a)+old*a)+denormal_remove;
313
for (int x=0 ; !par.cancel() && (x < sizex) ; x++)
316
REALTYPE old = data[pos];
318
for (int y=1 ; !par.cancel() && (y < sizey) ; y++)
320
old = (data[pos]*(1-a)+old*a)+denormal_remove;
325
pos = x+sizex*(sizey-1);
327
for (int y=1 ; !par.cancel() && (y < sizey) ; y++)
329
old = (data[pos]*(1-a)+old*a)+denormal_remove;
337
void ToneMappingFloat::stretch_contrast(REALTYPE *data, int datasize)
339
//stretch the contrast
340
const unsigned int histogram_size=256;
341
//first, we compute the histogram
342
unsigned int histogram[histogram_size];
344
for (unsigned int i=0 ; i < histogram_size ; i++) histogram[i] = 0;
346
for (unsigned int i=0 ; !par.cancel() && (i < (unsigned int)datasize) ; i++)
348
int m = (int)(data[i]*(histogram_size-1));
350
if (m > (int)(histogram_size-1)) m = histogram_size-1;
354
//I want to strip the lowest and upper 0.1 procents (in the histogram) of the pixels
355
int min = 0,max = 255;
356
unsigned int desired_sum = datasize/1000;
357
unsigned int sum_min = 0;
358
unsigned int sum_max = 0;
360
for (unsigned int i=0 ; !par.cancel() && (i < histogram_size) ; i++)
362
sum_min += histogram[i];
363
if (sum_min > desired_sum)
370
for (int i = histogram_size-1 ; !par.cancel() && (i >= 0) ; i--)
372
sum_max += histogram[i];
373
if (sum_max > desired_sum)
386
REALTYPE min_src_val = (REALTYPE)(min/255.0);
387
REALTYPE max_src_val = (REALTYPE)(max/255.0);
389
for (int i=0 ; !par.cancel() && (i < datasize) ; i++)
391
//stretch the contrast
392
REALTYPE x = data[i];
393
x = (x-min_src_val)/(max_src_val-min_src_val);
394
if (x < 0.0) x = 0.0;
395
if (x > 1.0) x = 1.0;
400
} // namespace DigikamNoiseReductionImagesPlugin