/* ------------------------------------------------------------------------- // Figure 17.17: Image smoothing - main program. // Figure 17.18: Reading program input data. // Figure 17.19: Reading and writing image files. // Figure 17.20: The smoothing calculation. // ------------------------------------------------------------------------- */ #include "tools.h" #define SIZE 128 typedef unsigned char pixel; /* image element is a pixel */ typedef pixel picture [SIZE][SIZE]; /* image is a square, 128 X 128 */ typedef struct pt { int x, y; } point; typedef struct rect { point ul, lr; } window; /* processing mask */ void setup( stream* infile, stream* outfile, int* masksize ); void read_image( stream infile, picture image ); void write_image( stream outfile, picture image ); void smooth_image( picture im_in, picture im_out, int ms ); pixel average( picture image, window w ); void main( void ) { picture image, new_image; /* original and processed images */ stream infp, outfp; /* streams for input and output images */ int mask_size; /* dimension of processing mask */ banner(); puts( "This program will smooth a greyscale image" ); setup( &infp, &outfp, &mask_size ); read_image( infp, image ); smooth_image( image, new_image, mask_size ); write_image( outfp, new_image ); bye(); } /* ------------------------------------------------------------------------- // Read in the name of the input image file to process, the output // file to send the results to, and the desired processing mask size. // Check data files and the mask size for validity. Errors are fatal. */ void setup( stream* infile, stream* outfile, int* masksize ) { char filename[80]; /* name of image file */ printf( "Please enter name of image file to open: " ); scanf( "%79s",filename ); *infile = fopen( filename, "rb" ); /* open binary file in read mode */ if (*infile == NULL) fatal( "Error: couldn't open input file %s\n", filename ); printf( "Please enter name of file for result image: " ); scanf( "%79s",filename ); *outfile = fopen( filename, "wb" ); /* open binary file in write mode */ if (*outfile == NULL) fatal( "Error: couldn't open output file %s\n", filename ); printf( "Enter size of square smoothing mask: " ); scanf( "%i", masksize ); /* should be 3, 5, 7, 9 or 11 */ if (*masksize % 2 == 0) fatal( "Error: mask size must be an odd number.\n" ); if (*masksize < 3 || *masksize > 11) fatal( "Error: mask size must be in range 3 - 11.\n" ); } /* ------------------------------------------------------------------------ // Image data is read from data file into 2D array. If data file is too // small it causes program termination. */ void read_image( stream infile, picture image ) { int num_bytes; /* actual number of bytes read from file */ num_bytes = fread( image, sizeof(pixel), SIZE * SIZE, infile ); if (num_bytes != SIZE * SIZE) fatal( "Error: input file not of size %3i X %3i\n", SIZE, SIZE ); fclose(infile); } /* ------------------------------------------------------------------------ // New image data is written from 2D array into file. If disk fills up // during write operation it causes program termination. */ void write_image( stream outfile, picture image ) { int num_bytes; /* actual number of bytes written to file */ num_bytes = fwrite( image, sizeof(pixel), SIZE * SIZE, outfile ); if (num_bytes != SIZE * SIZE) fatal( "Error: unable to write entire output file." ); fclose(outfile); } /* ------------------------------------------------------------------------ // Pixel values in original image are recomputed based on calculating // the average pixel value in a window of dimensions ms X ms centered // about each image pixel. */ void smooth_image( picture im_in, picture im_out, int ms ) { int row, col; /* image indices */ window mask; /* boundary limits of processing mask */ for (row = 0; row < SIZE; row++) for (col = 0; col < SIZE; col++) { /* window is normally centered about the current pixel. If */ /* pixel is near the image boundary the complete mask may */ /* not fall entirely within the image and must be resized. */ mask.ul.x = col - ms / 2; if (mask.ul.x < 0) mask.ul.x = 0; mask.ul.y = row - ms / 2; if (mask.ul.y < 0) mask.ul.y = 0; mask.lr.y = row + ms / 2; if (mask.lr.y >= SIZE) mask.lr.y = SIZE-1; mask.lr.x = col + ms / 2; if (mask.lr.x >= SIZE) mask.lr.x = SIZE-1; im_out[row][col] = average( im_in, mask ); /* compute value */ } } /* ------------------------------------------------------------------------ // Compute average value of pixels in bounded window of image. */ pixel average ( picture image, window w ) { const int rmin = w.ul.y, rmax = w.lr.y, /* unpack row mask limits */ cmin = w.ul.x, cmax = w.lr.x; /* unpack column mask limits */ int r, c; /* image indices */ int sum = 0, count = 0; /* sum and pixel count for average */ for (r = rmin; r <= rmax; r++) for (c = cmin; c <= cmax; c++) { sum += image[r][c]; count++; } return sum / count; }