diff options
Diffstat (limited to 'editor/specialty/pgmmorphconv.c')
-rw-r--r-- | editor/specialty/pgmmorphconv.c | 520 |
1 files changed, 343 insertions, 177 deletions
diff --git a/editor/specialty/pgmmorphconv.c b/editor/specialty/pgmmorphconv.c index abc4e718..2ba2d62d 100644 --- a/editor/specialty/pgmmorphconv.c +++ b/editor/specialty/pgmmorphconv.c @@ -17,237 +17,403 @@ */ #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 }; + + + +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 */ - int c, r, tc, tr; - int templatecount; - gray source; + enum Operation operation; +}; - 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 ){ +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; - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; + MALLOCARRAY_NOFAIL(option_def, 100); - ++templatecount; + 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); - 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 */ + 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 */ - return templatecount; + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ -} /* dilate */ + 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); + } + } +} + + + +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; + + templateFileP = pm_openr(fileName); + + *templateP = pbm_readpbm(templateFileP, &cols, &rows); + + pm_close(templateFileP); + + if (cols % 2 != 1 || rows % 2 != 1) + pm_error("the template matrix must have an odd number of " + "rows and columns" ); + + /* the reason is that we want the middle pixel to be the origin */ + *rowsP = rows; + *colsP = cols; +} + + + +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; + } +} + + + +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; +} + + + +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: same as dilate except !!!! - ************************************************************/ -static int -erode( bit** template, int trowso2, int tcolso2, - gray** in_image, gray** out_image, - int rows, int cols ){ +static void +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) { - int c, r, tc, tr; - int templatecount; - gray source; + gray ** erodedImage; + unsigned int erodedTemplateCount; - 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 - */ + erodedImage = pgm_allocarray(cols, rows); + + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, &erodedTemplateCount); - templatecount=0; + dilate(template, trowso2, tcolso2, + erodedImage, outputImage, rows, cols, templateCountP); - for( tr=-trowso2; tr<=trowso2; ++tr ){ - for( tc=-tcolso2; tc<=tcolso2; ++tc ){ + pgm_freearray(erodedImage, rows); +} - if( template[trowso2+tr][tcolso2+tc] == PBM_BLACK ) continue; - ++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 ){ +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) { - source = in_image[r+tr][c+tc]; - out_image[r][c] = MIN(source, out_image[r][c]); - - } /* for c */ - } /* for r */ + gray ** dilatedImage; + unsigned int dilatedTemplateCount; + dilatedImage = pgm_allocarray(cols, rows); + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); - } /* for tr */ - } /* for tc */ + erode(template, trowso2, tcolso2, + dilatedImage, outputImage, rows, cols, templateCountP); - return templatecount; + pgm_freearray(dilatedImage, rows); +} -} /* erode */ +static void +subtract(gray ** const subtrahendImage, + gray ** const subtractorImage, + gray ** const outImage, + unsigned int const rows, + unsigned int const cols ) { -/************************************************************ - * Main - ************************************************************/ + /* (I call the minuend the subtrahend and the subtrahend the subtractor, + to be consistent with other arithmetic terminology). + */ + unsigned int c; -int main( int argc, char* argv[] ){ + for (c = 0; c < cols; ++c) { + unsigned int r; + for (r = 0; r < rows; ++r) + outImage[r][c] = subtrahendImage[r][c] - subtractorImage[r][c]; + } +} - int argn; - char operation; - const char* usage = "-dilate|-erode|-open|-close <templatefile> [pgmfile]"; - FILE* tifp; /* template */ - int tcols, trows; - int tcolso2, trowso2; - bit** template; +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) { - FILE* ifp; /* input image */ - int cols, rows; - gray maxval; + gray ** dilatedImage; + gray ** erodedImage; + unsigned int dilatedTemplateCount; + + dilatedImage = pgm_allocarray(cols, rows); + erodedImage = pgm_allocarray(cols, rows); - gray** in_image; - gray** out_image; + dilate(template, trowso2, tcolso2, + inputImage, dilatedImage, rows, cols, &dilatedTemplateCount); - int templatecount=0; + erode(template, trowso2, tcolso2, + inputImage, erodedImage, rows, cols, templateCountP); - pgm_init( &argc, argv ); + subtract(dilatedImage, erodedImage, outputImage, rows, cols); - /* - * parse arguments - */ - - ifp = stdin; - operation = 'd'; + 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++; } - - 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 - - /* - * Allocate output buffer and initialize with min or max value - */ + inputImage = pgm_readpgm(ifP, &cols, &rows, &maxval); - 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 ); - } + 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, 0); + + pgm_freearray(outputImage, rows); + pgm_freearray(inputImage, rows); + pm_close(ifP); + + return 0; +} |