openbsd-ports/graphics/netpbm/patches/patch-an
1999-03-19 01:31:46 +00:00

1873 lines
55 KiB
Plaintext

--- pnm/pnmconvol.c.orig Mon Oct 4 10:11:36 1993
+++ pnm/pnmconvol.c Sun Jan 10 23:48:40 1999
@@ -1,5 +1,10 @@
/* pnmconvol.c - general MxN convolution on a portable anymap
**
+** Version 2.0.1 January 30, 1995
+**
+** Major rewriting by Mike Burns
+** Copyright (C) 1994, 1995 by Mike Burns (burns@chem.psu.edu)
+**
** Copyright (C) 1989, 1991 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
@@ -10,31 +15,109 @@
** implied warranty.
*/
+/* Version 2.0.1 Changes
+** ---------------------
+** Fixed four lines that were improperly allocated as sizeof( float ) when they
+** should have been sizeof( long ).
+**
+** Version 2.0 Changes
+** -------------------
+** Reduce run time by general optimizations and handling special cases of
+** convolution matrices. Program automatically determines if convolution
+** matrix is one of the types it can make use of so no extra command line
+** arguments are necessary.
+**
+** Examples of convolution matrices for the special cases are
+**
+** Mean Horizontal Vertical
+** x x x x x x x y z
+** x x x y y y x y z
+** x x x z z z x y z
+**
+** I don't know if the horizontal and vertical ones are of much use, but
+** after working on the mean convolution, it gave me ideas for the other two.
+**
+** Some other compiler dependent optimizations
+** -------------------------------------------
+** Created separate functions as code was getting too large to put keep both
+** PGM and PPM cases in same function and also because SWITCH statement in
+** inner loop can take progressively more time the larger the size of the
+** convolution matrix. GCC is affected this way.
+**
+** Removed use of MOD (%) operator from innermost loop by modifying manner in
+** which the current xelbuf[] is chosen.
+**
+*/
+
#include "pnm.h"
+/* Macros to verify that r,g,b values are within proper range */
+
+#define CHECK_GRAY \
+ if ( tempgsum < 0L ) g = 0; \
+ else if ( tempgsum > maxval ) g = maxval; \
+ else g = tempgsum;
+
+#define CHECK_RED \
+ if ( temprsum < 0L ) r = 0; \
+ else if ( temprsum > maxval ) r = maxval; \
+ else r = temprsum;
+
+#define CHECK_GREEN \
+ if ( tempgsum < 0L ) g = 0; \
+ else if ( tempgsum > maxval ) g = maxval; \
+ else g = tempgsum;
+
+#define CHECK_BLUE \
+ if ( tempbsum < 0L ) b = 0; \
+ else if ( tempbsum > maxval ) b = maxval; \
+ else b = tempbsum;
+
+
+static int check_convolve_type ARGS((xel **cxels));
+static void pgm_general_convolve ARGS((void));
+static void ppm_general_convolve ARGS((void));
+static void pgm_mean_convolve ARGS((void));
+static void ppm_mean_convolve ARGS((void));
+static void pgm_vertical_convolve ARGS((void));
+static void ppm_vertical_convolve ARGS((void));
+static void pgm_horizontal_convolve ARGS((void));
+static void ppm_horizontal_convolve ARGS((void));
+
+#define TRUE 1
+#define FALSE 0
+
+#define GENERAL_CONVOLVE 0
+#define MEAN_CONVOLVE 1
+#define HORIZONTAL_CONVOLVE 2
+#define VERTICAL_CONVOLVE 3
+
+static FILE* ifp;
+static float** rweights;
+static float** gweights;
+static float** bweights;
+static int crows, ccols, ccolso2, crowso2;
+static int cols, rows;
+static xelval maxval;
+static int format, newformat;
+static float rmeanweight, gmeanweight, bmeanweight;
+
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;
+ int argn, cformat;
+ int crow, row;
register int ccol, col;
- xelval cmaxval, maxval;
+ xelval cmaxval;
xelval g;
- float** gweights;
float gsum;
- xelval r, b;
- float** rweights;
- float** bweights;
float rsum, bsum;
char* usage = "<convolutionfile> [pnmfile]";
+ int convolve_type;
pnm_init( &argc, argv );
@@ -90,6 +173,7 @@
}
}
+
/* Set up the normalized weights. */
rweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
gweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
@@ -115,6 +199,14 @@
break;
}
}
+
+ /* For mean_convolve routines. All weights of a single color are the same
+ ** so just grab any one of them.
+ */
+ rmeanweight = rweights[0][0];
+ gmeanweight = gweights[0][0];
+ bmeanweight = bweights[0][0];
+
switch ( PNM_FORMAT_TYPE(format) )
{
case PPM_TYPE:
@@ -131,11 +223,199 @@
break;
}
+ /* Handle certain special cases when runtime can be improved. */
+
+ convolve_type = check_convolve_type(cxels);
+
+ switch ( PNM_FORMAT_TYPE(format) )
+ {
+ case PPM_TYPE:
+ switch (convolve_type)
+ {
+ case MEAN_CONVOLVE:
+ ppm_mean_convolve();
+ break;
+
+ case HORIZONTAL_CONVOLVE:
+ ppm_horizontal_convolve();
+ break;
+
+ case VERTICAL_CONVOLVE:
+ ppm_vertical_convolve();
+ break;
+
+ default: /* GENERAL_CONVOLVE */
+ ppm_general_convolve();
+ break;
+ }
+ break;
+
+ default:
+ switch (convolve_type)
+ {
+ case MEAN_CONVOLVE:
+ pgm_mean_convolve();
+ break;
+
+ case HORIZONTAL_CONVOLVE:
+ pgm_horizontal_convolve();
+ break;
+
+ case VERTICAL_CONVOLVE:
+ pgm_vertical_convolve();
+ break;
+
+ default: /* GENERAL_CONVOLVE */
+ pgm_general_convolve();
+ break;
+ }
+ break;
+ } /* PNM_TYPE */
+
+ pm_close( ifp );
+ exit( 0 );
+ }
+
+
+
+/* check_convolve_type
+**
+** Determine if the convolution matrix is one of the special cases that
+** can be processed faster than the general form.
+**
+** Does not check for the case where one of the PPM colors can have differing
+** types. Only handles cases where all PPM's are of the same special case.
+*/
+
+static int
+check_convolve_type (cxels)
+ xel **cxels;
+ {
+ int convolve_type;
+ int horizontal, vertical;
+ int tempcxel, rtempcxel, gtempcxel, btempcxel;
+ int crow, ccol;
+
+ switch ( PNM_FORMAT_TYPE(format) )
+ {
+ case PPM_TYPE:
+ horizontal = TRUE;
+ crow = 0;
+ while ( horizontal && (crow < crows) )
+ {
+ ccol = 1;
+ rtempcxel = PPM_GETR(cxels[crow][0]);
+ gtempcxel = PPM_GETG(cxels[crow][0]);
+ btempcxel = PPM_GETB(cxels[crow][0]);
+ while ( horizontal && (ccol < ccols) )
+ {
+ if (( PPM_GETR(cxels[crow][ccol]) != rtempcxel ) |
+ ( PPM_GETG(cxels[crow][ccol]) != gtempcxel ) |
+ ( PPM_GETB(cxels[crow][ccol]) != btempcxel ))
+ horizontal = FALSE;
+ ++ccol;
+ }
+ ++crow;
+ }
+
+ vertical = TRUE;
+ ccol = 0;
+ while ( vertical && (ccol < ccols) )
+ {
+ crow = 1;
+ rtempcxel = PPM_GETR(cxels[0][ccol]);
+ gtempcxel = PPM_GETG(cxels[0][ccol]);
+ btempcxel = PPM_GETB(cxels[0][ccol]);
+ while ( vertical && (crow < crows) )
+ {
+ if (( PPM_GETR(cxels[crow][ccol]) != rtempcxel ) |
+ ( PPM_GETG(cxels[crow][ccol]) != gtempcxel ) |
+ ( PPM_GETB(cxels[crow][ccol]) != btempcxel ))
+ vertical = FALSE;
+ ++crow;
+ }
+ ++ccol;
+ }
+ break;
+
+ default:
+ horizontal = TRUE;
+ crow = 0;
+ while ( horizontal && (crow < crows) )
+ {
+ ccol = 1;
+ tempcxel = PNM_GET1(cxels[crow][0]);
+ while ( horizontal && (ccol < ccols) )
+ {
+ if ( PNM_GET1(cxels[crow][ccol]) != tempcxel )
+ horizontal = FALSE;
+ ++ccol;
+ }
+ ++crow;
+ }
+
+ vertical = TRUE;
+ ccol = 0;
+ while ( vertical && (ccol < ccols) )
+ {
+ crow = 1;
+ tempcxel = PNM_GET1(cxels[0][ccol]);
+ while ( vertical && (crow < crows) )
+ {
+ if ( PNM_GET1(cxels[crow][ccol]) != tempcxel )
+ vertical = FALSE;
+ ++crow;
+ }
+ ++ccol;
+ }
+ break;
+ }
+
+ /* Which type do we have? */
+ if ( horizontal && vertical )
+ convolve_type = MEAN_CONVOLVE;
+ else if ( horizontal )
+ convolve_type = HORIZONTAL_CONVOLVE;
+ else if ( vertical )
+ convolve_type = VERTICAL_CONVOLVE;
+ else
+ convolve_type = GENERAL_CONVOLVE;
+
+ return (convolve_type);
+ }
+
+
+
+
+/* General PGM Convolution
+**
+** No useful redundancy in convolution matrix.
+*/
+
+static void
+pgm_general_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xel x, y;
+ xelval g;
+ int row, crow;
+ float gsum;
+ xel **rowptr, *temprptr;
+ int toprow, temprow;
+ int i, irow;
+ int leftcol;
+ long tempgsum;
+
/* Allocate space for one convolution-matrix's worth of rows, plus
** a row output buffer. */
xelbuf = pnm_allocarray( cols, crows );
outputrow = pnm_allocrow( cols );
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows );
+
pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 );
/* Read in one convolution-matrix's worth of image, less one row. */
@@ -155,65 +435,1470 @@
*/
for ( ; row < rows; ++row )
{
- pnm_readpnmrow( ifp, xelbuf[row % crows], cols, maxval, format );
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
if ( PNM_FORMAT_TYPE(format) != newformat )
pnm_promoteformatrow(
- xelbuf[row % crows], cols, maxval, format, maxval, newformat );
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
for ( col = 0; col < cols; ++col )
+ {
if ( col < ccolso2 || col >= cols - ccolso2 )
- outputrow[col] = xelbuf[(row - crowso2) % crows][col];
+ outputrow[col] = rowptr[crowso2][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;
+ leftcol = col - ccolso2;
+ gsum = 0.0;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ gsum += PNM_GET1( *(temprptr + ccol) )
+ * gweights[crow][ccol];
+ }
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
PNM_ASSIGN1( outputrow[col], g );
- break;
- }
}
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PGM Mean Convolution
+**
+** This is the common case where you just want the target pixel replaced with
+** the average value of its neighbors. This can work much faster than the
+** general case because you can reduce the number of floating point operations
+** that are required since all the weights are the same. You will only need
+** to multiply by the weight once, not for every pixel in the convolution
+** matrix.
+**
+** This algorithm works by creating sums for each column of crows height for
+** the whole width of the image. Then add ccols column sums together to obtain
+** the total sum of the neighbors and multiply that sum by the weight. As you
+** move right to left to calculate the next pixel, take the total sum you just
+** generated, add in the value of the next column and subtract the value of the
+** leftmost column. Multiply that by the weight and that's it. As you move
+** down a row, calculate new column sums by using previous sum for that column
+** and adding in pixel on current row and subtracting pixel in top row.
+**
+*/
+
+
+static void
+pgm_mean_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xelval g;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int toprow, temprow;
+ int subrow, addrow;
+ int subcol, addcol;
+ long gisum;
+ int tempcol, crowsp1;
+ long tempgsum;
+ long *gcolumnsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. MEAN uses an extra row. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf. MEAN uses an extra row. */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1);
+
+ /* Allocate space for intermediate column sums */
+ gcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ for ( col = 0; col < cols; ++col )
+ gcolumnsum[col] = 0L;
+
+ 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 );
+ }
+
+ /* Do first real row only */
+ subrow = crows;
+ addrow = crows - 1;
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ gisum = 0L;
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ gcolumnsum[leftcol + ccol] +=
+ PNM_GET1( *(temprptr + ccol) );
+ }
+ for ( ccol = 0; ccol < ccols; ++ccol)
+ gisum += gcolumnsum[leftcol + ccol];
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ /* Column numbers to subtract or add to isum */
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ gcolumnsum[addcol] += PNM_GET1( rowptr[crow][addcol] );
+ gisum = gisum - gcolumnsum[subcol] + gcolumnsum[addcol];
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ ++row;
+ /* For all subsequent rows do it this way as the columnsums have been
+ ** generated. Now we can use them to reduce further calculations.
+ */
+ crowsp1 = crows + 1;
+ for ( ; row < rows; ++row )
+ {
+ toprow = row + 1;
+ temprow = row % (crows + 1);
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* This rearrangement using crows+1 rowptrs and xelbufs will cause
+ ** rowptr[0..crows-1] to always hold active xelbufs and for
+ ** rowptr[crows] to always hold the oldest (top most) xelbuf.
+ */
+ temprow = (toprow + 1) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ gisum = 0L;
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ tempcol = leftcol + ccol;
+ gcolumnsum[tempcol] = gcolumnsum[tempcol]
+ - PNM_GET1( rowptr[subrow][ccol] )
+ + PNM_GET1( rowptr[addrow][ccol] );
+ gisum += gcolumnsum[tempcol];
+ }
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ /* Column numbers to subtract or add to isum */
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ gcolumnsum[addcol] = gcolumnsum[addcol]
+ - PNM_GET1( rowptr[subrow][addcol] )
+ + PNM_GET1( rowptr[addrow][addcol] );
+ gisum = gisum - gcolumnsum[subcol] + gcolumnsum[addcol];
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
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 )
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
pnm_writepnmrow(
- stdout, xelbuf[(row-crowso2) % crows], cols, maxval, newformat, 0 );
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PGM Horizontal Convolution
+**
+** Similar idea to using columnsums of the Mean and Vertical convolution,
+** but uses temporary sums of row values. Need to multiply by weights crows
+** number of times. Each time a new line is started, must recalculate the
+** initials rowsums for the newest row only. Uses queue to still access
+** previous row sums.
+**
+*/
+
+static void
+pgm_horizontal_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xel x;
+ xelval g;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int temprow;
+ int subcol, addcol;
+ float gsum;
+ int addrow, subrow;
+ long **growsum, **growsumptr;
+ int crowsp1;
+ long tempgsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1);
+
+ /* Allocate intermediate row sums. HORIZONTAL uses an extra row. */
+ /* crows current rows and 1 extra for newest added row. */
+ growsum = (long **) pm_allocarray( cols, crows + 1, sizeof(long) );
+ growsumptr = (long **) pnm_allocarray( 1, crows + 1);
+
+ 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 );
+ }
+
+ /* First row only */
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = (row + 1) % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( crow = 0; crow < crows; ++crow )
+ growsumptr[crow] = growsum[crow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ gsum = 0.0;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ growsumptr[crow][leftcol] = 0L;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ growsumptr[crow][leftcol] +=
+ PNM_GET1( *(temprptr + ccol) );
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ }
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ growsumptr[crow][leftcol] = growsumptr[crow][subcol]
+ - PNM_GET1( rowptr[crow][subcol] )
+ + PNM_GET1( rowptr[crow][addcol] );
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ }
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+
+
+ /* For all subsequent rows */
+
+ subrow = crows;
+ addrow = crows - 1;
+ crowsp1 = crows + 1;
+ ++row;
+ for ( ; row < rows; ++row )
+ {
+ temprow = row % crowsp1;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = (row + 2) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ {
+ rowptr[i] = xelbuf[irow];
+ growsumptr[i] = growsum[irow];
+ }
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ {
+ rowptr[i] = xelbuf[irow];
+ growsumptr[i] = growsum[irow];
+ }
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ growsumptr[addrow][leftcol] = 0L;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ growsumptr[addrow][leftcol] +=
+ PNM_GET1( rowptr[addrow][leftcol + ccol] );
+ for ( crow = 0; crow < crows; ++crow )
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ growsumptr[addrow][leftcol] = growsumptr[addrow][subcol]
+ - PNM_GET1( rowptr[addrow][subcol] )
+ + PNM_GET1( rowptr[addrow][addcol] );
+ for ( crow = 0; crow < crows; ++crow )
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PGM Vertical Convolution
+**
+** Uses column sums as in Mean Convolution.
+**
+*/
+
+
+static void
+pgm_vertical_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xelval g;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int toprow, temprow;
+ int subrow, addrow;
+ int tempcol;
+ float gsum;
+ long *gcolumnsum;
+ int crowsp1;
+ int addcol;
+ long tempgsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. VERTICAL uses an extra row. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1 );
+
+ /* Allocate space for intermediate column sums */
+ gcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ for ( col = 0; col < cols; ++col )
+ gcolumnsum[col] = 0L;
+
+ 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 first row only */
+
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ gcolumnsum[leftcol + ccol] +=
+ PNM_GET1( *(temprptr + ccol) );
+ }
+ for ( ccol = 0; ccol < ccols; ++ccol)
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ gcolumnsum[addcol] += PNM_GET1( rowptr[crow][addcol] );
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+
+ /* For all subsequent rows */
+ subrow = crows;
+ addrow = crows - 1;
+ crowsp1 = crows + 1;
+ ++row;
+ for ( ; row < rows; ++row )
+ {
+ toprow = row + 1;
+ temprow = row % (crows +1);
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = (toprow + 1) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ tempcol = leftcol + ccol;
+ gcolumnsum[tempcol] = gcolumnsum[tempcol]
+ - PNM_GET1( rowptr[subrow][ccol] )
+ + PNM_GET1( rowptr[addrow][ccol] );
+ gsum = gsum + gcolumnsum[tempcol] * gweights[0][ccol];
+ }
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ else
+ {
+ gsum = 0.0;
+ leftcol = col - ccolso2;
+ addcol = col + ccolso2;
+ gcolumnsum[addcol] = gcolumnsum[addcol]
+ - PNM_GET1( rowptr[subrow][addcol] )
+ + PNM_GET1( rowptr[addrow][addcol] );
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ tempgsum = gsum + 0.5;
+ CHECK_GRAY;
+ PNM_ASSIGN1( outputrow[col], g );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+
+
+/* PPM General Convolution Algorithm
+**
+** No redundancy in convolution matrix. Just use brute force.
+** See pgm_general_convolve() for more details.
+*/
+
+static void
+ppm_general_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xel x, y;
+ xelval r, g, b;
+ int row, crow;
+ float rsum, gsum, bsum;
+ xel **rowptr, *temprptr;
+ int toprow, temprow;
+ int i, irow;
+ int leftcol;
+ long temprsum, tempgsum, tempbsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. */
+ xelbuf = pnm_allocarray( cols, crows );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows );
+
+ 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 )
+ {
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else
+ {
+ leftcol = col - ccolso2;
+ rsum = gsum = bsum = 0.0;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rsum += PPM_GETR( *(temprptr + ccol) )
+ * rweights[crow][ccol];
+ gsum += PPM_GETG( *(temprptr + ccol) )
+ * gweights[crow][ccol];
+ bsum += PPM_GETB( *(temprptr + ccol) )
+ * bweights[crow][ccol];
+ }
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PPM Mean Convolution
+**
+** Same as pgm_mean_convolve() but for PPM.
+**
+*/
+
+static void
+ppm_mean_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xelval r, g, b;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int toprow, temprow;
+ int subrow, addrow;
+ int subcol, addcol;
+ long risum, gisum, bisum;
+ float rsum, gsum, bsum;
+ long temprsum, tempgsum, tempbsum;
+ int tempcol, crowsp1;
+ long *rcolumnsum, *gcolumnsum, *bcolumnsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. MEAN uses an extra row. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf. MEAN uses an extra row. */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1);
+
+ /* Allocate space for intermediate column sums */
+ rcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ gcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ bcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ for ( col = 0; col < cols; ++col )
+ {
+ rcolumnsum[col] = 0L;
+ gcolumnsum[col] = 0L;
+ bcolumnsum[col] = 0L;
+ }
+
+ 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 );
+ }
+
+ /* Do first real row only */
+ subrow = crows;
+ addrow = crows - 1;
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ risum = 0L;
+ gisum = 0L;
+ bisum = 0L;
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rcolumnsum[leftcol + ccol] +=
+ PPM_GETR( *(temprptr + ccol) );
+ gcolumnsum[leftcol + ccol] +=
+ PPM_GETG( *(temprptr + ccol) );
+ bcolumnsum[leftcol + ccol] +=
+ PPM_GETB( *(temprptr + ccol) );
+ }
+ }
+ for ( ccol = 0; ccol < ccols; ++ccol)
+ {
+ risum += rcolumnsum[leftcol + ccol];
+ gisum += gcolumnsum[leftcol + ccol];
+ bisum += bcolumnsum[leftcol + ccol];
+ }
+ temprsum = (float) risum * rmeanweight + 0.5;
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ tempbsum = (float) bisum * bmeanweight + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ /* Column numbers to subtract or add to isum */
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rcolumnsum[addcol] += PPM_GETR( rowptr[crow][addcol] );
+ gcolumnsum[addcol] += PPM_GETG( rowptr[crow][addcol] );
+ bcolumnsum[addcol] += PPM_GETB( rowptr[crow][addcol] );
+ }
+ risum = risum - rcolumnsum[subcol] + rcolumnsum[addcol];
+ gisum = gisum - gcolumnsum[subcol] + gcolumnsum[addcol];
+ bisum = bisum - bcolumnsum[subcol] + bcolumnsum[addcol];
+ temprsum = (float) risum * rmeanweight + 0.5;
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ tempbsum = (float) bisum * bmeanweight + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+
+ ++row;
+ /* For all subsequent rows do it this way as the columnsums have been
+ ** generated. Now we can use them to reduce further calculations.
+ */
+ crowsp1 = crows + 1;
+ for ( ; row < rows; ++row )
+ {
+ toprow = row + 1;
+ temprow = row % (crows + 1);
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* This rearrangement using crows+1 rowptrs and xelbufs will cause
+ ** rowptr[0..crows-1] to always hold active xelbufs and for
+ ** rowptr[crows] to always hold the oldest (top most) xelbuf.
+ */
+ temprow = (toprow + 1) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ risum = 0L;
+ gisum = 0L;
+ bisum = 0L;
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ tempcol = leftcol + ccol;
+ rcolumnsum[tempcol] = rcolumnsum[tempcol]
+ - PPM_GETR( rowptr[subrow][ccol] )
+ + PPM_GETR( rowptr[addrow][ccol] );
+ risum += rcolumnsum[tempcol];
+ gcolumnsum[tempcol] = gcolumnsum[tempcol]
+ - PPM_GETG( rowptr[subrow][ccol] )
+ + PPM_GETG( rowptr[addrow][ccol] );
+ gisum += gcolumnsum[tempcol];
+ bcolumnsum[tempcol] = bcolumnsum[tempcol]
+ - PPM_GETB( rowptr[subrow][ccol] )
+ + PPM_GETB( rowptr[addrow][ccol] );
+ bisum += bcolumnsum[tempcol];
+ }
+ temprsum = (float) risum * rmeanweight + 0.5;
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ tempbsum = (float) bisum * bmeanweight + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ /* Column numbers to subtract or add to isum */
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ rcolumnsum[addcol] = rcolumnsum[addcol]
+ - PPM_GETR( rowptr[subrow][addcol] )
+ + PPM_GETR( rowptr[addrow][addcol] );
+ risum = risum - rcolumnsum[subcol] + rcolumnsum[addcol];
+ gcolumnsum[addcol] = gcolumnsum[addcol]
+ - PPM_GETG( rowptr[subrow][addcol] )
+ + PPM_GETG( rowptr[addrow][addcol] );
+ gisum = gisum - gcolumnsum[subcol] + gcolumnsum[addcol];
+ bcolumnsum[addcol] = bcolumnsum[addcol]
+ - PPM_GETB( rowptr[subrow][addcol] )
+ + PPM_GETB( rowptr[addrow][addcol] );
+ bisum = bisum - bcolumnsum[subcol] + bcolumnsum[addcol];
+ temprsum = (float) risum * rmeanweight + 0.5;
+ tempgsum = (float) gisum * gmeanweight + 0.5;
+ tempbsum = (float) bisum * bmeanweight + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PPM Horizontal Convolution
+**
+** Same as pgm_horizontal_convolve()
+**
+**/
+
+static void
+ppm_horizontal_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xel x;
+ xelval r, g, b;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int temprow;
+ int subcol, addcol;
+ float rsum, gsum, bsum;
+ int addrow, subrow;
+ long **rrowsum, **rrowsumptr;
+ long **growsum, **growsumptr;
+ long **browsum, **browsumptr;
+ int crowsp1;
+ long temprsum, tempgsum, tempbsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1);
+
+ /* Allocate intermediate row sums. HORIZONTAL uses an extra row */
+ rrowsum = (long **) pm_allocarray( cols, crows + 1, sizeof(long) );
+ rrowsumptr = (long **) pnm_allocarray( 1, crows + 1);
+ growsum = (long **) pm_allocarray( cols, crows + 1, sizeof(long) );
+ growsumptr = (long **) pnm_allocarray( 1, crows + 1);
+ browsum = (long **) pm_allocarray( cols, crows + 1, sizeof(long) );
+ browsumptr = (long **) pnm_allocarray( 1, crows + 1);
+
+ 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 );
+ }
+
+ /* First row only */
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = (row + 1) % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rrowsumptr[crow] = rrowsum[crow];
+ growsumptr[crow] = growsum[crow];
+ browsumptr[crow] = browsum[crow];
+ }
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ leftcol = col - ccolso2;
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ rrowsumptr[crow][leftcol] = 0L;
+ growsumptr[crow][leftcol] = 0L;
+ browsumptr[crow][leftcol] = 0L;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rrowsumptr[crow][leftcol] +=
+ PPM_GETR( *(temprptr + ccol) );
+ growsumptr[crow][leftcol] +=
+ PPM_GETG( *(temprptr + ccol) );
+ browsumptr[crow][leftcol] +=
+ PPM_GETB( *(temprptr + ccol) );
+ }
+ rsum += rrowsumptr[crow][leftcol] * rweights[crow][0];
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ bsum += browsumptr[crow][leftcol] * bweights[crow][0];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rrowsumptr[crow][leftcol] = rrowsumptr[crow][subcol]
+ - PPM_GETR( rowptr[crow][subcol] )
+ + PPM_GETR( rowptr[crow][addcol] );
+ rsum += rrowsumptr[crow][leftcol] * rweights[crow][0];
+ growsumptr[crow][leftcol] = growsumptr[crow][subcol]
+ - PPM_GETG( rowptr[crow][subcol] )
+ + PPM_GETG( rowptr[crow][addcol] );
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ browsumptr[crow][leftcol] = browsumptr[crow][subcol]
+ - PPM_GETB( rowptr[crow][subcol] )
+ + PPM_GETB( rowptr[crow][addcol] );
+ bsum += browsumptr[crow][leftcol] * bweights[crow][0];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+
+
+ /* For all subsequent rows */
+
+ subrow = crows;
+ addrow = crows - 1;
+ crowsp1 = crows + 1;
+ ++row;
+ for ( ; row < rows; ++row )
+ {
+ temprow = row % crowsp1;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ temprow = (row + 2) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ {
+ rowptr[i] = xelbuf[irow];
+ rrowsumptr[i] = rrowsum[irow];
+ growsumptr[i] = growsum[irow];
+ browsumptr[i] = browsum[irow];
+ }
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ {
+ rowptr[i] = xelbuf[irow];
+ rrowsumptr[i] = rrowsum[irow];
+ growsumptr[i] = growsum[irow];
+ browsumptr[i] = browsum[irow];
+ }
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ rrowsumptr[addrow][leftcol] = 0L;
+ growsumptr[addrow][leftcol] = 0L;
+ browsumptr[addrow][leftcol] = 0L;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rrowsumptr[addrow][leftcol] +=
+ PPM_GETR( rowptr[addrow][leftcol + ccol] );
+ growsumptr[addrow][leftcol] +=
+ PPM_GETG( rowptr[addrow][leftcol + ccol] );
+ browsumptr[addrow][leftcol] +=
+ PPM_GETB( rowptr[addrow][leftcol + ccol] );
+ }
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rsum += rrowsumptr[crow][leftcol] * rweights[crow][0];
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ bsum += browsumptr[crow][leftcol] * bweights[crow][0];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ subcol = col - ccolso2 - 1;
+ addcol = col + ccolso2;
+ rrowsumptr[addrow][leftcol] = rrowsumptr[addrow][subcol]
+ - PPM_GETR( rowptr[addrow][subcol] )
+ + PPM_GETR( rowptr[addrow][addcol] );
+ growsumptr[addrow][leftcol] = growsumptr[addrow][subcol]
+ - PPM_GETG( rowptr[addrow][subcol] )
+ + PPM_GETG( rowptr[addrow][addcol] );
+ browsumptr[addrow][leftcol] = browsumptr[addrow][subcol]
+ - PPM_GETB( rowptr[addrow][subcol] )
+ + PPM_GETB( rowptr[addrow][addcol] );
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rsum += rrowsumptr[crow][leftcol] * rweights[crow][0];
+ gsum += growsumptr[crow][leftcol] * gweights[crow][0];
+ bsum += browsumptr[crow][leftcol] * bweights[crow][0];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
+
+ pm_close( stdout );
+ }
+
+
+/* PPM Vertical Convolution
+**
+** Same as pgm_vertical_convolve()
+**
+*/
+
+static void
+ppm_vertical_convolve()
+ {
+ register int ccol, col;
+ xel** xelbuf;
+ xel* outputrow;
+ xelval r, g, b;
+ int row, crow;
+ xel **rowptr, *temprptr;
+ int leftcol;
+ int i, irow;
+ int toprow, temprow;
+ int subrow, addrow;
+ int tempcol;
+ float rsum, gsum, bsum;
+ long *rcolumnsum, *gcolumnsum, *bcolumnsum;
+ int crowsp1;
+ int addcol;
+ long temprsum, tempgsum, tempbsum;
+
+ /* Allocate space for one convolution-matrix's worth of rows, plus
+ ** a row output buffer. VERTICAL uses an extra row. */
+ xelbuf = pnm_allocarray( cols, crows + 1 );
+ outputrow = pnm_allocrow( cols );
+
+ /* Allocate array of pointers to xelbuf */
+ rowptr = (xel **) pnm_allocarray( 1, crows + 1 );
+
+ /* Allocate space for intermediate column sums */
+ rcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ gcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ bcolumnsum = (long *) pm_allocrow( cols, sizeof(long) );
+ for ( col = 0; col < cols; ++col )
+ {
+ rcolumnsum[col] = 0L;
+ gcolumnsum[col] = 0L;
+ bcolumnsum[col] = 0L;
+ }
+
+ 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 first row only */
+
+ toprow = row + 1;
+ temprow = row % crows;
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = toprow % crows;
+ i = 0;
+ for (irow = temprow; irow < crows; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ temprptr = rowptr[crow] + leftcol;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rcolumnsum[leftcol + ccol] +=
+ PPM_GETR( *(temprptr + ccol) );
+ gcolumnsum[leftcol + ccol] +=
+ PPM_GETG( *(temprptr + ccol) );
+ bcolumnsum[leftcol + ccol] +=
+ PPM_GETB( *(temprptr + ccol) );
+ }
+ }
+ for ( ccol = 0; ccol < ccols; ++ccol)
+ {
+ rsum += rcolumnsum[leftcol + ccol] * rweights[0][ccol];
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ bsum += bcolumnsum[leftcol + ccol] * bweights[0][ccol];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ addcol = col + ccolso2;
+ for ( crow = 0; crow < crows; ++crow )
+ {
+ rcolumnsum[addcol] += PPM_GETR( rowptr[crow][addcol] );
+ gcolumnsum[addcol] += PPM_GETG( rowptr[crow][addcol] );
+ bcolumnsum[addcol] += PPM_GETB( rowptr[crow][addcol] );
+ }
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rsum += rcolumnsum[leftcol + ccol] * rweights[0][ccol];
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ bsum += bcolumnsum[leftcol + ccol] * bweights[0][ccol];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+
+ /* For all subsequent rows */
+ subrow = crows;
+ addrow = crows - 1;
+ crowsp1 = crows + 1;
+ ++row;
+ for ( ; row < rows; ++row )
+ {
+ toprow = row + 1;
+ temprow = row % (crows +1);
+ pnm_readpnmrow( ifp, xelbuf[temprow], cols, maxval, format );
+ if ( PNM_FORMAT_TYPE(format) != newformat )
+ pnm_promoteformatrow(
+ xelbuf[temprow], cols, maxval, format, maxval, newformat );
+
+ /* Arrange rowptr to eliminate the use of mod function to determine
+ ** which row of xelbuf is 0...crows. Mod function can be very costly.
+ */
+ temprow = (toprow + 1) % crowsp1;
+ i = 0;
+ for (irow = temprow; irow < crowsp1; ++i, ++irow)
+ rowptr[i] = xelbuf[irow];
+ for (irow = 0; irow < temprow; ++irow, ++i)
+ rowptr[i] = xelbuf[irow];
+
+ for ( col = 0; col < cols; ++col )
+ {
+ if ( col < ccolso2 || col >= cols - ccolso2 )
+ outputrow[col] = rowptr[crowso2][col];
+ else if ( col == ccolso2 )
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ tempcol = leftcol + ccol;
+ rcolumnsum[tempcol] = rcolumnsum[tempcol]
+ - PPM_GETR( rowptr[subrow][ccol] )
+ + PPM_GETR( rowptr[addrow][ccol] );
+ rsum = rsum + rcolumnsum[tempcol] * rweights[0][ccol];
+ gcolumnsum[tempcol] = gcolumnsum[tempcol]
+ - PPM_GETG( rowptr[subrow][ccol] )
+ + PPM_GETG( rowptr[addrow][ccol] );
+ gsum = gsum + gcolumnsum[tempcol] * gweights[0][ccol];
+ bcolumnsum[tempcol] = bcolumnsum[tempcol]
+ - PPM_GETB( rowptr[subrow][ccol] )
+ + PPM_GETB( rowptr[addrow][ccol] );
+ bsum = bsum + bcolumnsum[tempcol] * bweights[0][ccol];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ else
+ {
+ rsum = 0.0;
+ gsum = 0.0;
+ bsum = 0.0;
+ leftcol = col - ccolso2;
+ addcol = col + ccolso2;
+ rcolumnsum[addcol] = rcolumnsum[addcol]
+ - PPM_GETR( rowptr[subrow][addcol] )
+ + PPM_GETR( rowptr[addrow][addcol] );
+ gcolumnsum[addcol] = gcolumnsum[addcol]
+ - PPM_GETG( rowptr[subrow][addcol] )
+ + PPM_GETG( rowptr[addrow][addcol] );
+ bcolumnsum[addcol] = bcolumnsum[addcol]
+ - PPM_GETB( rowptr[subrow][addcol] )
+ + PPM_GETB( rowptr[addrow][addcol] );
+ for ( ccol = 0; ccol < ccols; ++ccol )
+ {
+ rsum += rcolumnsum[leftcol + ccol] * rweights[0][ccol];
+ gsum += gcolumnsum[leftcol + ccol] * gweights[0][ccol];
+ bsum += bcolumnsum[leftcol + ccol] * bweights[0][ccol];
+ }
+ temprsum = rsum + 0.5;
+ tempgsum = gsum + 0.5;
+ tempbsum = bsum + 0.5;
+ CHECK_RED;
+ CHECK_GREEN;
+ CHECK_BLUE;
+ PPM_ASSIGN( outputrow[col], r, g, b );
+ }
+ }
+ pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
+ }
+
+ /* Now write out the remaining unconvolved rows in xelbuf. */
+ for ( irow = crowso2 + 1; irow < crows; ++irow )
+ pnm_writepnmrow(
+ stdout, rowptr[irow], cols, maxval, newformat, 0 );
pm_close( stdout );
- exit( 0 );
}