/*============================================================================= pamsumm =============================================================================== Summarize all the samples of a PAM image with various functions. By Bryan Henderson, San Jose CA 2004.02.07. Contributed to the public domain =============================================================================*/ #include "pm_c_util.h" #include "pam.h" #include "shhopt.h" #include "mallocvar.h" enum Function {FN_ADD, FN_MEAN, FN_MIN, FN_MAX}; struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; /* Name of input file */ enum Function function; unsigned int normalize; unsigned int brief; unsigned int verbose; }; static void parseCommandLine(int argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { optEntry * option_def; /* Instructions to OptParseOptions4 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; unsigned int sumSpec, meanSpec, minSpec, maxSpec; MALLOCARRAY(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "sum", OPT_FLAG, NULL, &sumSpec, 0); OPTENT3(0, "mean", OPT_FLAG, NULL, &meanSpec, 0); OPTENT3(0, "min", OPT_FLAG, NULL, &minSpec, 0); OPTENT3(0, "max", OPT_FLAG, NULL, &maxSpec, 0); OPTENT3(0, "normalize", OPT_FLAG, NULL, &cmdlineP->normalize, 0); OPTENT3(0, "brief", OPT_FLAG, NULL, &cmdlineP->brief, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (sumSpec + minSpec + maxSpec + meanSpec > 1) pm_error("You may specify at most one of -sum, -min, -max, and -mean"); if (sumSpec) { cmdlineP->function = FN_ADD; } else if (meanSpec) { cmdlineP->function = FN_MEAN; } else if (minSpec) { cmdlineP->function = FN_MIN; } else if (maxSpec) { cmdlineP->function = FN_MAX; } else pm_error("You must specify one of -sum, -min, -max, or -mean"); if (argc-1 > 1) pm_error("Too many arguments (%d). File name is the only argument.", argc-1); if (argc-1 < 1) cmdlineP->inputFileName = "-"; else cmdlineP->inputFileName = argv[1]; free(option_def); } struct Accum { union { double sum; unsigned int min; unsigned int max; } u; }; static void initAccumulator(struct Accum * const accumulatorP, enum Function const function) { switch(function) { case FN_ADD: accumulatorP->u.sum = 0.0; break; case FN_MEAN: accumulatorP->u.sum = 0.0; break; case FN_MIN: accumulatorP->u.min = UINT_MAX; break; case FN_MAX: accumulatorP->u.max = 0; break; } } static void aggregate(struct pam * const inpamP, tuple * const tupleRow, enum Function const function, struct Accum * const accumulatorP) { unsigned int col; for (col = 0; col < inpamP->width; ++col) { unsigned int plane; for (plane = 0; plane < inpamP->depth; ++plane) { switch(function) { case FN_ADD: case FN_MEAN: accumulatorP->u.sum += tupleRow[col][plane]; break; case FN_MIN: if (tupleRow[col][plane] < accumulatorP->u.min) accumulatorP->u.min = tupleRow[col][plane]; break; case FN_MAX: if (tupleRow[col][plane] > accumulatorP->u.min) accumulatorP->u.min = tupleRow[col][plane]; break; } } } } static void printSummary(struct Accum const accumulator, unsigned int const scale, unsigned int const count, enum Function const function, bool const mustNormalize, bool const brief) { switch (function) { case FN_ADD: { const char * const intro = brief ? "" : "the sum of all samples is "; if (mustNormalize) printf("%s%f\n", intro, accumulator.u.sum/scale); else printf("%s%u\n", intro, (unsigned int)accumulator.u.sum); } break; case FN_MEAN: { const char * const intro = brief ? "" : "the mean of all samples is "; if (mustNormalize) printf("%s%f\n", intro, accumulator.u.sum/count/scale); else printf("%s%f\n", intro, accumulator.u.sum/count); } break; case FN_MIN: { const char * const intro = brief ? "" : "the minimum of all samples is "; if (mustNormalize) printf("%s%f\n", intro, (double)accumulator.u.min/scale); else printf("%s%u\n", intro, accumulator.u.min); } break; case FN_MAX: { const char * const intro = brief ? "" : "the maximum of all samples is "; if (mustNormalize) printf("%s%f\n", intro, (double)accumulator.u.max/scale); else printf("%s%u\n", intro, accumulator.u.max); } break; } } int main(int argc, const char *argv[]) { FILE * ifP; tuple * inputRow; /* Row from input image */ unsigned int row; struct CmdlineInfo cmdline; struct pam inpam; /* Input PAM image */ struct Accum accumulator; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); inputRow = pnm_allocpamrow(&inpam); initAccumulator(&accumulator, cmdline.function); for (row = 0; row < inpam.height; ++row) { pnm_readpamrow(&inpam, inputRow); aggregate(&inpam, inputRow, cmdline.function, &accumulator); } printSummary(accumulator, (unsigned)inpam.maxval, inpam.height * inpam.width * inpam.depth, cmdline.function, cmdline.normalize, cmdline.brief); pnm_freepamrow(inputRow); pm_close(inpam.file); return 0; }