diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2013-12-19 23:18:13 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2013-12-19 23:18:13 +0000 |
commit | f3117dbb027bef24d8d5aaade2ddbd7a8a874792 (patch) | |
tree | 3c2abe696d142925fd01cebec26cb9ad46693600 /generator | |
parent | c2e9cd928e183e09ad9515ec336b2e13ec093019 (diff) | |
download | netpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.tar.gz netpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.tar.xz netpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.zip |
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2067 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r-- | generator/pgmkernel.c | 267 |
1 files changed, 200 insertions, 67 deletions
diff --git a/generator/pgmkernel.c b/generator/pgmkernel.c index b741d596..d6c75cdc 100644 --- a/generator/pgmkernel.c +++ b/generator/pgmkernel.c @@ -1,8 +1,8 @@ -/* pgmkernel.c - generate a portable graymap convolution kernel +/* pgmkernel.c - generate a PGM convolution kernel ** -** Creates a Portable Graymap file containing a convolution filter -** with max value = 255 and minimum value > 127 that can be used as a -** smoothing kernel for pnmconvol. +** Creates a PGM image containing a convolution filter with max value = 255 +** and minimum value > 127 that can be used as a smoothing kernel for +** pnmconvol. ** ** Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical ** Observatory. @@ -16,76 +16,209 @@ */ #include <math.h> -#include "pgm.h" +#include "pm_c_util.h" +#include "shhopt.h" #include "mallocvar.h" +#include "pgm.h" -int -main ( argc, argv ) - int argc; - char *argv[]; -{ - register int i, j; - int argn = 1, ixsize, iysize, maxval = 255; - double fxsize = 0.0, fysize = 0.0, w = 6.0, kxcenter, kycenter, - tmax = 0, *fkernel; - const char *usage = "[-weight f] width [height]"; - - pgm_init( &argc, argv ); - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-weight", 2 )) { - if (++argn >= argc) - pm_usage( usage ); - else if (sscanf(argv[argn], "%lf", &w) != 1) - pm_usage( usage ); - } - else - pm_usage( usage ); - argn++; - } - if (argn == argc) - pm_usage( usage ); - - if (sscanf(argv[argn], "%lf", &fxsize) != 1) - pm_error( "error reading input kernel x size, (%s)\n", argv[argn]); - ++argn; - if (argn == argc - 1) { - if (sscanf(argv[argn], "%lf", &fysize) != 1) - pm_error( "error reading input kernel y size, (%s)\n", argv[argn]); +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int cols; + unsigned int rows; + float weight; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Convert program invocation arguments (argc,argv) into a format the + program can use easily, struct cmdlineInfo. Validate arguments along + the way and exit program with message if invalid. + + Note that some string information we return as *cmdlineP is in the storage + argv[] points to. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int weightSpec; + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "weight", OPT_FLOAT, &cmdlineP->weight, + &weightSpec, 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_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!weightSpec) + cmdlineP->weight = 6.0; + + if (argc-1 < 1) + pm_error("Need at least one argument: size of (square) kernel"); + else if (argc-1 == 1) { + if (atoi(argv[1]) <= 0) + pm_error("Dimension must be a positive number. " + "You specified '%s'", argv[1]); + cmdlineP->cols = atoi(argv[1]); + cmdlineP->rows = atoi(argv[1]); + } else if (argc-1 == 2) { + if (atoi(argv[1]) <= 0) + pm_error("Width must be a positive number. " + "You specified '%s'", argv[1]); + if (atoi(argv[2]) <= 0) + pm_error("Height must be a positive number. " + "You specified '%s'", argv[2]); + cmdlineP->cols = atoi(argv[1]); + cmdlineP->rows = atoi(argv[2]); + } else + pm_error("At most two arguments allowed. " + "You specified %u", argc-1); +} + + + +static double +t(double const dx2, + double const dy2, + double const weight) { +/*---------------------------------------------------------------------------- + The t value for a pixel that is (dx, dy) pixels away from the center of + the kernel, where 'dx2' is SQR(dx) and 'dy2' is SQR(dy), if the distance is + weighted by 'weight'. +-----------------------------------------------------------------------------*/ + + return 1.0 / (1.0 + weight * sqrt(dx2 + dy2)); +} + + + +static double +tMaxAllKernel(unsigned int const cols, + unsigned int const rows, + double const weight) { +/*---------------------------------------------------------------------------- + The maximum t value over all pixels in the kernel, if the kernel is + 'cols' by 'rows' pixels and distance is weighted by 'weight'. +-----------------------------------------------------------------------------*/ + + /* It depends upon whether there is an even or odd number of rows + and columns. If both dimensions are odd, there is a pixel right + at the center, and it has the greatest t value. If both dimensions + are even, the center of the image is in the center of a 4-pixel + square and each of those 4 pixels has the greatest t value. If + one dimension is even and the other odd, the center of the kernel + is midway between two pixels, horizontally or vertically, and one + of those two pixels has the greatest t value. + */ + + double dxMax, dyMax; + + switch (cols % 2 + rows % 2) { + case 0: + dxMax = 0.5; + dyMax = 0.5; + break; + case 1: + dxMax = 0.5; + dyMax = 0.0; + break; + case 2: + dxMax = 0.0; + dyMax = 0.0; } - else if (argn == argc) - fysize = fxsize; - else - pm_usage( usage ); - - if (fxsize <= 1 || fysize <= 1) - pm_usage( usage ); - - kxcenter = (fxsize - 1) / 2.0; - kycenter = (fysize - 1) / 2.0; - ixsize = fxsize + 0.999; - iysize = fysize + 0.999; - MALLOCARRAY(fkernel, ixsize * iysize); - for (i = 0; i < iysize; i++) - for (j = 0; j < ixsize; j++) { - fkernel[i*ixsize+j] = 1.0 / (1.0 + w * sqrt((double) - (i-kycenter)*(i-kycenter)+ - (j-kxcenter)*(j-kxcenter))); - if (tmax < fkernel[i*ixsize+j]) - tmax = fkernel[i*ixsize+j]; - } - /* output PGM header + data (ASCII format only) */ - printf("P2\n%d %d\n%d\n", ixsize, iysize, maxval); + return t(SQR(dxMax), SQR(dyMax), weight); +} + + + +static void +writeKernel(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + gray const maxval, + gray ** const halfKernel, + unsigned int const halfRows) { + + unsigned int row; - for (i = 0; i < iysize; i++, printf("\n")) - for (j = 0; j < ixsize; j++) - printf(" %3d", (int)(maxval * (fkernel[i*ixsize+j] / - (2*tmax) + 0.5))); + pgm_writepgminit(stdout, cols, rows, maxval, 0); + + for (row = 0; row < halfRows; ++row) + pgm_writepgmrow(stdout, halfKernel[row], cols, maxval, 0); + + /* Now write out the same rows in reverse order. */ - exit(0); + for (; row < rows; ++row) + pgm_writepgmrow(stdout, halfKernel[rows-1-row], cols, maxval, 0); } + + +int +main(int argc, const char * argv[]) { + + gray const maxval = 255; + + struct CmdlineInfo cmdline; + unsigned int arows; + int arow; + double xcenter, ycenter; + /* row, column "number" of center of kernel */ + double tMax; + /* The maximum t value over all pixels */ + gray ** destarray; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + xcenter = ((double) cmdline.cols - 1) / 2.0; + ycenter = ((double) cmdline.rows - 1) / 2.0; + + tMax = tMaxAllKernel(cmdline.cols, cmdline.rows, cmdline.weight); + + /* Output matrix is symmetric vertically and horizontally. */ + + arows = (cmdline.rows + 1) / 2; + /* Half the number of rows. Add 1 if odd. */ + destarray = pgm_allocarray(cmdline.cols, arows); + + for (arow = 0; arow < arows; ++arow) { + double const dy2 = SQR(arow - ycenter); + + unsigned int col; + + for (col = 0; col < cmdline.cols; ++col) { + double const dx2 = SQR(col - xcenter); + + double const normalized = t(dx2, dy2, cmdline.weight) / 2 / tMax; + + destarray[arow][col] = destarray[arow][cmdline.cols - col - 1] = + ROUNDU(maxval * (0.5 + normalized)); + } + } + + writeKernel(stdout, cmdline.cols, cmdline.rows, maxval, + destarray, arows); + + pgm_freearray(destarray, arows); + + return 0; +} |