diff options
-rw-r--r-- | editor/specialty/pgmmorphconv.c | 536 |
1 files changed, 336 insertions, 200 deletions
diff --git a/editor/specialty/pgmmorphconv.c b/editor/specialty/pgmmorphconv.c index 5079e19f..e2572081 100644 --- a/editor/specialty/pgmmorphconv.c +++ b/editor/specialty/pgmmorphconv.c @@ -17,263 +17,399 @@ */ #include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" #include "pgm.h" -/************************************************************ - * Dilate - ************************************************************/ -static int -dilate( bit** template, int trowso2, int tcolso2, - gray** in_image, gray** out_image, - int rows, int cols ){ +enum Operation { ERODE, DILATE, OPEN, CLOSE, GRADIENT }; - int c, r, tc, tr; - int templatecount; - gray source; - for( c=0; c<cols; ++c) - for( r=0; r<rows; ++r ) - out_image[r][c] = 0; /* only difference with erode is here and below */ - - /* - * for each non-black pixel of the template - * add in to out - */ - - templatecount=0; - for( tr=-trowso2; tr<=trowso2; ++tr ){ - for( tc=-tcolso2; tc<=tcolso2; ++tc ){ +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + const char * templateFileName; /* File name of template file */ - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; + enum Operation operation; +}; - ++templatecount; - for( r= ((tr>0)?0:-tr) ; r< ((tr>0)?(rows-tr):rows) ; ++r ){ - for( c= ((tc>0)?0:-tc) ; c< ((tc>0)?(cols-tc):cols) ; ++c ){ - source = in_image[r+tr][c+tc]; - out_image[r][c] = MAX(source, out_image[r][c]); - } /* for c */ - } /* for r */ - } /* for tr */ - } /* for tc */ - return templatecount; +static void +parseCommandLine(int argc, const char ** const argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + unsigned int option_def_index; + unsigned int erode, dilate, open, close, gradient; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "erode", OPT_FLAG, NULL, &erode, 0); + OPTENT3(0, "dilate", OPT_FLAG, NULL, &dilate, 0); + OPTENT3(0, "open", OPT_FLAG, NULL, &open, 0); + OPTENT3(0, "close", OPT_FLAG, NULL, &close, 0); + OPTENT3(0, "gradient", OPT_FLAG, NULL, &gradient, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = TRUE; /* We may have 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 (erode + dilate + open + close + gradient > 1) + pm_error("You may specify at most one of -erode, -dilate, " + "-open, -close, or -gradient"); + + if (erode) + cmdlineP->operation = ERODE; + else if (dilate) + cmdlineP->operation = DILATE; + else if (open) + cmdlineP->operation = OPEN; + else if (close) + cmdlineP->operation = CLOSE; + else if (gradient) + cmdlineP->operation = GRADIENT; + else + cmdlineP->operation = DILATE; + + if (argc-1 < 1) + pm_error("You must specify the template file name as an argument"); + else { + cmdlineP->templateFileName = argv[1]; + + if (argc-1 < 2) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[2]; + + if (argc-1 > 2) + pm_error("Too many arguments: %u. " + "The only possible arguments " + "are the template file name and the input file name", + argc-1); + } + } +} -} /* dilate */ +static void +readTemplateMatrix(const char * const fileName, + bit *** const templateP, + unsigned int * const rowsP, + unsigned int * const colsP) { +/*---------------------------------------------------------------------------- + Read in the template matrix. +-----------------------------------------------------------------------------*/ + FILE * templateFileP; + int cols, rows; -/************************************************************ - * Erode: same as dilate except !!!! - ************************************************************/ + templateFileP = pm_openr(fileName); -static int -erode( bit** template, int trowso2, int tcolso2, - gray** in_image, gray** out_image, - int rows, int cols ){ + *templateP = pbm_readpbm(templateFileP, &cols, &rows); - int c, r, tc, tr; - int templatecount; - gray source; + pm_close(templateFileP); - for( c=0; c<cols; ++c) - for( r=0; r<rows; ++r ) - out_image[r][c] = PGM_MAXMAXVAL; /* !!!! */ - - /* - * for each non-black pixel of the template - * add in to out - */ + if (cols % 2 != 1 || rows % 2 != 1) + pm_error("the template matrix must have an odd number of " + "rows and columns" ); - templatecount=0; + /* the reason is that we want the middle pixel to be the origin */ + *rowsP = rows; + *colsP = cols; +} - for( tr=-trowso2; tr<=trowso2; ++tr ){ - for( tc=-tcolso2; tc<=tcolso2; ++tc ){ - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; - ++templatecount; +static void +setAllPixel(gray ** const image, + unsigned int const rows, + unsigned int const cols, + gray const value) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + unsigned int row; + for (row = 0; row < rows; ++row) + image[row][col] = value; + } +} - for( r= ((tr>0)?0:-tr) ; r< ((tr>0)?(rows-tr):rows) ; ++r ){ - for( c= ((tc>0)?0:-tc) ; c< ((tc>0)?(cols-tc):cols) ; ++c ){ - source = in_image[r+tr][c+tc]; - out_image[r][c] = MIN(source, out_image[r][c]); - - } /* for c */ - } /* for r */ +static void +dilate(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + unsigned int templateCount; + int tr; + + setAllPixel(outImage, rows, cols, 0); + + /* for each non-black pixel of the template add in to out */ + + for (tr = -trowso2, templateCount = 0; tr <= trowso2; ++tr) { + int tc; + for (tc = -tcolso2; tc <= tcolso2; ++tc) { + int r; + if (template[trowso2+tr][tcolso2+tc] != PBM_BLACK) { + ++templateCount; + + for (r = ((tr > 0) ? 0 : -tr); + r < ((tr > 0) ? (rows-tr) : rows); + ++r) { + int c; + for (c = ((tc > 0) ? 0 : -tc); + c < ((tc > 0) ? (cols-tc) : cols); + ++c) { + gray const source = inImage[r+tr][c+tc]; + outImage[r][c] = MAX(source, outImage[r][c]); + } + } + } + } + } + *templateCountP = templateCount; +} - } /* for tr */ - } /* for tc */ - return templatecount; +static void +erode(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + unsigned int templateCount; + int tr; + + setAllPixel(outImage, rows, cols, PGM_MAXMAXVAL); + + /* For each non-black pixel of the template add in to out */ + + for (tr = -trowso2, templateCount = 0; tr <= trowso2; ++tr) { + int tc; + for (tc = -tcolso2; tc <= tcolso2; ++tc) { + if (template[trowso2+tr][tcolso2+tc] != PBM_BLACK) { + int r; + ++templateCount; + + for (r = ((tr > 0) ? 0 : -tr); + r < ((tr > 0) ? (rows-tr) : rows); + ++r){ + int c; + + for (c = ((tc > 0) ? 0 : -tc); + c < ((tc > 0) ? (cols-tc) : cols); + ++c) { + + gray const source = inImage[r+tr][c+tc]; + outImage[r][c] = MIN(source, outImage[r][c]); + + } + } + } + } + } + *templateCountP = templateCount; +} -} /* erode */ static void -subtract(gray** in1_image, gray** in2_image, gray** out_image, - int rows, int cols ){ - - int c, r; - - for( c=0; c<cols; ++c) - for( r=0; r<rows; ++r ) - out_image[r][c] = in1_image[r][c] - in2_image[r][c]; +openMorph(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + gray ** erodedImage; + unsigned int erodedTemplateCount; + + erodedImage = pgm_allocarray(cols, rows); + + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, &erodedTemplateCount); + + dilate(template, trowso2, tcolso2, + erodedImage, outputImage, rows, cols, templateCountP); + + pgm_freearray(erodedImage, rows); } -/************************************************************ - * Main - ************************************************************/ +static void +closeMorph(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + gray ** dilatedImage; + unsigned int dilatedTemplateCount; + dilatedImage = pgm_allocarray(cols, rows); -int main( int argc, char* argv[] ){ + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); - int argn; - char operation; - const char* usage = "-dilate|-erode|-open|-close|-gradient <templatefile> [pgmfile]"; + erode(template, trowso2, tcolso2, + dilatedImage, outputImage, rows, cols, templateCountP); - FILE* tifp; /* template */ - int tcols, trows; - int tcolso2, trowso2; - bit** template; + pgm_freearray(dilatedImage, rows); +} - FILE* ifp; /* input image */ - int cols, rows; - gray maxval; - gray** in_image; - gray** out_image; +static void +subtract(gray ** const in1Image, + gray ** const in2Image, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols ) { + + unsigned int c; + + for (c = 0; c < cols; ++c) { + unsigned int r; + for (r = 0; r < rows; ++r) + outImage[r][c] = in1Image[r][c] - in2Image[r][c]; + } +} - int templatecount=0; - pgm_init( &argc, argv ); - /* - * parse arguments - */ - - ifp = stdin; - operation = 'd'; +static void +gradient(bit ** const template, + int const trowso2, + int const tcolso2, + gray ** const inputImage, + gray ** const outputImage, + unsigned int const rows, + unsigned int const cols, + unsigned int * const templateCountP) { + + gray ** dilatedImage; + gray ** erodedImage; + unsigned int dilatedTemplateCount; + + dilatedImage = pgm_allocarray(cols, rows); + erodedImage = pgm_allocarray(cols, rows); + + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); + + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, templateCountP); + + subtract(dilatedImage, erodedImage, outputImage, rows, cols); + + pgm_freearray(erodedImage, rows ); + pgm_freearray(dilatedImage, rows ); +} - argn=1; - - if( argn == argc ) pm_usage( usage ); - - if( pm_keymatch( argv[argn], "-erode", 2 )) { operation='e'; argn++; } - else - if( pm_keymatch( argv[argn], "-dilate", 2 )) { operation='d'; argn++; } - else - if( pm_keymatch( argv[argn], "-open", 2 )) { operation='o'; argn++; } - else - if( pm_keymatch( argv[argn], "-close", 2 )) { operation='c'; argn++; } - else - if( pm_keymatch( argv[argn], "-gradient", 2 )) { operation='g'; argn++; } - - if( argn == argc ) pm_usage( usage ); - - tifp = pm_openr( argv[argn++] ); - - if( argn != argc ) ifp = pm_openr( argv[argn++] ); - if( argn != argc ) pm_usage( usage ); - - /* - * Read in the template matrix. - */ +int +main(int argc, const char ** argv) { - template = pbm_readpbm( tifp, &tcols, &trows ); - pm_close( tifp ); + struct CmdlineInfo cmdline; + FILE * ifP; + bit ** template; + unsigned int templateCols, templateRows; + int cols, rows; + gray maxval; + gray ** inputImage; + gray ** outputImage; + unsigned int templateCount; - if( tcols % 2 != 1 || trows % 2 != 1 ) - pm_error("the template matrix must have an odd number of " - "rows and columns" ); + pm_proginit(&argc, argv); - /* the reason is that we want the middle pixel to be the origin */ - tcolso2 = tcols / 2; /* template coords run from -tcols/2 .. 0 .. +tcols/2 */ - trowso2 = trows / 2; + parseCommandLine(argc, argv, &cmdline); -#if 0 - fprintf(stderr, "template: %d x %d\n", trows, tcols); - fprintf(stderr, "half: %d x %d\n", trowso2, tcolso2); -#endif + ifP = pm_openr(cmdline.inputFileName); - /* - * Read in the image - */ - - in_image = pgm_readpgm( ifp, &cols, &rows, &maxval); + readTemplateMatrix(cmdline.templateFileName, + &template, &templateRows, &templateCols); - if( cols < tcols || rows < trows ) - pm_error("the image is smaller than the convolution matrix" ); + /* Template coords run from -templateCols/2 .. 0 .. + templateCols/2 */ -#if 0 - fprintf(stderr, "image: %d x %d (%d)\n", rows, cols, maxval); -#endif + inputImage = pgm_readpgm(ifP, &cols, &rows, &maxval); - /* - * Allocate output buffer and initialize with min or max value - */ - - out_image = pgm_allocarray( cols, rows ); + if (cols < templateCols || rows < templateRows) + pm_error("the image is smaller than the convolution matrix" ); - if( operation == 'd' ){ - templatecount = dilate(template, trowso2, tcolso2, - in_image, out_image, rows, cols); - } - else if( operation == 'e' ){ - templatecount = erode(template, trowso2, tcolso2, - in_image, out_image, rows, cols); - } - else if( operation == 'o' ){ - gray ** eroded_image; - eroded_image = pgm_allocarray( cols, rows ); - templatecount = erode(template, trowso2, tcolso2, - in_image, eroded_image, rows, cols); - templatecount = dilate(template, trowso2, tcolso2, - eroded_image, out_image, rows, cols); - pgm_freearray( eroded_image, rows ); - } - else if( operation == 'c' ){ - gray ** dilated_image; - dilated_image = pgm_allocarray( cols, rows ); - templatecount = dilate(template, trowso2, tcolso2, - in_image, dilated_image, rows, cols); - templatecount = erode(template, trowso2, tcolso2, - dilated_image, out_image, rows, cols); - pgm_freearray( dilated_image, rows ); - } - else if( operation == 'g' ){ - gray ** dilated_image, ** eroded_image; - dilated_image = pgm_allocarray( cols, rows ); - eroded_image = pgm_allocarray( cols, rows ); - templatecount = dilate(template, trowso2, tcolso2, - in_image, dilated_image, rows, cols); - templatecount = erode(template, trowso2, tcolso2, - in_image, eroded_image, rows, cols); - subtract(dilated_image, eroded_image, out_image, rows, cols); - pgm_freearray( dilated_image, rows ); - pgm_freearray( eroded_image, rows ); - } + outputImage = pgm_allocarray(cols, rows); - if(templatecount == 0 ) pm_error( "The template was empty!" ); - - pgm_writepgm( stdout, out_image, cols, rows, maxval, 1 ); - - pgm_freearray( out_image, rows ); - pgm_freearray( in_image, rows ); - pm_close( ifp ); - - exit( 0 ); - -} /* main */ + switch (cmdline.operation) { + case DILATE: + dilate(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case ERODE: + erode(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case OPEN: + openMorph(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case CLOSE: + closeMorph(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + case GRADIENT: + gradient(template, templateRows/2, templateCols/2, + inputImage, outputImage, rows, cols, + &templateCount); + break; + } + + if (templateCount == 0) + pm_error( "The template was empty!" ); + + pgm_writepgm(stdout, outputImage, cols, rows, maxval, 1); + + pgm_freearray(outputImage, rows); + pgm_freearray(inputImage, rows); + pm_close(ifP); + + return 0; +} |