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
cb3bec4e
Commit
cb3bec4e
authored
May 03, 2014
by
Gilles Caulier
🗼
Browse files
Charcoal Tool : add support of multicore CPU based on QtConcurrent API.
CCBUGS: 289204
parent
d8e04596
Changes
6
Hide whitespace changes
Inline
Side-by-side
NEWS
View file @
cb3bec4e
...
...
@@ -15,6 +15,7 @@ Editor : Port of canvas to Qt Model/view.
Editor : LocalContrast tool support multicore CPU.
Editor : Sharpen tool support multicore CPU.
Editor : Blur tool support multicore CPU.
Editor : Charcoal tool support multicore CPU.
Showfoto : Port of Thumbbar to Qt Model/view.
...
...
imageplugins/TODO
View file @
cb3bec4e
...
...
@@ -24,7 +24,7 @@ decorate
filters
/colorfx DONE TODO DONE DONE
/charcoal DONE
TO
DO DONE TODO
/charcoal DONE DO
NE
DONE TODO
/distortionfx DONE TODO TODO TODO
/emboss DONE TODO DONE TODO
/oilpaint DONE TODO DONE TODO
...
...
libs/dimg/filters/fx/blurfilter.cpp
View file @
cb3bec4e
...
...
@@ -29,6 +29,7 @@
#include <qmath.h>
#include <QtConcurrentRun>
#include <QMutex>
// KDE includes
...
...
libs/dimg/filters/fx/blurfilter.h
View file @
cb3bec4e
...
...
@@ -26,8 +26,6 @@
#ifndef BLURFILTER_H
#define BLURFILTER_H
#include <QMutex>
// Local includes
#include "digikam_export.h"
...
...
libs/dimg/filters/fx/charcoalfilter.cpp
View file @
cb3bec4e
...
...
@@ -6,7 +6,7 @@
* Date : 2005-05-25
* Description : Charcoal threaded image filter.
*
* Copyright (C) 2005-201
3
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
...
...
@@ -31,6 +31,11 @@
#include <cmath>
// Qt includes
#include <QtConcurrentRun>
#include <QMutex>
// KDE includes
#include <kdebug.h>
...
...
@@ -46,19 +51,37 @@
namespace
Digikam
{
class
CharcoalFilter
::
Private
{
public:
Private
()
{
globalProgress
=
0
;
pencil
=
5.0
;
smooth
=
10.0
;
}
double
pencil
;
double
smooth
;
int
globalProgress
;
QMutex
lock
;
};
CharcoalFilter
::
CharcoalFilter
(
QObject
*
const
parent
)
:
DImgThreadedFilter
(
parent
)
:
DImgThreadedFilter
(
parent
),
d
(
new
Private
)
{
m_pencil
=
5.0
;
m_smooth
=
10.0
;
initFilter
();
}
CharcoalFilter
::
CharcoalFilter
(
DImg
*
const
orgImage
,
QObject
*
const
parent
,
double
pencil
,
double
smooth
)
:
DImgThreadedFilter
(
orgImage
,
parent
,
"Charcoal"
)
:
DImgThreadedFilter
(
orgImage
,
parent
,
"Charcoal"
),
d
(
new
Private
)
{
m_
pencil
=
pencil
;
m_
smooth
=
smooth
;
d
->
pencil
=
pencil
;
d
->
smooth
=
smooth
;
initFilter
();
}
...
...
@@ -66,6 +89,7 @@ CharcoalFilter::CharcoalFilter(DImg* const orgImage, QObject* const parent, doub
CharcoalFilter
::~
CharcoalFilter
()
{
cancelFilter
();
delete
d
;
}
void
CharcoalFilter
::
filterImage
()
...
...
@@ -76,7 +100,7 @@ void CharcoalFilter::filterImage()
return
;
}
if
(
m_
pencil
<=
0.0
)
if
(
d
->
pencil
<=
0.0
)
{
m_destImage
=
m_orgImage
;
return
;
...
...
@@ -85,7 +109,7 @@ void CharcoalFilter::filterImage()
// -- Applying Edge effect -----------------------------------------------
register
long
i
=
0
;
int
kernelWidth
=
getOptimalKernelWidth
(
m_
pencil
,
m_
smooth
);
int
kernelWidth
=
getOptimalKernelWidth
(
d
->
pencil
,
d
->
smooth
);
if
((
int
)
m_orgImage
.
width
()
<
kernelWidth
)
{
...
...
@@ -111,7 +135,7 @@ void CharcoalFilter::filterImage()
// -- Applying Gaussian blur effect ---------------------------------------
BlurFilter
(
this
,
m_destImage
,
m_destImage
,
80
,
85
,
(
int
)(
m_
smooth
/
10.0
));
BlurFilter
(
this
,
m_destImage
,
m_destImage
,
80
,
85
,
(
int
)(
d
->
smooth
/
10.0
));
if
(
!
runningFlag
())
{
...
...
@@ -163,70 +187,28 @@ void CharcoalFilter::filterImage()
}
}
bool
CharcoalFilter
::
convolveImage
(
const
unsigned
int
order
,
const
double
*
kernel
)
void
CharcoalFilter
::
convolveImage
Multithreaded
(
uint
start
,
uint
stop
,
double
*
normal_kernel
,
double
kernel
Width
)
{
long
kernelWidth
=
order
;
if
((
kernelWidth
%
2
)
==
0
)
{
kWarning
()
<<
"Kernel width must be an odd number!"
;
return
false
;
}
uint
x
,
y
;
long
i
;
int
mx
,
my
,
sx
,
sy
,
mcx
,
mcy
,
progress
;
double
red
,
green
,
blue
,
alpha
,
normalize
=
0.0
;
int
mx
,
my
,
sx
,
sy
,
mcx
,
mcy
,
oldProgress
=
0
,
progress
=
0
;
double
red
,
green
,
blue
,
alpha
;
double
*
k
=
0
;
QScopedArrayPointer
<
double
>
normal_kernel
(
new
double
[
kernelWidth
*
kernelWidth
]);
if
(
!
normal_kernel
)
{
kWarning
()
<<
"Unable to allocate memory!"
;
return
false
;
}
for
(
i
=
0
;
i
<
(
kernelWidth
*
kernelWidth
);
++
i
)
{
normalize
+=
kernel
[
i
];
}
if
(
fabs
(
normalize
)
<=
Epsilon
)
{
normalize
=
1.0
;
}
normalize
=
1.0
/
normalize
;
for
(
i
=
0
;
i
<
(
kernelWidth
*
kernelWidth
);
++
i
)
{
normal_kernel
[
i
]
=
normalize
*
kernel
[
i
];
}
// --------------------------------------------------------
// caching
uint
height
=
m_destImage
.
height
();
uint
width
=
m_destImage
.
width
();
bool
sixteenBit
=
m_destImage
.
sixteenBit
();
uchar
*
ddata
=
m_destImage
.
bits
();
int
ddepth
=
m_destImage
.
bytesDepth
();
uchar
*
sdata
=
m_orgImage
.
bits
();
int
sdepth
=
m_orgImage
.
bytesDepth
();
double
maxClamp
=
m_destImage
.
sixteenBit
()
?
16777215.0
:
65535.0
;
// --------------------------------------------------------
for
(
y
=
0
;
runningFlag
()
&&
(
y
<
height
);
++
y
)
for
(
uint
y
=
start
;
runningFlag
()
&&
(
y
<
stop
)
;
++
y
)
{
sy
=
y
-
(
kernelWidth
/
2
);
for
(
x
=
0
;
runningFlag
()
&&
(
x
<
width
);
++
x
)
for
(
uint
x
=
0
;
runningFlag
()
&&
(
x
<
width
);
++
x
)
{
k
=
normal_kernel
.
data
()
;
k
=
normal_kernel
;
red
=
green
=
blue
=
alpha
=
0
;
sy
=
y
-
(
kernelWidth
/
2
);
...
...
@@ -257,14 +239,79 @@ bool CharcoalFilter::convolveImage(const unsigned int order, const double* kerne
color
.
setPixel
((
ddata
+
x
*
ddepth
+
(
width
*
y
*
ddepth
)));
}
progress
=
(
int
)(
(
(
double
)
y
*
80.0
)
/
height
);
progress
=
(
int
)(
(
(
double
)
y
*
(
80.0
/
QThreadPool
::
globalInstance
()
->
maxThreadCount
())
)
/
(
stop
-
start
)
);
if
(
progress
%
5
==
0
)
if
(
(
progress
%
5
==
0
)
&&
(
progress
>
oldProgress
))
{
postProgress
(
progress
);
d
->
lock
.
lock
();
oldProgress
=
progress
;
d
->
globalProgress
+=
5
;
postProgress
(
d
->
globalProgress
);
d
->
lock
.
unlock
();
}
}
}
bool
CharcoalFilter
::
convolveImage
(
const
unsigned
int
order
,
const
double
*
kernel
)
{
long
kernelWidth
=
order
;
if
((
kernelWidth
%
2
)
==
0
)
{
kWarning
()
<<
"Kernel width must be an odd number!"
;
return
false
;
}
long
i
;
double
normalize
=
0.0
;
QScopedArrayPointer
<
double
>
normal_kernel
(
new
double
[
kernelWidth
*
kernelWidth
]);
if
(
!
normal_kernel
)
{
kWarning
()
<<
"Unable to allocate memory!"
;
return
false
;
}
for
(
i
=
0
;
i
<
(
kernelWidth
*
kernelWidth
);
++
i
)
{
normalize
+=
kernel
[
i
];
}
if
(
fabs
(
normalize
)
<=
Epsilon
)
{
normalize
=
1.0
;
}
normalize
=
1.0
/
normalize
;
for
(
i
=
0
;
i
<
(
kernelWidth
*
kernelWidth
);
++
i
)
{
normal_kernel
[
i
]
=
normalize
*
kernel
[
i
];
}
// --------------------------------------------------------
int
nbCore
=
QThreadPool
::
globalInstance
()
->
maxThreadCount
();
float
step
=
m_destImage
.
height
()
/
nbCore
;
QList
<
QFuture
<
void
>
>
tasks
;
for
(
int
j
=
0
;
runningFlag
()
&&
(
j
<
nbCore
)
;
++
j
)
{
tasks
.
append
(
QtConcurrent
::
run
(
this
,
&
CharcoalFilter
::
convolveImageMultithreaded
,
(
uint
)(
j
*
step
),
(
uint
)((
j
+
1
)
*
step
),
normal_kernel
.
data
(),
kernelWidth
));
}
foreach
(
QFuture
<
void
>
t
,
tasks
)
t
.
waitForFinished
();
return
true
;
}
...
...
@@ -307,16 +354,16 @@ FilterAction CharcoalFilter::filterAction()
FilterAction
action
(
FilterIdentifier
(),
CurrentVersion
());
action
.
setDisplayableName
(
DisplayableName
());
action
.
addParameter
(
"pencil"
,
m_
pencil
);
action
.
addParameter
(
"smooth"
,
m_
smooth
);
action
.
addParameter
(
"pencil"
,
d
->
pencil
);
action
.
addParameter
(
"smooth"
,
d
->
smooth
);
return
action
;
}
void
CharcoalFilter
::
readParameters
(
const
Digikam
::
FilterAction
&
action
)
{
m_
pencil
=
action
.
parameter
(
"pencil"
).
toDouble
();
m_
smooth
=
action
.
parameter
(
"smooth"
).
toDouble
();
d
->
pencil
=
action
.
parameter
(
"pencil"
).
toDouble
();
d
->
smooth
=
action
.
parameter
(
"smooth"
).
toDouble
();
}
}
// namespace Digikam
libs/dimg/filters/fx/charcoalfilter.h
View file @
cb3bec4e
...
...
@@ -6,7 +6,7 @@
* Date : 2005-05-25
* Description : Charcoal threaded image filter.
*
* Copyright (C) 2005-201
3
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
...
...
@@ -76,11 +76,12 @@ private:
void
filterImage
();
bool
convolveImage
(
const
unsigned
int
order
,
const
double
*
kernel
);
int
getOptimalKernelWidth
(
double
radius
,
double
sigma
);
void
convolveImageMultithreaded
(
uint
start
,
uint
stop
,
double
*
normal_kernel
,
double
kernelWidth
);
private:
double
m_pencil
;
double
m_smooth
;
class
Private
;
Private
*
const
d
;
};
}
// namespace Digikam
...
...
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