Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Graphics
digiKam
Commits
c63d1ffd
Commit
c63d1ffd
authored
May 06, 2014
by
Gilles Caulier
🗼
Browse files
NoiseReduction Tool : add support of multicore CPU based on QtConcurrent API.
CCBUGS: 289204
parent
6e7f4a61
Changes
4
Hide whitespace changes
Inline
Side-by-side
NEWS
View file @
c63d1ffd
...
...
@@ -20,6 +20,7 @@ Editor : OilPaint tool support multicore CPU.
Editor : Emboss tool support multicore CPU.
Editor : Raindrop tool support multicore CPU.
Editor : FilmGrain tool support multicore CPU.
Editor : NoiseReduction tool support multicore CPU.
Showfoto : Port of Thumbbar to Qt Model/view.
...
...
imageplugins/TODO
View file @
c63d1ffd
...
...
@@ -33,7 +33,7 @@ filters
/filmgrain DONE DONE DONE DONE
enhance
/noisereductiontool DONE
TO
DO DONE DONE
/noisereductiontool DONE DO
NE
DONE DONE
/sharpentool DONE DONE DONE DONE
/restoration DONE TODO DONE DONE
/blurtool DONE DONE DONE DONE
...
...
libs/dimg/filters/nr/nrfilter.cpp
View file @
c63d1ffd
...
...
@@ -7,7 +7,7 @@
* Description : Wavelets Noise Reduction threaded image filter.
* This filter work in YCrCb color space.
*
* Copyright (C) 2005-201
2
by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2005-201
4
by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2008 by Marco Rossini <marco dot rossini at gmx dot net>
* Copyright (C) 2010 by Martin Klapetek <martin dot klapetek at gmail dot com>
*
...
...
@@ -30,6 +30,10 @@
#include <cmath>
// Qt includes
#include <QtConcurrentRun>
// Local includes
#include "dimg.h"
...
...
@@ -279,17 +283,121 @@ void NRFilter::filterImage()
// -- Wavelets denoise methods -----------------------------------------------------------
void
NRFilter
::
waveletDenoise
(
float
*
const
fimg
[
3
],
unsigned
int
width
,
unsigned
int
height
,
void
NRFilter
::
calculteStdevMultithreaded
(
const
Args
&
prm
)
{
for
(
uint
i
=
prm
.
start
;
runningFlag
()
&&
(
i
<
prm
.
stop
);
++
i
)
{
prm
.
fimg
[
*
prm
.
hpass
][
i
]
-=
prm
.
fimg
[
*
prm
.
lpass
][
i
];
if
(
prm
.
fimg
[
*
prm
.
hpass
][
i
]
<
*
prm
.
thold
&&
prm
.
fimg
[
*
prm
.
hpass
][
i
]
>
-*
prm
.
thold
)
{
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.8
)
{
prm
.
stdev
[
4
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*
prm
.
fimg
[
*
prm
.
hpass
][
i
];
prm
.
samples
[
4
]
++
;
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.6
)
{
prm
.
stdev
[
3
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*
prm
.
fimg
[
*
prm
.
hpass
][
i
];
prm
.
samples
[
3
]
++
;
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.4
)
{
prm
.
stdev
[
2
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*
prm
.
fimg
[
*
prm
.
hpass
][
i
];
prm
.
samples
[
2
]
++
;
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.2
)
{
prm
.
stdev
[
1
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*
prm
.
fimg
[
*
prm
.
hpass
][
i
];
prm
.
samples
[
1
]
++
;
}
else
{
prm
.
stdev
[
0
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*
prm
.
fimg
[
*
prm
.
hpass
][
i
];
prm
.
samples
[
0
]
++
;
}
}
}
}
void
NRFilter
::
thresholdingMultithreaded
(
const
Args
&
prm
)
{
for
(
uint
i
=
prm
.
start
;
runningFlag
()
&&
(
i
<
prm
.
stop
);
++
i
)
{
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.8
)
{
*
prm
.
thold
=
prm
.
threshold
*
prm
.
stdev
[
4
];
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.6
)
{
*
prm
.
thold
=
prm
.
threshold
*
prm
.
stdev
[
3
];
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.4
)
{
*
prm
.
thold
=
prm
.
threshold
*
prm
.
stdev
[
2
];
}
else
if
(
prm
.
fimg
[
*
prm
.
lpass
][
i
]
>
0.2
)
{
*
prm
.
thold
=
prm
.
threshold
*
prm
.
stdev
[
1
];
}
else
{
*
prm
.
thold
=
prm
.
threshold
*
prm
.
stdev
[
0
];
}
if
(
prm
.
fimg
[
*
prm
.
hpass
][
i
]
<
-*
prm
.
thold
)
{
prm
.
fimg
[
*
prm
.
hpass
][
i
]
+=
*
prm
.
thold
-
*
prm
.
thold
*
prm
.
softness
;
}
else
if
(
prm
.
fimg
[
*
prm
.
hpass
][
i
]
>
*
prm
.
thold
)
{
prm
.
fimg
[
*
prm
.
hpass
][
i
]
-=
*
prm
.
thold
-
*
prm
.
thold
*
prm
.
softness
;
}
else
{
prm
.
fimg
[
*
prm
.
hpass
][
i
]
*=
prm
.
softness
;
}
if
(
*
prm
.
hpass
)
{
prm
.
fimg
[
0
][
i
]
+=
prm
.
fimg
[
*
prm
.
hpass
][
i
];
}
}
}
void
NRFilter
::
waveletDenoise
(
float
*
fimg
[
3
],
unsigned
int
width
,
unsigned
int
height
,
float
threshold
,
double
softness
)
{
float
thold
;
uint
lpass
=
0
,
hpass
=
0
,
size
;
double
stdev
[
5
];
unsigned
int
samples
[
5
];
float
thold
;
uint
lpass
=
0
,
hpass
=
0
;
double
stdev
[
5
];
uint
samples
[
5
];
uint
size
=
width
*
height
;
size
=
width
*
height
;
QScopedArrayPointer
<
float
>
temp
(
new
float
[
qMax
(
width
,
height
)]);
uint
nbCore
=
QThreadPool
::
globalInstance
()
->
maxThreadCount
();
float
step
=
size
/
nbCore
;
uint
vals
[
nbCore
+
1
];
vals
[
0
]
=
0
;
vals
[
nbCore
]
=
size
;
for
(
uint
i
=
1
;
i
<
nbCore
;
++
i
)
vals
[
i
]
=
vals
[
i
-
1
]
+
step
;
QList
<
QFuture
<
void
>
>
tasks
;
Args
prm
;
prm
.
thold
=
&
thold
;
prm
.
lpass
=
&
lpass
;
prm
.
hpass
=
&
hpass
;
prm
.
threshold
=
threshold
;
prm
.
softness
=
softness
;
prm
.
stdev
=
&
stdev
[
0
];
prm
.
samples
=
&
samples
[
0
];
prm
.
fimg
=
fimg
;
for
(
uint
lev
=
0
;
runningFlag
()
&&
(
lev
<
5
);
++
lev
)
{
lpass
=
((
lev
&
1
)
+
1
);
...
...
@@ -323,40 +431,19 @@ void NRFilter::waveletDenoise(float* const fimg[3], unsigned int width, unsigned
// calculate stdevs for all intensities
for
(
uint
i
=
0
;
runningFlag
()
&&
(
i
<
siz
e
);
++
i
)
for
(
uint
j
=
0
;
runningFlag
()
&&
(
j
<
nbCor
e
)
;
++
j
)
{
fimg
[
hpass
][
i
]
-=
fimg
[
lpass
][
i
];
if
(
fimg
[
hpass
][
i
]
<
thold
&&
fimg
[
hpass
][
i
]
>
-
thold
)
{
if
(
fimg
[
lpass
][
i
]
>
0.8
)
{
stdev
[
4
]
+=
fimg
[
hpass
][
i
]
*
fimg
[
hpass
][
i
];
samples
[
4
]
++
;
}
else
if
(
fimg
[
lpass
][
i
]
>
0.6
)
{
stdev
[
3
]
+=
fimg
[
hpass
][
i
]
*
fimg
[
hpass
][
i
];
samples
[
3
]
++
;
}
else
if
(
fimg
[
lpass
][
i
]
>
0.4
)
{
stdev
[
2
]
+=
fimg
[
hpass
][
i
]
*
fimg
[
hpass
][
i
];
samples
[
2
]
++
;
}
else
if
(
fimg
[
lpass
][
i
]
>
0.2
)
{
stdev
[
1
]
+=
fimg
[
hpass
][
i
]
*
fimg
[
hpass
][
i
];
samples
[
1
]
++
;
}
else
{
stdev
[
0
]
+=
fimg
[
hpass
][
i
]
*
fimg
[
hpass
][
i
];
samples
[
0
]
++
;
}
}
prm
.
start
=
vals
[
j
];
prm
.
stop
=
vals
[
j
+
1
];
tasks
.
append
(
QtConcurrent
::
run
(
this
,
&
NRFilter
::
calculteStdevMultithreaded
,
prm
));
}
foreach
(
QFuture
<
void
>
t
,
tasks
)
t
.
waitForFinished
();
stdev
[
0
]
=
sqrt
(
stdev
[
0
]
/
(
samples
[
0
]
+
1
));
stdev
[
1
]
=
sqrt
(
stdev
[
1
]
/
(
samples
[
1
]
+
1
));
stdev
[
2
]
=
sqrt
(
stdev
[
2
]
/
(
samples
[
2
]
+
1
));
...
...
@@ -365,48 +452,21 @@ void NRFilter::waveletDenoise(float* const fimg[3], unsigned int width, unsigned
// do thresholding
for
(
uint
i
=
0
;
runningFlag
()
&&
(
i
<
size
);
++
i
)
{
if
(
fimg
[
lpass
][
i
]
>
0.8
)
{
thold
=
threshold
*
stdev
[
4
];
}
else
if
(
fimg
[
lpass
][
i
]
>
0.6
)
{
thold
=
threshold
*
stdev
[
3
];
}
else
if
(
fimg
[
lpass
][
i
]
>
0.4
)
{
thold
=
threshold
*
stdev
[
2
];
}
else
if
(
fimg
[
lpass
][
i
]
>
0.2
)
{
thold
=
threshold
*
stdev
[
1
];
}
else
{
thold
=
threshold
*
stdev
[
0
];
}
if
(
fimg
[
hpass
][
i
]
<
-
thold
)
{
fimg
[
hpass
][
i
]
+=
thold
-
thold
*
softness
;
}
else
if
(
fimg
[
hpass
][
i
]
>
thold
)
{
fimg
[
hpass
][
i
]
-=
thold
-
thold
*
softness
;
}
else
{
fimg
[
hpass
][
i
]
*=
softness
;
}
tasks
.
clear
();
if
(
hpass
)
{
fimg
[
0
][
i
]
+=
fimg
[
hpass
][
i
];
}
for
(
uint
j
=
0
;
runningFlag
()
&&
(
j
<
nbCore
)
;
++
j
)
{
prm
.
start
=
vals
[
j
];
prm
.
stop
=
vals
[
j
+
1
];
tasks
.
append
(
QtConcurrent
::
run
(
this
,
&
NRFilter
::
thresholdingMultithreaded
,
prm
));
}
foreach
(
QFuture
<
void
>
t
,
tasks
)
t
.
waitForFinished
();
hpass
=
lpass
;
}
...
...
@@ -468,175 +528,4 @@ void NRFilter::ycbcr2srgb(float** const fimg, int size)
}
}
// Methods not used.
/*
void NRFilter::srgb2xyz(float** const fimg, int size)
{
// fimg in [0:1], sRGB
float x, y, z;
for (int i = 0; i < size; ++i)
{
// scaling and gamma correction (approximate)
fimg[0][i] = pow(fimg[0][i], (float)2.2);
fimg[1][i] = pow(fimg[1][i], (float)2.2);
fimg[2][i] = pow(fimg[2][i], (float)2.2);
// matrix RGB -> XYZ, with D65 reference white (www.brucelindbloom.com)
x = 0.412424 * fimg[0][i] + 0.357579 * fimg[1][i] + 0.180464 * fimg[2][i];
y = 0.212656 * fimg[0][i] + 0.715158 * fimg[1][i] + 0.0721856 * fimg[2][i];
z = 0.0193324 * fimg[0][i] + 0.119193 * fimg[1][i] + 0.950444 * fimg[2][i];
// x = 0.412424 * fimg[0][i] + 0.212656 * fimg[1][i] + 0.0193324 * fimg[2][i];
// y = 0.357579 * fimg[0][i] + 0.715158 * fimg[1][i] + 0.119193 * fimg[2][i];
// z = 0.180464 * fimg[0][i] + 0.0721856 * fimg[1][i] + 0.950444 * fimg[2][i];
fimg[0][i] = x;
fimg[1][i] = y;
fimg[2][i] = z;
}
}
void NRFilter::xyz2srgb(float** const fimg, int size)
{
float r, g, b;
for (int i = 0; i < size; ++i)
{
// matrix RGB -> XYZ, with D65 reference white (www.brucelindbloom.com)
r = 3.24071 * fimg[0][i] - 1.53726 * fimg[1][i] - 0.498571 * fimg[2][i];
g = -0.969258 * fimg[0][i] + 1.87599 * fimg[1][i] + 0.0415557 * fimg[2][i];
b = 0.0556352 * fimg[0][i] - 0.203996 * fimg[1][i] + 1.05707 * fimg[2][i];
// r = 3.24071 * fimg[0][i] - 0.969258 * fimg[1][i]
// + 0.0556352 * fimg[2][i];
// g = -1.53726 * fimg[0][i] + 1.87599 * fimg[1][i]
// - 0.203996 * fimg[2][i];
// b = -0.498571 * fimg[0][i] + 0.0415557 * fimg[1][i]
// + 1.05707 * fimg[2][i];
// scaling and gamma correction (approximate)
r = r < 0 ? 0 : pow(r, (float)(1.0 / 2.2));
g = g < 0 ? 0 : pow(g, (float)(1.0 / 2.2));
b = b < 0 ? 0 : pow(b, (float)(1.0 / 2.2));
fimg[0][i] = r;
fimg[1][i] = g;
fimg[2][i] = b;
}
}
void NRFilter::lab2srgb(float** const fimg, int size)
{
float x, y, z;
for (int i = 0; i < size; ++i)
{
// convert back to normal LAB
fimg[0][i] = (fimg[0][i] - 0 * 16 * 27 / 24389.0) * 116;
fimg[1][i] = (fimg[1][i] - 0.5) * 500 * 2;
fimg[2][i] = (fimg[2][i] - 0.5) * 200 * 2.2;
// matrix
y = (fimg[0][i] + 16) / 116;
z = y - fimg[2][i] / 200.0;
x = fimg[1][i] / 500.0 + y;
// scale
if (x * x * x > 216 / 24389.0)
{
x = x * x * x;
}
else
{
x = (116 * x - 16) * 27 / 24389.0;
}
if (fimg[0][i] > 216 / 27.0)
{
y = y * y * y;
}
else
{
//y = fimg[0][i] * 27 / 24389.0;
y = (116 * y - 16) * 27 / 24389.0;
}
if (z * z * z > 216 / 24389.0)
{
z = z * z * z;
}
else
{
z = (116 * z - 16) * 27 / 24389.0;
}
// white reference
fimg[0][i] = x * 0.95047;
fimg[1][i] = y;
fimg[2][i] = z * 1.08883;
}
xyz2srgb(fimg, size);
}
void NRFilter::srgb2lab(float** const fimg, int size)
{
float l, a, b;
srgb2xyz(fimg, size);
for (int i = 0; i < size; ++i)
{
// reference white
fimg[0][i] /= 0.95047F;
//fimg[1][i] /= 1.00000; // (just for completeness)
fimg[2][i] /= 1.08883F;
// scale
if (fimg[0][i] > 216.0 / 24389.0)
{
fimg[0][i] = pow(fimg[0][i], (float)(1.0 / 3.0));
}
else
{
fimg[0][i] = (24389.0 * fimg[0][i] / 27.0 + 16.0) / 116.0;
}
if (fimg[1][i] > 216.0 / 24389.0)
{
fimg[1][i] = pow(fimg[1][i], (float)(1.0 / 3.0));
}
else
{
fimg[1][i] = (24389 * fimg[1][i] / 27.0 + 16.0) / 116.0;
}
if (fimg[2][i] > 216.0 / 24389.0)
{
fimg[2][i] = (float)pow(fimg[2][i], (float)(1.0 / 3.0));
}
else
{
fimg[2][i] = (24389.0 * fimg[2][i] / 27.0 + 16.0) / 116.0;
}
l = 116 * fimg[1][i] - 16;
a = 500 * (fimg[0][i] - fimg[1][i]);
b = 200 * (fimg[1][i] - fimg[2][i]);
fimg[0][i] = l / 116.0; // + 16 * 27 / 24389.0;
fimg[1][i] = a / 500.0 / 2.0 + 0.5;
fimg[2][i] = b / 200.0 / 2.2 + 0.5;
if (fimg[0][i] < 0)
{
fimg[0][i] = 0;
}
}
}
*/
}
// namespace Digikam
libs/dimg/filters/nr/nrfilter.h
View file @
c63d1ffd
...
...
@@ -7,7 +7,7 @@
* Description : Wavelets Noise Reduction threaded image filter.
* This filter work in YCrCb color space.
*
* Copyright (C) 2005-201
2
by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2005-201
4
by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2010 by Martin Klapetek <martin dot klapetek at gmail dot com>
*
* This program is free software; you can redistribute it
...
...
@@ -81,23 +81,35 @@ public:
static
void
srgb2ycbcr
(
float
**
const
fimg
,
int
size
);
private:
struct
Args
{
uint
start
;
uint
stop
;
float
*
thold
;
uint
*
lpass
;
uint
*
hpass
;
double
*
stdev
;
uint
*
samples
;
float
**
fimg
;
float
threshold
;
double
softness
;
};
private:
void
filterImage
();
void
waveletDenoise
(
float
*
const
fimg
[
3
],
unsigned
int
width
,
unsigned
int
height
,
void
waveletDenoise
(
float
*
fimg
[
3
],
unsigned
int
width
,
unsigned
int
height
,
float
threshold
,
double
softness
);
inline
void
hatTransform
(
float
*
const
temp
,
float
*
const
base
,
int
st
,
int
size
,
int
sc
);
void
ycbcr2srgb
(
float
**
const
fimg
,
int
size
);
// Methods not used.
/*
void srgb2lab(float** const fimg, int size);
void lab2srgb(float** const fimg, int size);
void srgb2xyz(float** const fimg, int size);
void xyz2srgb(float** const fimg, int size);
*/
void
calculteStdevMultithreaded
(
const
Args
&
prm
);
void
thresholdingMultithreaded
(
const
Args
&
prm
);
private:
class
Private
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment