home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pnm / pnmconvol.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  7KB  |  220 lines

  1. /* pnmconvol.c - general MxN convolution on a portable anymap
  2. **
  3. ** Copyright (C) 1989, 1991 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pnm.h"
  14.  
  15. int
  16. main( argc, argv )
  17.     int argc;
  18.     char* argv[];
  19.     {
  20.     FILE* cifp;
  21.     FILE* ifp;
  22.     xel** cxels;
  23.     xel** xelbuf;
  24.     xel* outputrow;
  25.     xel x;
  26.     int argn, crows, ccols, cformat, ccolso2, crowso2;
  27.     int rows, cols, format, newformat, crow, row;
  28.     register int ccol, col;
  29.     xelval cmaxval, maxval;
  30.     xelval g;
  31.     float** gweights;
  32.     float gsum;
  33.     xelval r, b;
  34.     float** rweights;
  35.     float** bweights;
  36.     float rsum, bsum;
  37.     char* usage = "<convolutionfile> [pnmfile]";
  38.  
  39.     pnm_init( &argc, argv );
  40.  
  41.     argn = 1;
  42.  
  43.     if ( argn == argc )
  44.     pm_usage( usage );
  45.     cifp = pm_openr( argv[argn] );
  46.     ++argn;
  47.  
  48.     if ( argn != argc )
  49.     {
  50.     ifp = pm_openr( argv[argn] );
  51.     ++argn;
  52.     }
  53.     else
  54.     ifp = stdin;
  55.  
  56.     if ( argn != argc )
  57.     pm_usage( usage );
  58.  
  59.     pnm_pbmmaxval = PNM_MAXMAXVAL;  /* use larger value for better results */
  60.  
  61.     /* Read in the convolution matrix. */
  62.     cxels = pnm_readpnm( cifp, &ccols, &crows, &cmaxval, &cformat );
  63.     pm_close( cifp );
  64.     if ( ccols % 2 != 1 || crows % 2 != 1 )
  65.     pm_error(
  66.      "the convolution matrix must have an odd number of rows and columns" );
  67.     ccolso2 = ccols / 2;
  68.     crowso2 = crows / 2;
  69.  
  70.     pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
  71.     if ( cols < ccols || rows < crows )
  72.     pm_error(
  73.         "the image is smaller than the convolution matrix" );
  74.  
  75.     newformat = max( PNM_FORMAT_TYPE(cformat), PNM_FORMAT_TYPE(format) );
  76.     if ( PNM_FORMAT_TYPE(cformat) != newformat )
  77.     pnm_promoteformat( cxels, ccols, crows, cmaxval, cformat, cmaxval, newformat );
  78.     if ( PNM_FORMAT_TYPE(format) != newformat )
  79.         {
  80.         switch ( PNM_FORMAT_TYPE(newformat) )
  81.             {
  82.             case PPM_TYPE:
  83.             if ( PNM_FORMAT_TYPE(format) != newformat )
  84.                 pm_message( "promoting to PPM" );
  85.             break;
  86.             case PGM_TYPE:
  87.             if ( PNM_FORMAT_TYPE(format) != newformat )
  88.                 pm_message( "promoting to PGM" );
  89.             break;
  90.             }
  91.         }
  92.  
  93.     /* Set up the normalized weights. */
  94.     rweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
  95.     gweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
  96.     bweights = (float**) pm_allocarray( ccols, crows, sizeof(float) );
  97.     rsum = gsum = bsum = 0;
  98.     for ( crow = 0; crow < crows; ++crow )
  99.     for ( ccol = 0; ccol < ccols; ++ccol )
  100.         {
  101.         switch ( PNM_FORMAT_TYPE(format) )
  102.         {
  103.         case PPM_TYPE:
  104.         rsum += rweights[crow][ccol] =
  105.             ( PPM_GETR(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
  106.         gsum += gweights[crow][ccol] =
  107.             ( PPM_GETG(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
  108.         bsum += bweights[crow][ccol] =
  109.             ( PPM_GETB(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
  110.         break;
  111.  
  112.         default:
  113.         gsum += gweights[crow][ccol] =
  114.             ( PNM_GET1(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 );
  115.         break;
  116.         }
  117.         }
  118.     switch ( PNM_FORMAT_TYPE(format) )
  119.     {
  120.     case PPM_TYPE:
  121.     if ( rsum < 0.9 || rsum > 1.1 || gsum < 0.9 || gsum > 1.1 ||
  122.          bsum < 0.9 || bsum > 1.1 )
  123.         pm_message(
  124.         "WARNING - this convolution matrix is biased" );
  125.     break;
  126.  
  127.     default:
  128.     if ( gsum < 0.9 || gsum > 1.1 )
  129.         pm_message(
  130.          "WARNING - this convolution matrix is biased" );
  131.     break;
  132.     }
  133.  
  134.     /* Allocate space for one convolution-matrix's worth of rows, plus
  135.     ** a row output buffer. */
  136.     xelbuf = pnm_allocarray( cols, crows );
  137.     outputrow = pnm_allocrow( cols );
  138.  
  139.     pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 );
  140.  
  141.     /* Read in one convolution-matrix's worth of image, less one row. */
  142.     for ( row = 0; row < crows - 1; ++row )
  143.     {
  144.     pnm_readpnmrow( ifp, xelbuf[row], cols, maxval, format );
  145.     if ( PNM_FORMAT_TYPE(format) != newformat )
  146.         pnm_promoteformatrow(
  147.         xelbuf[row], cols, maxval, format, maxval, newformat );
  148.     /* Write out just the part we're not going to convolve. */
  149.     if ( row < crowso2 )
  150.         pnm_writepnmrow( stdout, xelbuf[row], cols, maxval, newformat, 0 );
  151.     }
  152.  
  153.     /* Now the rest of the image - read in the row at the end of
  154.     ** xelbuf, and convolve and write out the row in the middle.
  155.     */
  156.     for ( ; row < rows; ++row )
  157.     {
  158.     pnm_readpnmrow( ifp, xelbuf[row % crows], cols, maxval, format );
  159.     if ( PNM_FORMAT_TYPE(format) != newformat )
  160.         pnm_promoteformatrow(
  161.         xelbuf[row % crows], cols, maxval, format, maxval, newformat );
  162.  
  163.     for ( col = 0; col < cols; ++col )
  164.         if ( col < ccolso2 || col >= cols - ccolso2 )
  165.         outputrow[col] = xelbuf[(row - crowso2) % crows][col];
  166.         else
  167.         {
  168.                 switch ( PNM_FORMAT_TYPE(format) )
  169.                     {
  170.                     case PPM_TYPE:
  171.             rsum = gsum = bsum = 0.0;
  172.             for ( crow = 0; crow < crows; ++crow )
  173.             for ( ccol = 0; ccol < ccols; ++ccol )
  174.                 {
  175.                 x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol];
  176.                 rsum += PPM_GETR( x ) * rweights[crow][ccol];
  177.                 gsum += PPM_GETG( x ) * gweights[crow][ccol];
  178.                 bsum += PPM_GETB( x ) * bweights[crow][ccol];
  179.                 }
  180.             if ( rsum < 0.0 ) r = 0;
  181.             else if ( rsum > maxval ) r = maxval;
  182.             else r = rsum + 0.5;
  183.             if ( gsum < 0.0 ) g = 0;
  184.             else if ( gsum > maxval ) g = maxval;
  185.             else g = gsum + 0.5;
  186.             if ( bsum < 0.0 ) b = 0;
  187.             else if ( bsum > maxval ) b = maxval;
  188.             else b = bsum + 0.5;
  189.             PPM_ASSIGN( outputrow[col], r, g, b );
  190.                     break;
  191.  
  192.                     default:
  193.             gsum = 0.0;
  194.             for ( crow = 0; crow < crows; ++crow )
  195.             for ( ccol = 0; ccol < ccols; ++ccol )
  196.                 {
  197.                 x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol];
  198.                 gsum += PNM_GET1( x ) * gweights[crow][ccol];
  199.                 }
  200.             if ( gsum < 0.0 ) g = 0;
  201.             else if ( gsum > maxval ) g = maxval;
  202.             else g = gsum + 0.5;
  203.             PNM_ASSIGN1( outputrow[col], g );
  204.                     break;
  205.                     }
  206.         }
  207.  
  208.     pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 );
  209.     }
  210.     pm_close( ifp );
  211.  
  212.     /* Now write out the remaining unconvolved rows in xelbuf. */
  213.     for ( ; row < rows + crowso2; ++row )
  214.     pnm_writepnmrow(
  215.             stdout, xelbuf[(row-crowso2) % crows], cols, maxval, newformat, 0 );
  216.  
  217.     pm_close( stdout );
  218.     exit( 0 );
  219.     }
  220.