Commit b451f671 authored by Gilles Caulier's avatar Gilles Caulier 🗼
Browse files

OilPaint Tool : add support of multicore CPU based on QtConcurrent API.

CCBUGS: 289204
parent cb3bec4e
......@@ -16,6 +16,7 @@ Editor : LocalContrast tool support multicore CPU.
Editor : Sharpen tool support multicore CPU.
Editor : Blur tool support multicore CPU.
Editor : Charcoal tool support multicore CPU.
Editor : OilPaint tool support multicore CPU.
Showfoto : Port of Thumbbar to Qt Model/view.
......
......@@ -27,7 +27,7 @@ filters
/charcoal DONE DONE DONE TODO
/distortionfx DONE TODO TODO TODO
/emboss DONE TODO DONE TODO
/oilpaint DONE TODO DONE TODO
/oilpaint DONE DONE DONE TODO
/blurfx DONE TODO DONE TODO
/raindrop DONE TODO NO TODO
/filmgrain DONE TODO DONE DONE
......
......@@ -6,7 +6,7 @@
* Date : 2005-05-25
* Description : Oil Painting threaded image filter.
*
* Copyright (C) 2005-2013 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2005-2014 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2006-2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
* Copyright (C) 2010 by Martin Klapetek <martin dot klapetek at gmail dot com>
*
......@@ -33,6 +33,11 @@
#include <cmath>
#include <cstdlib>
// Qt includes
#include <QtConcurrentRun>
#include <QMutex>
// Local includes
#include "dimg.h"
......@@ -45,23 +50,18 @@ class OilPaintFilter::Private
public:
Private() :
intensityCount(0),
brushSize(1),
smoothness(30),
averageColorR(0),
averageColorG(0),
averageColorB(0)
globalProgress(0)
{
}
uchar* intensityCount;
int brushSize;
int smoothness;
uint* averageColorR;
uint* averageColorG;
uint* averageColorB;
int globalProgress;
QMutex lock;
};
OilPaintFilter::OilPaintFilter(QObject* const parent)
......@@ -93,48 +93,66 @@ OilPaintFilter::~OilPaintFilter()
* Theory: Using MostFrequentColor function we take the main color in
* a matrix and simply write at the original position.
*/
void OilPaintFilter::filterImage()
void OilPaintFilter::oilPaintImageMultithreaded(uint start, uint stop)
{
int progress;
uchar* intensityCount = new uchar[d->smoothness + 1];
uint* averageColorR = new uint[d->smoothness + 1];
uint* averageColorG = new uint[d->smoothness + 1];
uint* averageColorB = new uint[d->smoothness + 1];
int oldProgress=0, progress=0;
DColor mostFrequentColor;
int w, h;
mostFrequentColor.setSixteenBit(m_orgImage.sixteenBit());
w = (int)m_orgImage.width();
h = (int)m_orgImage.height();
uchar* dest = m_destImage.bits();
int bytesDepth = m_orgImage.bytesDepth();
uchar* dptr = 0;
// Allocate some arrays to be used.
// Do this here once for all to save a few million new / delete operations
d->intensityCount = new uchar[d->smoothness + 1];
d->averageColorR = new uint[d->smoothness + 1];
d->averageColorG = new uint[d->smoothness + 1];
d->averageColorB = new uint[d->smoothness + 1];
for (int h2 = 0; runningFlag() && (h2 < h); ++h2)
for (uint h2 = start; runningFlag() && (h2 < stop); ++h2)
{
for (int w2 = 0; runningFlag() && (w2 < w); ++w2)
for (uint w2 = 0; runningFlag() && (w2 < m_orgImage.width()); ++w2)
{
mostFrequentColor = MostFrequentColor(m_orgImage, w2, h2, d->brushSize, d->smoothness);
dptr = dest + w2 * bytesDepth + (w * h2 * bytesDepth);
mostFrequentColor = MostFrequentColor(m_orgImage, w2, h2, d->brushSize, d->smoothness,
intensityCount, averageColorR, averageColorG, averageColorB);
dptr = dest + w2 * m_orgImage.bytesDepth() + (m_orgImage.width() * h2 * m_orgImage.bytesDepth());
mostFrequentColor.setPixel(dptr);
}
progress = (int)(((double)h2 * 100.0) / h);
progress = (int)( ( (double)h2 * (100.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();
}
}
delete [] intensityCount;
delete [] averageColorR;
delete [] averageColorG;
delete [] averageColorB;
}
void OilPaintFilter::filterImage()
{
int nbCore = QThreadPool::globalInstance()->maxThreadCount();
float step = m_orgImage.height() / nbCore;
QList <QFuture<void> > tasks;
for (int j = 0 ; runningFlag() && (j < nbCore) ; ++j)
{
tasks.append(QtConcurrent::run(this,
&OilPaintFilter::oilPaintImageMultithreaded,
(uint)(j*step),
(uint)((j+1)*step)
));
}
// free all the arrays
delete [] d->intensityCount;
delete [] d->averageColorR;
delete [] d->averageColorG;
delete [] d->averageColorB;
foreach(QFuture<void> t, tasks)
t.waitForFinished();
}
/** Function to determine the most frequent color in a matrix
......@@ -150,7 +168,8 @@ void OilPaintFilter::filterImage()
* Theory => This function creates a matrix with the analyzed pixel in
* the center of this matrix and find the most frequently color
*/
DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, int Intensity)
DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, int Intensity,
uchar* intensityCount, uint* averageColorR, uint* averageColorG, uint* averageColorB)
{
int i, w, h, I, Width, Height;
uint red, green, blue;
......@@ -167,7 +186,7 @@ DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, in
Height = (int)src.height();
// Erase the array
memset(d->intensityCount, 0, (Intensity + 1) * sizeof(uchar));
memset(intensityCount, 0, (Intensity + 1) * sizeof(uchar));
for (w = X - Radius; w <= X + Radius; ++w)
{
......@@ -184,19 +203,19 @@ DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, in
blue = (uint)color.blue();
I = lround(GetIntensity(red, green, blue) * Scale);
d->intensityCount[I]++;
intensityCount[I]++;
if (d->intensityCount[I] == 1)
if (intensityCount[I] == 1)
{
d->averageColorR[I] = red;
d->averageColorG[I] = green;
d->averageColorB[I] = blue;
averageColorR[I] = red;
averageColorG[I] = green;
averageColorB[I] = blue;
}
else
{
d->averageColorR[I] += red;
d->averageColorG[I] += green;
d->averageColorB[I] += blue;
averageColorR[I] += red;
averageColorG[I] += green;
averageColorB[I] += blue;
}
}
}
......@@ -207,10 +226,10 @@ DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, in
for (i = 0 ; i <= Intensity ; ++i)
{
if (d->intensityCount[i] > MaxInstance)
if (intensityCount[i] > MaxInstance)
{
I = i;
MaxInstance = d->intensityCount[i];
MaxInstance = intensityCount[i];
}
}
......@@ -218,9 +237,9 @@ DColor OilPaintFilter::MostFrequentColor(DImg& src, int X, int Y, int Radius, in
mostFrequentColor = src.getPixelColor(X, Y);
// Overwrite RGB values to destination.
mostFrequentColor.setRed(d->averageColorR[I] / MaxInstance);
mostFrequentColor.setGreen(d->averageColorG[I] / MaxInstance);
mostFrequentColor.setBlue(d->averageColorB[I] / MaxInstance);
mostFrequentColor.setRed(averageColorR[I] / MaxInstance);
mostFrequentColor.setGreen(averageColorG[I] / MaxInstance);
mostFrequentColor.setBlue(averageColorB[I] / MaxInstance);
return mostFrequentColor;
}
......
......@@ -6,7 +6,7 @@
* Date : 2005-05-25
* Description : Oil Painting threaded image filter.
*
* Copyright (C) 2005-2013 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2005-2014 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2006-2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
* Copyright (C) 2010 by Martin Klapetek <martin dot klapetek at gmail dot com>
*
......@@ -75,8 +75,9 @@ public:
private:
void filterImage();
DColor MostFrequentColor(DImg& src, int X, int Y, int Radius, int Intensity);
void oilPaintImageMultithreaded(uint start, uint stop);
DColor MostFrequentColor(DImg& src, int X, int Y, int Radius, int Intensity,
uchar* intensityCount, uint* averageColorR, uint* averageColorG, uint* averageColorB);
inline double GetIntensity(uint Red, uint Green, uint Blue);
private:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment