Пример #1
0
/** This method apply grain adjustment on a pixel color channel from YCrCb color space.
    NRand is the lead uniform noise set from matrix used to scan whole image step by step.
    Additionally noise is applied on pixel using Poisson or Gaussian distribution.
 */
void FilmGrainFilter::adjustYCbCr(DColor& col, double range, double nRand, int channel)
{
    double y, cb, cr, n2;
    col.getYCbCr(&y, &cb, &cr);

    if (d->settings.photoDistribution)
    {
        n2 = randomizePoisson((d->settings.grainSize / 2.0) * (range / 1.414));
    }
    else
    {
        n2 = randomizeGauss((d->settings.grainSize / 2.0) * (range / 1.414));
    }

    switch (channel)
    {
        case Private::Luma:
            y  = CLAMP(y  + (nRand + n2) / d->div, 0.0, 1.0);
            break;

        case Private::ChromaBlue:
            cb = CLAMP(cb + (nRand + n2) / d->div, 0.0, 1.0);
            break;

        default:       // ChromaRed
            cr = CLAMP(cr + (nRand + n2) / d->div, 0.0, 1.0);
            break;
    }

    col.setYCbCr(y, cb, cr, col.sixteenBit());
}
Пример #2
0
/** This method interpolate gain adjustments to apply grain on shadows, midtones and highlights colors.
    The output value is a coefficient computed between 0.0 and 1.0.
 */
double FilmGrainFilter::interpolate(int shadows, int midtones, int highlights, const DColor& col)
{
    double s = (shadows    + 100.0) / 200.0;
    double m = (midtones   + 100.0) / 200.0;
    double h = (highlights + 100.0) / 200.0;

    double y, cb, cr;
    col.getYCbCr(&y, &cb, &cr);

    if (y >= 0.0 && y <= 0.5)
    {
        return (s + 2 * (m - s) * y);
    }
    else if (y >= 0.5 && y <= 1.0)
    {
        return (2 * (h - m) * y + 2 * m - h);
    }
    else
    {
        return 1.0;
    }
}