Example #1
0
static sample
composeComponents(sample           const compA, 
                  sample           const compB,
                  float            const distrib,
                  float            const aFactor,
                  float            const composedFactor,
                  sample           const maxval,
                  enum sampleScale const sampleScale) {
/*----------------------------------------------------------------------------
  Compose a single color component of each of two pixels, with 'distrib' being
  the fraction of 'compA' in the result, 1-distrib the fraction of 'compB'.
  Note that this does not apply to an opacity component.

  'sampleScale' tells in what domain the 'distrib' fraction applies:
  brightness or light intensity (gamma-adjusted or not).

  'aFactor' is a factor in [0,1] to apply to 'compA' first.

  'composedFactor' is a factor to apply to the result.

  See above for explanation of why 'aFactor' and 'composedFactor' are
  useful.

  The inputs and result are based on a maxval of 'maxval'.
  
  Note that while 'distrib' in the straightforward case is always in
  [0,1], it can in fact be negative or greater than 1.  We clip the
  result as required to return a legal sample value.
-----------------------------------------------------------------------------*/
    sample retval;

    if (fabs(distrib) > .999 && aFactor > .999 && composedFactor > .999)
        /* Fast path for common case */
        retval = compA;
    else {
        if (sampleScale == INTENSITY_SAMPLE) {
            sample const mix = 
                ROUNDU(compA * aFactor * distrib + compB * (1.0 - distrib));
            retval = MIN(maxval, MAX(0, mix));
        } else {
            float const compANormalized = (float)compA/maxval;
            float const compBNormalized = (float)compB/maxval;
            float const compALinear = pm_ungamma709(compANormalized);
            float const compBLinear = pm_ungamma709(compBNormalized);
            float const compALinearAdj = compALinear * aFactor;
            float const mix = 
                compALinearAdj * distrib + compBLinear * (1.0 - distrib)
                * composedFactor;
            sample const sampleValue = ROUNDU(pm_gamma709(mix) * maxval);
            retval = MIN(maxval, MAX(0, sampleValue));
        }
    }
    return retval;
}
Example #2
0
static void
computeMap(const unsigned int * const lumahist,
           xelval               const maxval,
           unsigned int         const pixelCount,
           gray *               const lumamap) {

    /* Calculate initial histogram equalization curve. */
    
    unsigned int i;
    unsigned int pixsum;
    xelval maxluma;

    for (i = 0, pixsum = 0; i <= maxval; ++i) {
            
        /* With 16 bit grays, the following calculation can
           overflow a 32 bit long.  So, we do it in floating
           point.
        */

        lumamap[i] = ROUNDU((((double) pixsum * maxval)) / pixelCount);

        pixsum += lumahist[i];
    }

    findMaxLuma(lumahist, maxval, &maxluma);

    {
        double const lscale = (double)maxval /
            ((lumahist[maxluma] > 0) ?
             (double) lumamap[maxluma] : (double) maxval);

        unsigned int i;

        /* Normalize so that the brightest pixels are set to maxval. */

        for (i = 0; i <= maxval; ++i)
            lumamap[i] = MIN(maxval, ROUNDU(lumamap[i] * lscale));
    }
}
Example #3
0
static sample
composeComponents(sample           const compA, 
                  sample           const compB,
                  float            const distrib,
                  sample           const maxval,
                  enum sampleScale const sampleScale) {
/*----------------------------------------------------------------------------
  Compose a single component of each of two pixels, with 'distrib' being
  the fraction of 'compA' in the result, 1-distrib the fraction of 'compB'.
  
  The inputs and result are based on a maxval of 'maxval'.
  
  Note that while 'distrib' in the straightforward case is always in
  [0,1], it can in fact be negative or greater than 1.  We clip the
  result as required to return a legal sample value.
-----------------------------------------------------------------------------*/
    sample retval;

    if (fabs(1.0-distrib) < .001)
        /* Fast path for common case */
        retval = compA;
    else {
        if (sampleScale == INTENSITY_SAMPLE) {
            sample const mix = 
                ROUNDU(compA * distrib + compB * (1.0 - distrib));
            retval = MIN(maxval, MAX(0, mix));
        } else {
            float const compANormalized = (float)compA/maxval;
            float const compBNormalized = (float)compB/maxval;
            float const compALinear = pm_ungamma709(compANormalized);
            float const compBLinear = pm_ungamma709(compBNormalized);
            float const mix = 
                compALinear * distrib + compBLinear * (1.0 - distrib);
            sample const sampleValue = ROUNDU(pm_gamma709(mix) * maxval);
            retval = MIN(maxval, MAX(0, sampleValue));
        }
    }
    return retval;
}
Example #4
0
static void
remap(xel **       const xels,
      unsigned int const cols,
      unsigned int const rows,
      xelval       const maxval,
      int          const format,
      bool         const monoOnly,
      const gray * const lumamap) {
/*----------------------------------------------------------------------------
   Update the array 'xels' to have the new intensities.
-----------------------------------------------------------------------------*/
    switch (PNM_FORMAT_TYPE(format)) {
    case PPM_TYPE: {
        unsigned int row;
        for (row = 0; row < rows; ++row) {
            unsigned int col;
            for (col = 0; col < cols; ++col) {
                xel const thisXel = xels[row][col];
                if (monoOnly && PPM_ISGRAY(thisXel)) {
                    /* Leave this pixel alone */
                } else {
                    struct hsv hsv;
                    xelval iv;

                    hsv = ppm_hsv_from_color(thisXel, maxval);
                    iv = MIN(maxval, ROUNDU(hsv.v * maxval));
                    
                    hsv.v = MIN(1.0, 
                                ((double) lumamap[iv]) / ((double) maxval));

                    xels[row][col] = ppm_color_from_hsv(hsv, maxval);
                }
            }
        }
    }
    break;

    case PBM_TYPE:
    case PGM_TYPE: {
        unsigned int row;
        for (row = 0; row < rows; ++row) {
            unsigned int col;
            for (col = 0; col < cols; ++col)
                PNM_ASSIGN1(xels[row][col],
                            lumamap[PNM_GET1(xels[row][col])]);
        }
    }
    break;
    }
}
Example #5
0
static void
countComp(xelval         const value,
          xelval         const startval,
          xelval         const endval,
          unsigned int   const histWidth,
          unsigned int * const hist) {

    double const hscale = (float)(histWidth-1) / (endval - startval - 1);

    if (value >= startval && value < endval) {
        unsigned int const bin = ROUNDU((value-startval) * hscale);

        assert(bin < histWidth);
        ++hist[bin];
    }
}
Example #6
0
pixel
ppm_color_from_hsv(struct hsv const hsv,
                   pixval     const maxval) {

    pixel retval;
    double R, G, B;

    if (hsv.s == 0) {
        R = hsv.v;
        G = hsv.v;
        B = hsv.v;
    } else {
        unsigned int const sectorSize = 60;
            /* Color wheel is divided into six 60 degree sectors. */
        unsigned int const sector = (hsv.h/sectorSize);
            /* The sector in which our color resides.  Value is in 0..5 */
        double const f = (hsv.h - sector*sectorSize)/60;
            /* The fraction of the way the color is from one side of
               our sector to the other side, going clockwise.  Value is
               in [0, 1).
            */
        double const m = (hsv.v * (1 - hsv.s));
        double const n = (hsv.v * (1 - (hsv.s * f)));
        double const k = (hsv.v * (1 - (hsv.s * (1 - f))));

        switch (sector) {
        case 0:
            R = hsv.v;
            G = k;
            B = m;
            break;
        case 1:
            R = n;
            G = hsv.v;
            B = m;
            break;
        case 2:
            R = m;
            G = hsv.v;
            B = k;
            break;
        case 3:
            R = m;
            G = n;
            B = hsv.v;
            break;
        case 4:
            R = k;
            G = m;
            B = hsv.v;
            break;
        case 5:
            R = hsv.v;
            G = m;
            B = n;
            break;
        default:
            pm_error("Invalid H value passed to color_from_HSV: %f", hsv.h);
        }
    }
    PPM_ASSIGN(retval, 
               ROUNDU(R * maxval),
               ROUNDU(G * maxval),
               ROUNDU(B * maxval));

    return retval;
}