1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : Wavelets Noise Reduction threaded image filter.
8
* This filter work in YCrCb color space.
10
* Copyright (C) 2005-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
11
* Copyright (C) 2008 by Marco Rossini <marco dot rossini at gmx dot net>
13
* This program is free software; you can redistribute it
14
* and/or modify it under the terms of the GNU General
15
* Public License as published by the Free Software Foundation;
16
* either version 2, or (at your option)
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* ============================================================ */
26
#include "waveletsnr.h"
36
#include "dimgimagefilters.h"
47
for (int c = 0 ; c < 3; c++)
57
WaveletsNRContainer settings;
60
WaveletsNR::WaveletsNR(DImg *orgImage, QObject *parent, const WaveletsNRContainer& settings)
61
: DImgThreadedFilter(orgImage, parent, "WaveletsNR"),
64
d->settings = settings;
69
WaveletsNR::~WaveletsNR()
74
void WaveletsNR::filterImage()
79
int width = m_orgImage.width();
80
int height = m_orgImage.height();
81
float clip = m_orgImage.sixteenBit() ? 65535.0 : 255.0;
85
for (int c = 0; c < 3; c++)
86
d->fimg[c] = new float[width * height];
88
d->buffer[1] = new float[width * height];
89
d->buffer[2] = new float[width * height];
91
// Read the full image and convert pixel values to float [0,1].
95
for (int y = 0; !m_cancel && (y < height); y++)
97
for (int x = 0; !m_cancel && (x < width); x++)
99
col = m_orgImage.getPixelColor(x, y);
100
d->fimg[0][j] = col.red() / clip;
101
d->fimg[1][j] = col.green() / clip;
102
d->fimg[2][j] = col.blue() / clip;
109
// do colour model conversion sRGB[0,1] -> YCrCb.
113
srgb2ycbcr(d->fimg, width * height);
118
// denoise the channels individually
120
for (int c = 0; !m_cancel && (c < 3); c++)
122
d->buffer[0] = d->fimg[c];
124
if (d->settings.thresholds[c] > 0.0)
126
waveletDenoise(d->buffer, width, height, d->settings.thresholds[c], d->settings.softness[c]);
128
progress = (int) (30.0 + ((double)c * 60.0) / 4);
129
if ( progress%5 == 0 )
130
postProgress( progress );
134
// Retransform the image data to sRGB[0,1].
138
ycbcr2srgb(d->fimg, width * height);
145
for (int c = 0; !m_cancel && (c < 3); c++)
147
for (int i = 0; i < width * height; i++)
149
d->fimg[c][i] = qBound(0.0F, d->fimg[c][i] * clip, clip);
155
// Write back the full image and convert pixel values from float [0,1].
159
for (int y = 0; !m_cancel && (y < height); y++)
161
for (int x = 0; x < width; x++)
163
col.setRed( (int)(d->fimg[0][j] + 0.5) );
164
col.setGreen( (int)(d->fimg[1][j] + 0.5) );
165
col.setBlue( (int)(d->fimg[2][j] + 0.5) );
166
col.setAlpha( m_orgImage.getPixelColor(x, y).alpha() );
169
m_destImage.setPixelColor(x, y, col);
177
for (int c = 0; c < 3; c++)
178
delete [] d->fimg[c];
180
delete [] d->buffer[1];
181
delete [] d->buffer[2];
184
// -- Wavelets denoise methods -----------------------------------------------------------
186
void WaveletsNR::waveletDenoise(float* fimg[3], unsigned int width, unsigned int height,
187
float threshold, double softness)
189
float *temp=0, thold;
190
unsigned int i, lev, lpass, hpass, size, col, row;
192
unsigned int samples[5];
194
size = width * height;
195
temp = new float[qMax(width, height)];
198
for (lev = 0; !m_cancel && (lev < 5); lev++)
200
lpass = ((lev & 1) + 1);
201
for (row = 0; !m_cancel && (row < height); row++)
203
hatTransform(temp, fimg[hpass] + row * width, 1, width, 1 << lev);
204
for (col = 0; col < width; col++)
206
fimg[lpass][row * width + col] = temp[col] * 0.25;
210
for (col = 0; !m_cancel && (col < width); col++)
212
hatTransform(temp, fimg[lpass] + col, width, height, 1 << lev);
213
for (row = 0; row < height; row++)
215
fimg[lpass][row * width + col] = temp[row] * 0.25;
219
thold = 5.0 / (1 << 6) * exp (-2.6 * sqrt (lev + 1.0)) * 0.8002 / exp (-2.6);
221
// initialize stdev values for all intensities
223
stdev[0] = stdev[1] = stdev[2] = stdev[3] = stdev[4] = 0.0;
224
samples[0] = samples[1] = samples[2] = samples[3] = samples[4] = 0;
226
// calculate stdevs for all intensities
228
for (i = 0; !m_cancel && (i < size); i++)
230
fimg[hpass][i] -= fimg[lpass][i];
232
if (fimg[hpass][i] < thold && fimg[hpass][i] > -thold)
234
if (fimg[lpass][i] > 0.8)
236
stdev[4] += fimg[hpass][i] * fimg[hpass][i];
239
else if (fimg[lpass][i] > 0.6)
241
stdev[3] += fimg[hpass][i] * fimg[hpass][i];
244
else if (fimg[lpass][i] > 0.4)
246
stdev[2] += fimg[hpass][i] * fimg[hpass][i];
249
else if (fimg[lpass][i] > 0.2)
251
stdev[1] += fimg[hpass][i] * fimg[hpass][i];
256
stdev[0] += fimg[hpass][i] * fimg[hpass][i];
262
stdev[0] = sqrt(stdev[0] / (samples[0] + 1));
263
stdev[1] = sqrt(stdev[1] / (samples[1] + 1));
264
stdev[2] = sqrt(stdev[2] / (samples[2] + 1));
265
stdev[3] = sqrt(stdev[3] / (samples[3] + 1));
266
stdev[4] = sqrt(stdev[4] / (samples[4] + 1));
270
for (i = 0; !m_cancel && (i < size); i++)
272
if (fimg[lpass][i] > 0.8)
274
thold = threshold * stdev[4];
276
else if (fimg[lpass][i] > 0.6)
278
thold = threshold * stdev[3];
280
else if (fimg[lpass][i] > 0.4)
282
thold = threshold * stdev[2];
284
else if (fimg[lpass][i] > 0.2)
286
thold = threshold * stdev[1];
290
thold = threshold * stdev[0];
293
if (fimg[hpass][i] < -thold)
294
fimg[hpass][i] += thold - thold * softness;
295
else if (fimg[hpass][i] > thold)
296
fimg[hpass][i] -= thold - thold * softness;
298
fimg[hpass][i] *= softness;
301
fimg[0][i] += fimg[hpass][i];
307
for (i = 0; !m_cancel && (i < size); i++)
308
fimg[0][i] = fimg[0][i] + fimg[lpass][i];
313
void WaveletsNR::hatTransform (float* temp, float* base, int st, int size, int sc)
317
for (i = 0; i < sc; i++)
318
temp[i] = 2 * base[st * i] + base[st * (sc - i)] + base[st * (i + sc)];
320
for (; i + sc < size; i++)
321
temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (i + sc)];
323
for (; i < size; i++)
324
temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (2 * size - 2 - (i + sc))];
327
// -- Color Space conversion methods --------------------------------------------------
329
void WaveletsNR::srgb2ycbcr(float** fimg, int size)
331
/* using JPEG conversion here - expecting all channels to be in [0:255] range */
334
for (int i = 0; i < size; i++)
336
y = 0.2990 * fimg[0][i] + 0.5870 * fimg[1][i] + 0.1140 * fimg[2][i];
337
cb = -0.1687 * fimg[0][i] - 0.3313 * fimg[1][i] + 0.5000 * fimg[2][i] + 0.5;
338
cr = 0.5000 * fimg[0][i] - 0.4187 * fimg[1][i] - 0.0813 * fimg[2][i] + 0.5;
345
void WaveletsNR::ycbcr2srgb(float** fimg, int size)
347
/* using JPEG conversion here - expecting all channels to be in [0:255] range */
350
for (int i = 0; i < size; i++)
352
r = fimg[0][i] + 1.40200 * (fimg[2][i] - 0.5);
353
g = fimg[0][i] - 0.34414 * (fimg[1][i] - 0.5) - 0.71414 * (fimg[2][i] - 0.5);
354
b = fimg[0][i] + 1.77200 * (fimg[1][i] - 0.5);
361
void WaveletsNR::srgb2xyz(float** fimg, int size)
363
/* fimg in [0:1], sRGB */
366
for (int i = 0; i < size; i++)
368
/* scaling and gamma correction (approximate) */
369
fimg[0][i] = pow(fimg[0][i], (float)2.2);
370
fimg[1][i] = pow(fimg[1][i], (float)2.2);
371
fimg[2][i] = pow(fimg[2][i], (float)2.2);
373
/* matrix RGB -> XYZ, with D65 reference white (www.brucelindbloom.com) */
374
x = 0.412424 * fimg[0][i] + 0.357579 * fimg[1][i] + 0.180464 * fimg[2][i];
375
y = 0.212656 * fimg[0][i] + 0.715158 * fimg[1][i] + 0.0721856 * fimg[2][i];
376
z = 0.0193324 * fimg[0][i] + 0.119193 * fimg[1][i] + 0.950444 * fimg[2][i];
379
x = 0.412424 * fimg[0][i] + 0.212656 * fimg[1][i] + 0.0193324 * fimg[2][i];
380
y = 0.357579 * fimg[0][i] + 0.715158 * fimg[1][i] + 0.119193 * fimg[2][i];
381
z = 0.180464 * fimg[0][i] + 0.0721856 * fimg[1][i] + 0.950444 * fimg[2][i];
390
void WaveletsNR::xyz2srgb(float** fimg, int size)
394
for (int i = 0; i < size; i++)
396
/* matrix RGB -> XYZ, with D65 reference white (www.brucelindbloom.com) */
397
r = 3.24071 * fimg[0][i] - 1.53726 * fimg[1][i] - 0.498571 * fimg[2][i];
398
g = -0.969258 * fimg[0][i] + 1.87599 * fimg[1][i] + 0.0415557 * fimg[2][i];
399
b = 0.0556352 * fimg[0][i] - 0.203996 * fimg[1][i] + 1.05707 * fimg[2][i];
402
r = 3.24071 * fimg[0][i] - 0.969258 * fimg[1][i]
403
+ 0.0556352 * fimg[2][i];
404
g = -1.53726 * fimg[0][i] + 1.87599 * fimg[1][i]
405
- 0.203996 * fimg[2][i];
406
b = -0.498571 * fimg[0][i] + 0.0415557 * fimg[1][i]
407
+ 1.05707 * fimg[2][i];
410
/* scaling and gamma correction (approximate) */
411
r = r < 0 ? 0 : pow(r, (float)(1.0 / 2.2));
412
g = g < 0 ? 0 : pow(g, (float)(1.0 / 2.2));
413
b = b < 0 ? 0 : pow(b, (float)(1.0 / 2.2));
421
void WaveletsNR::lab2srgb(float** fimg, int size)
425
for (int i = 0; i < size; i++)
427
/* convert back to normal LAB */
428
fimg[0][i] = (fimg[0][i] - 0 * 16 * 27 / 24389.0) * 116;
429
fimg[1][i] = (fimg[1][i] - 0.5) * 500 * 2;
430
fimg[2][i] = (fimg[2][i] - 0.5) * 200 * 2.2;
433
y = (fimg[0][i] + 16) / 116;
434
z = y - fimg[2][i] / 200.0;
435
x = fimg[1][i] / 500.0 + y;
438
if (x * x * x > 216 / 24389.0)
441
x = (116 * x - 16) * 27 / 24389.0;
442
if (fimg[0][i] > 216 / 27.0)
445
/*y = fimg[0][i] * 27 / 24389.0;*/
446
y = (116 * y - 16) * 27 / 24389.0;
447
if (z * z * z > 216 / 24389.0)
450
z = (116 * z - 16) * 27 / 24389.0;
452
/* white reference */
453
fimg[0][i] = x * 0.95047;
455
fimg[2][i] = z * 1.08883;
458
xyz2srgb(fimg, size);
461
void WaveletsNR::srgb2lab(float** fimg, int size)
465
srgb2xyz(fimg, size);
467
for (int i = 0; i < size; i++)
469
/* reference white */
470
fimg[0][i] /= 0.95047;
471
/* (just for completeness)
472
fimg[1][i] /= 1.00000; */
473
fimg[2][i] /= 1.08883;
476
if (fimg[0][i] > 216.0 / 24389.0)
478
fimg[0][i] = pow(fimg[0][i], (float)(1.0 / 3.0));
482
fimg[0][i] = (24389.0 * fimg[0][i] / 27.0 + 16.0) / 116.0;
485
if (fimg[1][i] > 216.0 / 24389.0)
487
fimg[1][i] = pow(fimg[1][i], (float)(1.0 / 3.0));
491
fimg[1][i] = (24389 * fimg[1][i] / 27.0 + 16.0) / 116.0;
494
if (fimg[2][i] > 216.0 / 24389.0)
496
fimg[2][i] = (float)pow(fimg[2][i], (float)(1.0 / 3.0));
500
fimg[2][i] = (24389.0 * fimg[2][i] / 27.0 + 16.0) / 116.0;
503
l = 116 * fimg[1][i] - 16;
504
a = 500 * (fimg[0][i] - fimg[1][i]);
505
b = 200 * (fimg[1][i] - fimg[2][i]);
506
fimg[0][i] = l / 116.0; /* + 16 * 27 / 24389.0; */
507
fimg[1][i] = a / 500.0 / 2.0 + 0.5;
508
fimg[2][i] = b / 200.0 / 2.2 + 0.5;
515
} // namespace Digikam