Example #1
0
/* Function to apply the waves effect
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * Amplitude        => Sinoidal maximum height.
 * Frequency        => Frequency value.
 * FillSides        => Like a boolean variable.
 * Direction        => Vertical or horizontal flag.
 *
 * Theory           => This is an amazing effect, very funny, and very simple to
 *                     understand. You just need understand how qSin and qCos works.
 */
void DistortionFXFilter::waves(DImg* orgImage, DImg* destImage,
                               int Amplitude, int Frequency,
                               bool FillSides, bool Direction)
{
    if (Amplitude < 0)
    {
        Amplitude = 0;
    }

    if (Frequency < 0)
    {
        Frequency = 0;
    }

    Args prm;
    prm.orgImage  = orgImage;
    prm.destImage = destImage;
    prm.Amplitude = Amplitude;
    prm.Frequency = Frequency;
    prm.FillSides = FillSides;

    if (Direction)        // Horizontal
    {
        QList<int> vals = multithreadedSteps(orgImage->height());
        QList <QFuture<void> > tasks;

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::wavesHorizontalMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();
    }
    else
    {
        QList<int> vals = multithreadedSteps(orgImage->width());
        QList <QFuture<void> > tasks;

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::wavesVerticalMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();
    }
}
Example #2
0
void RefocusFilter::convolveImage(const Args& prm)
{
    int progress;

    QList<int> vals = multithreadedSteps(prm.width);

    for (int y1 = 0; runningFlag() && (y1 < prm.height); ++y1)
    {
        QList <QFuture<void> > tasks;

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            tasks.append(QtConcurrent::run(this,
                                           &RefocusFilter::convolveImageMultithreaded,
                                           vals[j],
                                           vals[j+1],
                                           y1,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        // Update the progress bar in dialog.
        progress = (int)(((double)y1 * 100.0) / prm.height);

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }
}
Example #3
0
/** This method have been implemented following this report in bugzilla :
    https://bugs.kde.org/show_bug.cgi?id=148540
    We use YCbCr color space to perform noise addition. Please follow this url for
    details about this color space :
    http://en.allexperts.com/e/y/yc/ycbcr.htm
 */
void FilmGrainFilter::filterImage()
{
    if (d->settings.lumaIntensity <= 0       ||
        d->settings.chromaBlueIntensity <= 0 ||
        d->settings.chromaRedIntensity <= 0  ||
        !d->settings.isDirty())
    {
        m_destImage = m_orgImage;
        return;
    }

    d->div                 = m_orgImage.sixteenBit() ? 65535.0 : 255.0;
    d->leadLumaNoise       = d->settings.lumaIntensity       * (m_orgImage.sixteenBit() ? 256.0 : 1.0);
    d->leadChromaBlueNoise = d->settings.chromaBlueIntensity * (m_orgImage.sixteenBit() ? 256.0 : 1.0);
    d->leadChromaRedNoise  = d->settings.chromaRedIntensity  * (m_orgImage.sixteenBit() ? 256.0 : 1.0);

    d->generator.seed(1); // noise will always be the same

    QList<int> vals = multithreadedSteps(m_orgImage.width());
    QList <QFuture<void> > tasks;

    for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
    {
        tasks.append(QtConcurrent::run(this,
                                       &FilmGrainFilter::filmgrainMultithreaded,
                                       vals[j],
                                       vals[j+1]
                                      ));
    }

    foreach(QFuture<void> t, tasks)
        t.waitForFinished();
}
Example #4
0
bool CharcoalFilter::convolveImage(const unsigned int order, const double* kernel)
{
    long kernelWidth = order;

    if ((kernelWidth % 2) == 0)
    {
        qCWarning(DIGIKAM_DIMG_LOG) << "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)
    {
        qCWarning(DIGIKAM_DIMG_LOG) << "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];
    }

    // --------------------------------------------------------

    QList<int> vals = multithreadedSteps(m_orgImage.height());
    QList <QFuture<void> > tasks;

    for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
    {
        tasks.append(QtConcurrent::run(this,
                                       &CharcoalFilter::convolveImageMultithreaded,
                                       vals[j],
                                       vals[j+1],
                                       normal_kernel.data(),
                                       kernelWidth
                                      ));
    }

    foreach(QFuture<void> t, tasks)
        t.waitForFinished();

    return true;
}
Example #5
0
/* Function to apply the circular waves effect backported from ImageProcesqSing version 2
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * X, Y             => Position of circle center on the image.
 * Amplitude        => Sinoidal maximum height
 * Frequency        => Frequency value.
 * Phase            => Phase value.
 * WavesType        => If true  the amplitude is proportional to radius.
 * Antialias        => Smart bluring result.
 *
 * Theory           => Similar to Waves effect, but here I apply a senoidal function
 *                     with the angle point.
 */
void DistortionFXFilter::circularWaves(DImg* orgImage, DImg* destImage, int X, int Y, double Amplitude,
                                       double Frequency, double Phase, bool WavesType, bool AntiAlias)
{
    if (Amplitude < 0.0)
    {
        Amplitude = 0.0;
    }

    if (Frequency < 0.0)
    {
        Frequency = 0.0;
    }

    int progress;

    QList<int> vals = multithreadedSteps(orgImage->width());
    QList <QFuture<void> > tasks;

    Args prm;
    prm.orgImage  = orgImage;
    prm.destImage = destImage;
    prm.Phase     = Phase;
    prm.Frequency = Frequency;
    prm.Amplitude = Amplitude;
    prm.WavesType = WavesType;
    prm.X         = X;
    prm.Y         = Y;
    prm.AntiAlias = AntiAlias;

    for (int h = 0; runningFlag() && (h < (int)orgImage->height()); ++h)
    {
        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            prm.h     = h;
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::circularWavesMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        // Update the progress bar in dialog.
        progress = (int)(((double)h * 100.0) / orgImage->height());

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }
}
Example #6
0
/* Function to apply the Cilindrical effect backported from ImageProcessing version 2
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * Coeff            => Cilindrical value.
 * Horizontal       => Apply horizontally.
 * Vertical         => Apply vertically.
 * Antialias        => Smart blurring result.
 *
 * Theory           => This is a great effect, similar to Spherize (Photoshop).
 *                     If you understand FishEye, you will understand Cilindrical
 *                     FishEye apply a logarithm function using a sphere radius,
 *                     Spherize use the same function but in a rectangular
 *                     environment.
 */
void DistortionFXFilter::cilindrical(DImg* orgImage, DImg* destImage, double Coeff,
                                     bool Horizontal, bool Vertical, bool AntiAlias)

{
    if ((Coeff == 0.0) || (!(Horizontal || Vertical)))
    {
        return;
    }

    int progress;

    // initial copy
    memcpy(destImage->bits(), orgImage->bits(), orgImage->numBytes());

    QList<int> vals = multithreadedSteps(orgImage->width());
    QList <QFuture<void> > tasks;

    Args prm;
    prm.orgImage   = orgImage;
    prm.destImage  = destImage;
    prm.Coeff      = Coeff;
    prm.Horizontal = Horizontal;
    prm.Vertical   = Vertical;
    prm.AntiAlias  = AntiAlias;

    // main loop

    for (int h = 0; runningFlag() && (h < (int)orgImage->height()); ++h)
    {
        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            prm.h     = h;
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::cilindricalMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        // Update the progress bar in dialog.
        progress = (int)(((double)h * 100.0) / orgImage->height());

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }
}
Example #7
0
/* Function to apply the block waves effect
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * Amplitude        => Sinoidal maximum height
 * Frequency        => Frequency value
 * Mode             => The mode to be applied.
 *
 * Theory           => This is an amazing effect, very funny when amplitude and
 *                     frequency are small values.
 */
void DistortionFXFilter::blockWaves(DImg* orgImage, DImg* destImage,
                                    int Amplitude, int Frequency, bool Mode)
{
    if (Amplitude < 0)
    {
        Amplitude = 0;
    }

    if (Frequency < 0)
    {
        Frequency = 0;
    }

    int progress;

    QList<int> vals = multithreadedSteps(orgImage->height());
    QList <QFuture<void> > tasks;

    Args prm;
    prm.orgImage  = orgImage;
    prm.destImage = destImage;
    prm.Mode      = Mode;
    prm.Frequency = Frequency;
    prm.Amplitude = Amplitude;

    for (int w = 0; runningFlag() && (w < (int)orgImage->width()); ++w)
    {
        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            prm.w     = w;
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::blockWavesMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        // Update the progress bar in dialog.
        progress = (int)(((double)w * 100.0) / orgImage->width());

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }
}
Example #8
0
/* Function to apply the twirl effect backported from ImageProcesqSing version 2
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * dist             => Distance value.
 * Antialias        => Smart blurring result.
 *
 * Theory           => Take spiral studies, you will understand better, I'm studying
 *                     hard on this effect, because it is not too fast.
 */
void DistortionFXFilter::twirl(DImg* orgImage, DImg* destImage, int dist, bool AntiAlias)
{
    // if dist value is zero, we do nothing

    if (dist == 0)
    {
        return;
    }

    int progress;

    QList<int> vals = multithreadedSteps(orgImage->width());
    QList <QFuture<void> > tasks;

    Args prm;
    prm.orgImage  = orgImage;
    prm.destImage = destImage;
    prm.dist      = dist;
    prm.AntiAlias = AntiAlias;

    // main loop

    for (int h = 0; runningFlag() && (h < (int)orgImage->height()); ++h)
    {
        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            prm.h     = h;
            tasks.append(QtConcurrent::run(this,
                                           &DistortionFXFilter::twirlMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        // Update the progress bar in dialog.
        progress = (int)(((double)h * 100.0) / orgImage->height());

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }
}
Example #9
0
/* Function to apply the tile effect
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * WSize            => Tile Width
 * HSize            => Tile Height
 * Random           => Maximum random value
 *
 * Theory           => Similar to Tile effect from Photoshop and very easy to
 *                     understand. We get a rectangular area uqSing WSize and HSize and
 *                     replace in a position with a random distance from the original
 *                     position.
 */
void DistortionFXFilter::tile(DImg* orgImage, DImg* destImage,
                              int WSize, int HSize, int Random)
{
    if (WSize < 1)
    {
        WSize = 1;
    }

    if (HSize < 1)
    {
        HSize = 1;
    }

    if (Random < 1)
    {
        Random = 1;
    }

    Args prm;
    prm.orgImage  = orgImage;
    prm.destImage = destImage;
    prm.WSize     = WSize;
    prm.HSize     = HSize;
    prm.Random    = Random;

    d->generator.seed(d->randomSeed);

    QList<int> vals = multithreadedSteps(orgImage->height());
    QList <QFuture<void> > tasks;

    for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
    {
        prm.start = vals[j];
        prm.stop  = vals[j+1];
        tasks.append(QtConcurrent::run(this,
                                       &DistortionFXFilter::tileMultithreaded,
                                       prm
                                      ));
    }

    foreach(QFuture<void> t, tasks)
        t.waitForFinished();
}
Example #10
0
bool SharpenFilter::convolveImage(const unsigned int order, const double* const kernel)
{
    uint    y;
    int     progress;
    long    i;
    double  normalize = 0.0;

    Args prm;
    prm.kernelWidth     = order;
    prm.halfKernelWidth = prm.kernelWidth / 2;;

    if ((prm.kernelWidth % 2) == 0)
    {
        qCWarning(DIGIKAM_DIMG_LOG) << "Kernel width must be an odd number!";
        return false;
    }

    QScopedArrayPointer<double> normal_kernel(new double[prm.kernelWidth * prm.kernelWidth]);

    if (normal_kernel.isNull())
    {
        qCWarning(DIGIKAM_DIMG_LOG) << "Unable to allocate memory!";
        return false;
    }

    for (i = 0 ; i < (prm.kernelWidth * prm.kernelWidth) ; ++i)
    {
        normalize += kernel[i];
    }

    if (fabs(normalize) <= Epsilon)
    {
        normalize = 1.0;
    }

    normalize = 1.0 / normalize;

    for (i = 0 ; i < (prm.kernelWidth * prm.kernelWidth) ; ++i)
    {
        normal_kernel[i] = normalize * kernel[i];
    }

    prm.normal_kernel = normal_kernel.data();
    QList<int> vals = multithreadedSteps(m_destImage.width());

    for (y = 0 ; runningFlag() && (y < m_destImage.height()) ; ++y)
    {
        QList <QFuture<void> > tasks;

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            prm.start = vals[j];
            prm.stop  = vals[j+1];
            prm.y     = y;

            tasks.append(QtConcurrent::run(this,
                                           &SharpenFilter::convolveImageMultithreaded,
                                           prm
                                          ));
        }

        foreach(QFuture<void> t, tasks)
            t.waitForFinished();

        progress = (int)(((double)y * 100.0) / m_destImage.height());

        if (progress % 5 == 0)
        {
            postProgress(progress);
        }
    }

    return true;
}
Example #11
0
void NRFilter::waveletDenoise(float* fimg[3], unsigned int width, unsigned int height,
                              float threshold, double softness)
{
    float  thold;
    uint   lpass = 0, hpass = 0;
    double stdev[5];
    uint   samples[5];
    uint   size  = width * height;

    QScopedArrayPointer<float> temp(new float[qMax(width, height)]);

    QList<int> vals = multithreadedSteps(size);
    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);

        for (uint row = 0; runningFlag() && (row < height); ++row)
        {
            hatTransform(temp.data(), fimg[hpass] + row * width, 1, width, 1 << lev);

            for (uint col = 0; col < width; ++col)
            {
                fimg[lpass][row * width + col] = temp[col] * 0.25;
            }
        }

        for (uint col = 0; runningFlag() && (col < width); ++col)
        {
            hatTransform(temp.data(), fimg[lpass] + col, width, height, 1 << lev);

            for (uint row = 0; row < height; ++row)
            {
                fimg[lpass][row * width + col] = temp[row] * 0.25;
            }
        }

        thold = 5.0 / (1 << 6) * exp(-2.6 * sqrt(lev + 1.0)) * 0.8002 / exp(-2.6);

        // initialize stdev values for all intensities

        stdev[0]   = stdev[1]   = stdev[2]   = stdev[3]   = stdev[4]   = 0.0;
        samples[0] = samples[1] = samples[2] = samples[3] = samples[4] = 0;

        // calculate stdevs for all intensities

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j)
        {
            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));
        stdev[3] = sqrt(stdev[3] / (samples[3] + 1));
        stdev[4] = sqrt(stdev[4] / (samples[4] + 1));

        // do thresholding

        tasks.clear();

        for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++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;
    }

    for (uint i = 0; runningFlag() && (i < size); ++i)
    {
        fimg[0][i] = fimg[0][i] + fimg[lpass][i];
    }
}