home *** CD-ROM | disk | FTP | other *** search
- /* pnmconvol.c - general MxN convolution on a portable anymap
- **
- ** Copyright (C) 1989, 1991 by Jef Poskanzer.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- */
-
- #include "pnm.h"
-
- int
- main( argc, argv )
- int argc;
- char* argv[];
- {
- FILE* cifp;
- FILE* ifp;
- xel** cxels;
- xel** xelbuf;
- xel* outputrow;
- xel x;
- int argn, crows, ccols, cformat, ccolso2, crowso2;
- int rows, cols, format, newformat, crow, row;
- register int ccol, col;
- xelval cmaxval, maxval;
- xelval g;
- float** gweights;
- float gsum;
- xelval r, b;
- float** rweights;
- float** bweights;
- float rsum, bsum;
- char* usage = "<convolutionfile> [pnmfile]";
-
- pnm_init( &argc, argv );
-
- argn = 1;
-
- if ( argn == argc )
- pm_usage( usage );
- cifp = pm_openr( argv[argn] );
- ++argn;
-
- if ( argn != argc )
- {
- ifp = pm_openr( argv[argn] );
- ++argn;
- }
- else
- ifp = stdin;
-
- if ( argn != argc )
- pm_usage( usage );
-
- pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */
-
- /* Read in the convolution matrix. */
- cxels = pnm_readpnm( cifp, &ccols, &crows, &cmaxval, &cformat );
- pm_close( cifp );
- if ( ccols % 2 != 1 || crows % 2 != 1 )
- pm_error(
- "the convolution matrix must have an odd number of rows and columns" );
- ccolso2 = ccols / 2;
- crowso2 = crows / 2;
-
- pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
- if ( cols < ccols || rows < crows )
- pm_error(
- "the image is smaller than the convolution matrix" );
-
- newformat = max( PNM_FORMAT_TYPE(cformat), PNM_FORMAT_TYPE(format) );
- if ( PNM_FORMAT_TYPE(cformat) != newformat )
- pnm_promoteformat( cxels, ccols, crows, cmaxval, cformat, cmaxval, newformat );
- if ( PNM_FORMAT_TYPE(format) != newformat )
- {
- switch ( PNM_FORMAT_TYPE(newformat) )
- {
- case PPM_TYPE:
- if ( PNM_FORMAT_TYPE(format) != newformat )
- pm_message( "promoting to PPM" );
- break;
- case PGM_TYPE:
- if ( PNM_FORMAT_TYPE(format) != newformat )
- pm_message( "promoting to PGM" );
- break;
- }
- }
-
- /* Set up the normalized weights. */
- rweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
- gweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
- bweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
- rsum = gsum = bsum = 0;
- for ( crow = 0; crow < crows; ++crow )
- for ( ccol = 0; ccol < ccols; ++ccol )
- {
- switch ( PNM_FORMAT_TYPE(format) )
- {
- case PPM_TYPE:
- rsum += rweights[crow][ccol] =
- ( PPM_GETR(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
- gsum += gweights[crow][ccol] =
- ( PPM_GETG(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
- bsum += bweights[crow][ccol] =
- ( PPM_GETB(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
- break;
-
- default:
- gsum += gweights[crow][ccol] =
- ( PNM_GET1(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
- break;
- }
- }
- switch ( PNM_FORMAT_TYPE(format) )
- {
- case PPM_TYPE:
- if ( rsum < 0.9 || rsum > 1.1 || gsum < 0.9 || gsum > 1.1 ||
- bsum < 0.9 || bsum > 1.1 )
- pm_message(
- "WARNING - this convolution matrix is biased" );
- break;
-
- default:
- if ( gsum < 0.9 || gsum > 1.1 )
- pm_message(
- "WARNING - this convolution matrix is biased" );
- break;
- }
-
- /* Allocate space for one convolution-matrix's worth of rows, plus
- ** a row output buffer. */
- xelbuf = pnm_allocarray( cols, crows );
- outputrow = pnm_allocrow( cols );
-
- pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 );
-
- /* Read in one convolution-matrix's worth of image, less one row. */
- for ( row = 0; row < crows - 1; ++row )
- {
- pnm_readpnmrow( ifp, xelbuf[row], cols, maxval, format );
- if ( PNM_FORMAT_TYPE(format) != newformat )
- pnm_promoteformatrow(
- xelbuf[row], cols, maxval, format, maxval, newformat );
- /* Write out just the part we're not going to convolve. */
- if ( row < crowso2 )
- pnm_writepnmrow( stdout, xelbuf[row], cols, maxval, newformat, 0 );
- }
-
- /* Now the rest of the image - read in the row at the end of
- ** xelbuf, and convolve and write out the row in the middle.
- */
- for ( ; row < rows; ++row )
- {
- pnm_readpnmrow( ifp, xelbuf[row % crows], cols, maxval, format );
- if ( PNM_FORMAT_TYPE(format) != newformat )
- pnm_promoteformatrow(
- xelbuf[row % crows], cols, maxval, format, maxval, newformat );
-
- for ( col = 0; col < cols; ++col )
- if ( col < ccolso2 || col >= cols - ccolso2 )
- outputrow[col] = xelbuf[(row - crowso2) % crows][col];
- else
- {
- switch ( PNM_FORMAT_TYPE(format) )
- {
- case PPM_TYPE:
- rsum = gsum = bsum = 0.0;
- for ( crow = 0; crow < crows; ++crow )
- for ( ccol = 0; ccol < ccols; ++ccol )
- {
- x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol];
- rsum += PPM_GETR( x ) * rweights[crow][ccol];
- gsum += PPM_GETG( x ) * gweights[crow][ccol];
- bsum += PPM_GETB( x ) * bweights[crow][ccol];
- }
- if ( rsum < 0.0 ) r = 0;
- else if ( rsum > maxval ) r = maxval;
- else r = rsum + 0.5;
- if ( gsum < 0.0 ) g = 0;
- else if ( gsum > maxval ) g = maxval;
- else g = gsum + 0.5;
- if ( bsum < 0.0 ) b = 0;
- else if ( bsum > maxval ) b = maxval;
- else b = bsum + 0.5;
- PPM_ASSIGN( outputrow[col], r, g, b );
- break;
-
- default:
- gsum = 0.0;
- for ( crow = 0; crow < crows; ++crow )
- for ( ccol = 0; ccol < ccols; ++ccol )
- {
- x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol];
- gsum += PNM_GET1( x ) * gweights[crow][ccol];
- }
- if ( gsum < 0.0 ) g = 0;
- else if ( gsum > maxval ) g = maxval;
- else g = gsum + 0.5;
- PNM_ASSIGN1( outputrow[col], g );
- break;
- }
- }
-
- pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
- }
- pm_close( ifp );
-
- /* Now write out the remaining unconvolved rows in xelbuf. */
- for ( ; row < rows + crowso2; ++row )
- pnm_writepnmrow(
- stdout, xelbuf[(row-crowso2) % crows], cols, maxval, newformat, 0 );
-
- pm_close( stdout );
- exit( 0 );
- }
-