Blame other/pamsummcol.c

Packit 78deda
/******************************************************************************
Packit 78deda
                               pamsummcol
Packit 78deda
*******************************************************************************
Packit 78deda
  Summarize the columns of a PAM image with various functions.
Packit 78deda
Packit 78deda
  By Bryan Henderson, San Jose CA 2004.02.07.
Packit 78deda
Packit 78deda
  Contributed to the public domain
Packit 78deda
Packit 78deda
Packit 78deda
******************************************************************************/
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "pam.h"
Packit 78deda
#include "shhopt.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
Packit 78deda
enum function {FN_ADD, FN_MEAN, FN_MIN, FN_MAX};
Packit 78deda
Packit 78deda
struct cmdlineInfo {
Packit 78deda
    /* All the information the user supplied in the command line,
Packit 78deda
       in a form easy for the program to use.
Packit 78deda
    */
Packit 78deda
    const char *inputFilespec;  /* Filespec of input file */
Packit 78deda
    enum function function;
Packit 78deda
    unsigned int verbose;
Packit 78deda
};
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
parseCommandLine(int argc, char ** const argv,
Packit 78deda
                 struct cmdlineInfo * const cmdlineP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Note that the file spec array we return is stored in the storage that
Packit 78deda
   was passed to us as the argv array.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    optEntry *option_def = malloc(100*sizeof(optEntry));
Packit 78deda
        /* Instructions to OptParseOptions2 on how to parse our options.
Packit 78deda
         */
Packit 78deda
    optStruct3 opt;
Packit 78deda
Packit 78deda
    unsigned int option_def_index;
Packit 78deda
Packit 78deda
    unsigned int sumSpec, meanSpec, minSpec, maxSpec;
Packit 78deda
Packit 78deda
    option_def_index = 0;   /* incremented by OPTENTRY */
Packit 78deda
    OPTENT3(0,   "sum",      OPT_FLAG,  NULL, &sumSpec,           0);
Packit 78deda
    OPTENT3(0,   "mean",     OPT_FLAG,  NULL, &meanSpec,          0);
Packit 78deda
    OPTENT3(0,   "min",      OPT_FLAG,  NULL, &minSpec,           0);
Packit 78deda
    OPTENT3(0,   "max",      OPT_FLAG,  NULL, &maxSpec,           0);
Packit 78deda
    OPTENT3(0,   "verbose",  OPT_FLAG,  NULL, &cmdlineP->verbose, 0);
Packit 78deda
Packit 78deda
    opt.opt_table = option_def;
Packit 78deda
    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
Packit 78deda
    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
Packit 78deda
Packit 78deda
    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
Packit 78deda
        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
Packit 78deda
Packit 78deda
    if (sumSpec + minSpec + maxSpec > 1)
Packit 78deda
        pm_error("You may specify at most one of -sum, -min, and -max");
Packit 78deda
Packit 78deda
    if (sumSpec) {
Packit 78deda
        cmdlineP->function = FN_ADD;
Packit 78deda
    } else if (meanSpec) {
Packit 78deda
        cmdlineP->function = FN_MEAN;
Packit 78deda
    } else if (minSpec) {
Packit 78deda
        cmdlineP->function = FN_MIN;
Packit 78deda
    } else if (maxSpec) {
Packit 78deda
        cmdlineP->function = FN_MAX;
Packit 78deda
    } else 
Packit 78deda
        pm_error("You must specify one of -sum, -min, or -max");
Packit 78deda
        
Packit 78deda
    if (argc-1 > 1)
Packit 78deda
        pm_error("Too many arguments (%d).  File spec is the only argument.",
Packit 78deda
                 argc-1);
Packit 78deda
Packit 78deda
    if (argc-1 < 1)
Packit 78deda
        cmdlineP->inputFilespec = "-";
Packit 78deda
    else 
Packit 78deda
        cmdlineP->inputFilespec = argv[1];
Packit 78deda
    
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
struct accum {
Packit 78deda
    union {
Packit 78deda
        unsigned int sum;
Packit 78deda
        unsigned int min;
Packit 78deda
        unsigned int max;
Packit 78deda
    } u;
Packit 78deda
};
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
createAccumulator(enum function    const function,
Packit 78deda
                  unsigned int     const cols,
Packit 78deda
                  unsigned int     const planes,
Packit 78deda
                  struct accum *** const accumulatorP) {
Packit 78deda
    
Packit 78deda
    struct accum ** accumulator;
Packit 78deda
    unsigned int col;
Packit 78deda
Packit 78deda
    MALLOCARRAY_NOFAIL(accumulator, cols);
Packit 78deda
Packit 78deda
    for (col = 0; col < cols; ++col) {
Packit 78deda
        unsigned int plane;
Packit 78deda
Packit 78deda
        MALLOCARRAY_NOFAIL(accumulator[col], planes);
Packit 78deda
Packit 78deda
        for (plane = 0; plane < planes; ++plane) {
Packit 78deda
            switch(function) {
Packit 78deda
            case FN_ADD:  accumulator[col][plane].u.sum = 0;        break;
Packit 78deda
            case FN_MEAN: accumulator[col][plane].u.sum = 0;        break;
Packit 78deda
            case FN_MIN:  accumulator[col][plane].u.min = UINT_MAX; break;
Packit 78deda
            case FN_MAX:  accumulator[col][plane].u.max = 0;        break;
Packit 78deda
            } 
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    *accumulatorP = accumulator;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
destroyAccumulator(struct accum **    accumulator,
Packit 78deda
                   unsigned int const cols) {
Packit 78deda
Packit 78deda
    unsigned int col;
Packit 78deda
    for (col = 0; col < cols; ++col)
Packit 78deda
        free(accumulator[col]);
Packit 78deda
Packit 78deda
    free(accumulator);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
aggregate(struct pam *    const inpamP,
Packit 78deda
          tuple *         const tupleRow,
Packit 78deda
          enum function   const function,
Packit 78deda
          struct accum ** const accumulator) {
Packit 78deda
Packit 78deda
    unsigned int col;
Packit 78deda
Packit 78deda
    for (col = 0; col < inpamP->width; ++col) {
Packit 78deda
        unsigned int plane;
Packit 78deda
        for (plane = 0; plane < inpamP->depth; ++plane) {
Packit 78deda
            switch(function) {
Packit 78deda
            case FN_ADD:  
Packit 78deda
            case FN_MEAN: 
Packit 78deda
                if (accumulator[col][plane].u.sum > 
Packit 78deda
                    UINT_MAX - tupleRow[col][plane])
Packit 78deda
                    pm_error("Numerical overflow in Column %u", col);
Packit 78deda
                accumulator[col][plane].u.sum += tupleRow[col][plane];
Packit 78deda
            break;
Packit 78deda
            case FN_MIN:  
Packit 78deda
                if (tupleRow[col][plane] < accumulator[col][plane].u.min)
Packit 78deda
                    accumulator[col][plane].u.min = tupleRow[col][plane];
Packit 78deda
                break;
Packit 78deda
            case FN_MAX:
Packit 78deda
                if (tupleRow[col][plane] > accumulator[col][plane].u.min)
Packit 78deda
                    accumulator[col][plane].u.min = tupleRow[col][plane];
Packit 78deda
                break;
Packit 78deda
            } 
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
makeSummaryRow(struct accum ** const accumulator,
Packit 78deda
               unsigned int  const   count,
Packit 78deda
               struct pam *  const   pamP,
Packit 78deda
               enum function const   function,
Packit 78deda
               tuple *       const   tupleRow) {
Packit 78deda
    
Packit 78deda
    unsigned int col;
Packit 78deda
Packit 78deda
    for (col = 0; col < pamP->width; ++col) {
Packit 78deda
        unsigned int plane;
Packit 78deda
        for (plane = 0; plane < pamP->depth; ++plane) {
Packit 78deda
            switch(function) {
Packit 78deda
            case FN_ADD:  
Packit 78deda
                tupleRow[col][plane] = 
Packit 78deda
                    MIN(accumulator[col][plane].u.sum, pamP->maxval);
Packit 78deda
                break;
Packit 78deda
            case FN_MEAN: 
Packit 78deda
                tupleRow[col][plane] = 
Packit 78deda
                    ROUNDU((double)accumulator[col][plane].u.sum / count);
Packit 78deda
                break;
Packit 78deda
            case FN_MIN:  
Packit 78deda
                tupleRow[col][plane] = 
Packit 78deda
                    accumulator[col][plane].u.min;
Packit 78deda
                break;
Packit 78deda
            case FN_MAX:
Packit 78deda
                tupleRow[col][plane] = 
Packit 78deda
                    accumulator[col][plane].u.max;
Packit 78deda
                break;
Packit 78deda
            }
Packit 78deda
        } 
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int argc, char *argv[]) {
Packit 78deda
Packit 78deda
    FILE* ifP;
Packit 78deda
    tuple* inputRow;   /* Row from input image */
Packit 78deda
    tuple* outputRow;  /* Output row */
Packit 78deda
    int row;
Packit 78deda
    struct cmdlineInfo cmdline;
Packit 78deda
    struct pam inpam;   /* Input PAM image */
Packit 78deda
    struct pam outpam;  /* Output PAM image */
Packit 78deda
    struct accum ** accumulator;  /* malloc'ed two-dimensional array */
Packit 78deda
Packit 78deda
    pnm_init( &argc, argv );
Packit 78deda
Packit 78deda
    parseCommandLine(argc, argv, &cmdline);
Packit 78deda
Packit 78deda
    ifP = pm_openr(cmdline.inputFilespec);
Packit 78deda
Packit 78deda
    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
Packit 78deda
Packit 78deda
    createAccumulator(cmdline.function, inpam.width, inpam.depth, 
Packit 78deda
                      &accumulator);
Packit 78deda
Packit 78deda
    inputRow = pnm_allocpamrow(&inpam);
Packit 78deda
Packit 78deda
    outpam = inpam;    /* Initial value -- most fields should be same */
Packit 78deda
    outpam.file = stdout;
Packit 78deda
    outpam.height = 1;
Packit 78deda
Packit 78deda
    pnm_writepaminit(&outpam);
Packit 78deda
Packit 78deda
    outputRow = pnm_allocpamrow(&outpam);
Packit 78deda
Packit 78deda
    for (row = 0; row < inpam.height; row++) {
Packit 78deda
        pnm_readpamrow(&inpam, inputRow);
Packit 78deda
Packit 78deda
        aggregate(&inpam, inputRow, cmdline.function, accumulator);
Packit 78deda
    }
Packit 78deda
    makeSummaryRow(accumulator, inpam.height, &outpam, cmdline.function, 
Packit 78deda
                   outputRow);
Packit 78deda
    pnm_writepamrow(&outpam, outputRow);
Packit 78deda
Packit 78deda
    pnm_freepamrow(outputRow);
Packit 78deda
    pnm_freepamrow(inputRow);
Packit 78deda
    destroyAccumulator(accumulator, inpam.width);
Packit 78deda
    pm_close(inpam.file);
Packit 78deda
    pm_close(outpam.file);
Packit 78deda
    
Packit 78deda
    return 0;
Packit 78deda
}