diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2010-03-10 16:48:32 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2010-03-10 16:48:32 +0000 |
commit | 816786175161b60c34aecfcb66d9fe100ed96bab (patch) | |
tree | 6f71a929ad85afd666eed357667ef5ede403457b /editor | |
parent | 4303fbdc450e651900e0a3cd856c0e56a4392dce (diff) | |
download | netpbm-mirror-816786175161b60c34aecfcb66d9fe100ed96bab.tar.gz netpbm-mirror-816786175161b60c34aecfcb66d9fe100ed96bab.tar.xz netpbm-mirror-816786175161b60c34aecfcb66d9fe100ed96bab.zip |
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1146 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor')
-rw-r--r-- | editor/pbmclean.c | 343 |
1 files changed, 189 insertions, 154 deletions
diff --git a/editor/pbmclean.c b/editor/pbmclean.c index e0ef1445..beecf3e8 100644 --- a/editor/pbmclean.c +++ b/editor/pbmclean.c @@ -1,53 +1,58 @@ -/* pbmclean.c - pixel cleaning. Remove pixel if less than n connected - * identical neighbours, n=1 default. - * AJCD 20/9/90 - * stern, Fri Oct 19 00:10:38 MET DST 2001 - * add '-white/-black' flags to restrict operation to given blobs - */ +/*============================================================================= + pbmclean +=============================================================================== + Pixel cleaner: Remove pixel if less than N connected identical neighbors +=============================================================================*/ +#include <assert.h> #include <stdio.h> #include "pm_c_util.h" -#include "pbm.h" +#include "mallocvar.h" #include "shhopt.h" +#include "pbm.h" struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ + const char * inputFileName; /* File name of input file */ bool flipWhite; bool flipBlack; unsigned int connect; unsigned int verbose; }; + + static void -parseCommandLine(int argc, char ** argv, +parseCommandLine(int argc, const char ** argv, struct cmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ optStruct3 opt; /* set by OPTENT3 */ - optEntry *option_def = malloc(100*sizeof(optEntry)); + optEntry * option_def; unsigned int option_def_index; unsigned int black, white; unsigned int minneighborsSpec; + MALLOCARRAY(option_def, 100); + option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - OPTENT3(0, "black", OPT_FLAG, NULL, &black, 0); - OPTENT3(0, "white", OPT_FLAG, NULL, &white, 0); - OPTENT3(0, "minneighbors", OPT_UINT, &cmdlineP->connect, + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "black", OPT_FLAG, NULL, &black, 0); + OPTENT3(0, "white", OPT_FLAG, NULL, &white, 0); + OPTENT3(0, "minneighbors", OPT_UINT, &cmdlineP->connect, &minneighborsSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We sort of allow negative numbers as parms */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); @@ -91,9 +96,9 @@ parseCommandLine(int argc, char ** argv, } if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 == 1) - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; else pm_error("You specified too many arguments (%d). The only " "argument is the optional input file specification.", @@ -127,6 +132,8 @@ static unsigned int const p[256] = { return p[x]; } + + static unsigned int bitpop24(uint32_t const w){ /*---------------------------------------------------------------------------- @@ -136,11 +143,13 @@ bitpop24(uint32_t const w){ This table lookup method is faster. -----------------------------------------------------------------------------*/ - return ( bitpop8((w>>16) & 0xff) - + bitpop8((w>>8) & 0xff) - + bitpop8(w & 0xff) ); + return (bitpop8((w >> 16) & 0xff) + + bitpop8((w >> 8) & 0xff) + + bitpop8((w >> 0) & 0xff)); } + + /*---------------------------------------------------------------------------- Fast algorithm for counting friendly neighbor pixels @@ -177,8 +186,10 @@ that as a one bit in "flipmask". Bits are flipped in units of eight and written to outrow at the byte boundary. -----------------------------------------------------------------------------*/ + + static unsigned int -likeNeighbors(uint32_t const blackSample, +likeNeighbors(uint32_t const blackSample, unsigned int const offset) { bool const thispoint = ( blackSample >> (18-offset) ) & 0x01; @@ -187,122 +198,126 @@ likeNeighbors(uint32_t const blackSample, : ~ blackSample ; uint32_t const selection = 0x701407; - return ( bitpop24( ( sample >> (7-offset) ) & selection ) ); - + return (bitpop24((sample >> (7-offset)) & selection)); } -static uint32_t -setSample(const bit * const prevrow, - const bit * const thisrow, - const bit * const nextrow, - unsigned int const col){ - uint32_t sample; - int col8 = col/8; - sample = ( ( prevrow[col8 -1] ) << 29 ) - | ( ( prevrow[col8] ) << 21 ) - | ( ( prevrow[col8 +1] & 0x80 ) << 13 ) - | ( ( thisrow[col8 -1] & 0x01 ) << 19 ) - | ( ( thisrow[col8] ) << 11 ) - | ( ( thisrow[col8 +1] & 0x80 ) << 3 ) - | ( ( nextrow[col8 -1] & 0x01 ) << 9 ) - | ( ( nextrow[col8] ) << 1 ) - | ( ( nextrow[col8 +1] & 0x80 ) >> 7 ); +static uint32_t +setSample(const bit * const prevrow, + const bit * const thisrow, + const bit * const nextrow, + unsigned int const col){ - return (sample); + int const col8 = col/8; + uint32_t sample; + + sample = + ((prevrow[col8 - 1] ) << 29) | + ((prevrow[col8] ) << 21) | + ((prevrow[col8 + 1] & 0x80) << 13) | + ((thisrow[col8 - 1] & 0x01) << 19) | + ((thisrow[col8] ) << 11) | + ((thisrow[col8 + 1] & 0x80) << 3) | + ((nextrow[col8 - 1] & 0x01) << 9) | + ((nextrow[col8] ) << 1) | + ((nextrow[col8 + 1] & 0x80) >> 7); + + return sample; } + static unsigned char setTestmask(unsigned char const whiteTestmask, - bool const testWhite, - bool const testBlack) { + bool const testWhite, + bool const testBlack) { /* ----------------------------------------------------------------------- Make a byte pattern of what bits should be tested within a given "thisrow" (current inrow) byte. 0 means test, 1 means skip. - -------------------------------------------------------------------------- */ - - if (testWhite == testBlack) /* Both are TRUE */ - return ( 0x00 ); - else if (testWhite == TRUE) /* testBlack is FALSE */ - return whiteTestmask; - else - return ~ whiteTestmask; +-------------------------------------------------------------------------- */ + if (testWhite == testBlack) { + assert(testWhite); assert(testBlack); + return 0x00; + } else if (testWhite == TRUE) { + assert(!testBlack); + return whiteTestmask; + } else + return ~whiteTestmask; } -static int -cleanrow(const bit * const prevrow, - const bit * const thisrow, - const bit * const nextrow, - bit * const outrow, - int const cols, - unsigned int const threshold, - bool const flipWhite, - bool const flipBlack) { - /* ---------------------------------------------------------------------- + +static void +cleanrow(const bit * const prevrow, + const bit * const thisrow, + const bit * const nextrow, + bit * const outrow, + unsigned int const cols, + unsigned int const threshold, + bool const flipWhite, + bool const flipBlack, + unsigned int * const nFlippedP) { +/* ---------------------------------------------------------------------- Work through row, scanning for bits that require flipping, and write the results to outrow. - Returns the number of bits flipped within this one row. - ------------------------------------------------------------------------- */ - - uint32_t sample; - unsigned char testmask; - unsigned char flipmask=0x00; - unsigned int col; - unsigned int nFlipped =0; - - for ( col=0 ; col < cols ; ++col) { - int const col8 = col/8; - unsigned int const offset = col%8; - - if(offset == 0) { - - if(flipmask != 0x00) { /* Some bits have to be flipped */ - outrow[col8 -1] = thisrow [col8 -1] ^ flipmask; - nFlipped += bitpop8(flipmask); - flipmask = 0x00; - } - else if ( col8 > 0) - outrow[col8 -1] = thisrow [col8 -1]; + Returns the number of bits flipped within this one row as *nFlippedP. +-------------------------------------------------------------------------*/ + uint32_t sample; + unsigned char testmask; + unsigned char flipmask; + unsigned int col; + unsigned int nFlipped; + + flipmask = 0x00; /* initial value */ + nFlipped = 0; /* initial value */ + + for (col=0 ; col < cols ; ++col) { + unsigned int const col8 = col / 8; + unsigned int const offset = col % 8; + + if (offset == 0) { + if (flipmask != 0x00) { + /* Some bits have to be flipped */ + outrow[col8 -1] = thisrow [col8 -1] ^ flipmask; + nFlipped += bitpop8(flipmask); + flipmask = 0x00; + } else if (col8 > 0) + outrow[col8 -1] = thisrow [col8 -1]; + + sample = setSample(prevrow, thisrow, nextrow, col); + testmask = setTestmask(thisrow[col8], flipWhite, flipBlack); + } - sample = setSample(prevrow, thisrow, nextrow, col); - testmask = setTestmask(thisrow[col8], flipWhite, flipBlack); + if (((testmask << offset) & 0x80 ) ==0) { + if (likeNeighbors(sample, offset ) < threshold) + flipmask |= (0x80 >> offset); + } } - if ( ( ( testmask << offset ) & 0x80 ) ==0 ){ - if ( likeNeighbors(sample, offset ) < threshold ) - flipmask |= (0x80 >> offset); + { + /* Write out last byte */ + unsigned int const col8Last = pbm_packed_bytes(cols) -1; + + if (flipmask != 0x00) { + outrow[col8Last] = thisrow[col8Last] ^ flipmask; + nFlipped += bitpop8(flipmask); + } else + outrow[col8Last] = thisrow[col8Last]; } - } - - /* Write out last byte */ - { - unsigned int col8Last = pbm_packed_bytes(cols) -1; - if(flipmask != 0x00) { - outrow[col8Last] = thisrow [col8Last] ^ flipmask; - nFlipped += bitpop8(flipmask); - } - else - outrow[col8Last] = thisrow [col8Last]; - } - - return nFlipped; - + *nFlippedP = nFlipped; } +static void +pbmclean(FILE * const ifP, + FILE * const ofP, + struct cmdlineInfo const cmdline, + double * const nFlippedP) { - -int -main(int argc, char *argv[]) { - - struct cmdlineInfo cmdline; - FILE *ifp; bit ** buffer; bit * prevrow; bit * thisrow; @@ -312,16 +327,7 @@ main(int argc, char *argv[]) { int cols, rows, format; unsigned int row; - double nFlipped = 0; /* Number of pixels we have flipped so far. - Use type double to prevent overflow. */ - - pbm_init( &argc, argv ); - - parseCommandLine(argc, argv, &cmdline); - - ifp = pm_openr(cmdline.inputFilespec); - - pbm_readpbminit(ifp, &cols, &rows, &format); + pbm_readpbminit(ifP, &cols, &rows, &format); /* Initialize input buffers. We add a margin of 8 bits each on the left and right of the rows. @@ -330,64 +336,93 @@ main(int argc, char *argv[]) { ("edgerow") to facilitate the process. */ { - unsigned int i; - buffer = pbm_allocarray_packed(cols+16, 3); - edgerow = pbm_allocrow_packed(cols+16); + unsigned int i; - for(i=0; i < pbm_packed_bytes(cols+16); ++i) - edgerow[i] = 0x00; + buffer = pbm_allocarray_packed(cols+16, 3); + edgerow = pbm_allocrow_packed(cols+16); - for(i=0; i < 3; ++i) /* Add blank (all white) bytes beside the edges */ - buffer[i][0] = buffer[i][ pbm_packed_bytes( cols +16 ) -1 ] = 0x00; + for (i = 0; i < pbm_packed_bytes(cols+16); ++i) + edgerow[i] = 0x00; + + for (i = 0; i < 3; ++i) { + /* Add blank (all white) bytes beside the edges */ + buffer[i][0] = buffer[i][ pbm_packed_bytes( cols +16 ) - 1] = 0x00; + } + thisrow = &edgerow[1]; + nextrow = &buffer[0][1]; - thisrow = &edgerow[1]; - nextrow = &buffer[0][1]; + /* Read the top line into nextrow and clean the right end. */ - /* Read the top line into nextrow and clean the right end. */ + pbm_readpbmrow_packed(ifP, nextrow, cols, format); - pbm_readpbmrow_packed(ifp, nextrow, cols, format); - if (cols%8>0){ - nextrow[pbm_packed_bytes(cols) -1 ] >>= (8 - cols%8); - nextrow[pbm_packed_bytes(cols) -1 ] <<= (8 - cols%8); - } + if (cols % 8 > 0){ + nextrow[pbm_packed_bytes(cols) -1 ] >>= (8 - cols % 8); + nextrow[pbm_packed_bytes(cols) -1 ] <<= (8 - cols % 8); + } } outrow = pbm_allocrow(cols); - pbm_writepbminit(stdout, cols, rows, 0) ; + pbm_writepbminit(ofP, cols, rows, 0) ; + + *nFlippedP = 0; /* none flipped yet */ for (row = 0; row < rows; ++row) { + unsigned int nFlipped; + prevrow = thisrow; /* Slide up the input row window */ thisrow = nextrow; - if( row < rows -1){ - nextrow = &buffer[(row+1)%3][1]; - /* We take the address directly instead of shuffling the rows - with the help of a temporary. This provision is for proper - handling of the initial edgerow. */ - - pbm_readpbmrow_packed(ifp, nextrow, cols, format); - if (cols%8>0){ - nextrow[pbm_packed_bytes(cols) -1 ] >>= (8 - cols%8); - nextrow[pbm_packed_bytes(cols) -1 ] <<= (8 - cols%8); - } - } - else /* Bottom of image. */ - nextrow = & edgerow[1]; + if (row < rows -1){ + nextrow = &buffer[(row+1)%3][1]; + /* We take the address directly instead of shuffling the rows + with the help of a temporary. This provision is for proper + handling of the initial edgerow. + */ + pbm_readpbmrow_packed(ifP, nextrow, cols, format); + if (cols % 8 > 0){ + nextrow[pbm_packed_bytes(cols) -1 ] >>= (8 - cols % 8); + nextrow[pbm_packed_bytes(cols) -1 ] <<= (8 - cols % 8); + } + } else /* Bottom of image. */ + nextrow = & edgerow[1]; - nFlipped += - cleanrow ( prevrow, thisrow, nextrow, outrow, cols, cmdline.connect, - cmdline.flipWhite, cmdline.flipBlack ); + cleanrow(prevrow, thisrow, nextrow, outrow, cols, cmdline.connect, + cmdline.flipWhite, cmdline.flipBlack, &nFlipped); + + *nFlippedP += nFlipped; - pbm_writepbmrow_packed(stdout, outrow, cols, 0) ; + pbm_writepbmrow_packed(ofP, outrow, cols, 0) ; } - pbm_freearray(buffer,3); + pbm_freearray(buffer, 3); pbm_freerow(edgerow); pbm_freerow(outrow); - pm_close(ifp); +} + + + +int +main(int argc, const char *argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + double nFlipped; + /* Number of pixels we have flipped so far. Use type double to + prevent overflow. + */ + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbmclean(ifP, stdout, cmdline, &nFlipped); if (cmdline.verbose) pm_message("%f pixels flipped", nFlipped); + pm_close(ifP); + return 0; } |