#include /*****************************************************************************/ /* ucmain.c */ /*---------------------------------------------------------------------------*/ /* Main section of code for the canny edge detector */ /*---------------------------------------------------------------------------*/ /* PURPOSE: Detect edge points in an image. INPUT: (Non-interactive) - Pointer to the image data in row-major order (256 grey-levels, 1 byte per pixel) - Width of image - Height of image - Standard Deviation (sigma) of gaussian filter - Low gradient threshold for edge labeling - high gradient threshold for edge labeling - Pointer to the pointer to the edge list structure to return COMMENTS: */ /*****************************************************************************/ /* INCLUDE FILES */ #include "uc.h" #include "sys/types.h" #include "imgformat.h" /* Global variables */ PGMImage *pgmimage ; double sigma = 0.4 ; int mask = 3 ; float low_threshold = 1.4 ; float high_threshold = 2.0 ; int XSIZE = 128 ; int YSIZE = 128 ; int Sub_pixel = FALSE ; char outfile[MAXPATHLEN] ; /* defalut output file name */ char infile[MAXPATHLEN] ; /* defalut output file name */ /* Statistical counters (more Globals) */ int NUM_JCTS = 0 ; int NUM_EDGELS = 0 ; int NUM_EDGES = 0 ; unsigned short *Record_image = NULL ; unsigned short *image = NULL ; unsigned short *timage = NULL ; /* Hash table of edgels */ edgel **edgels = NULL ; edgel *tedgels = NULL ; edge *edges = NULL ; edge *tedges = NULL ; args_t args[] = { ARG_DEF("i", TRUE, STRING, MAXPATHLEN, infile, "the name of the PGM or PPM image file for input"), ARG_DEF("s", FALSE, FLOAT, 1, &sigma, "the sigma value used for convolution (default 0.4)"), ARG_DEF("m", FALSE, INT, 1, &mask, "the size of the full mask used for convolution (default 4*sigma)"), ARG_DEF("lt", FALSE, FLOAT, 1, &low_threshold, "the low threshold value (default 1.4)"), ARG_DEF("ht", FALSE, FLOAT, 1, &high_threshold, "the low threshold value (default 2.0)"), ARG_DEF("sp", FALSE, BOOLEAN, 1, &Sub_pixel, "print out sub-pixel localized values (default FALSE)"), ARG_DEF("o", TRUE, STRING, MAXPATHLEN, outfile, "the name of the file to store the connectivity list"), ARG_LAST } ; void canny() ; /* External functions */ extern void convolve() ; extern void local_extrema() ; extern void join_edges() ; extern void write_file() ; extern void args_parse() ; /* External utility functions */ extern PGMImage *read_pgm_file() ; extern void write_pgm_file() ; extern void free_pgm_data() ; /************************************************************* * These are added by Selim on 4/12/2001. *************************************************************/ #include "memory.h" extern PPMImage *read_ppm_file( char * ) ; extern void free_ppm_data( PPMImage * ) ; void main(int argc, char **argv) { /************************************************************* * These variables are added by Selim on 4/12/2001. *************************************************************/ PPMImage *ppmimage; char cbuf[3]; int r, c; FILE *f; /*************************************************************/ /* Parse the command-line arguments */ args_parse(argc, argv, args) ; /* Make sure the mask size is the smallest odd number greater than six times the s.d. */ mask = MAX( (int)(MASK_SIGMAS * sigma + 0.5), 3 ) ; if (( mask % 2) == 0) mask++ ; /************************************************************* * This part is added by Selim on 4/12/2001 to make canedg * support both pgm and ppm images. If the input is a ppm image, * the rgb values are first converted to grayscale. *************************************************************/ /* open the input image file */ f = fopen( infile, "rb" ); if( f == NULL ) { fprintf( stderr, "Error opening %s\n", infile ); exit( -1 ); } /* read the magic number in the first line */ fscanf( f, "%s\n", cbuf ); if( strcmp( cbuf, PPM_RAW ) == 0 ) { /* we have a PPM image */ fclose( f ); ppmimage = read_ppm_file( infile ); XSIZE = ppmimage->ImageWidth; YSIZE = ppmimage->ImageHeight; pgmimage = ( PGMImage * ) malloc( sizeof( PGMImage ) ); strcpy( pgmimage->MagicValue, PGM_RAW ); pgmimage->ImageWidth = XSIZE; pgmimage->ImageHeight = YSIZE; pgmimage->MaxGray = 255; pgmimage->data = ucmatrix( YSIZE, XSIZE ); for( r = 0; r < YSIZE; r++ ) { for( c = 0; c < XSIZE; c++ ) { pgmimage->data[ r ][ c ] = ( unsigned char ) ( ( ppmimage->red[ r ][ c ] + ppmimage->green[ r ][ c ] + ppmimage->blue[ r ][ c ] ) / 3 ); } } free_ppm_data( ppmimage ); } else if( strcmp( cbuf, PGM_RAW ) != 0 ) { /* image has an unknown format */ fprintf( stderr, "Input image should be in either PGM or PPM format\n" ); fclose( f ); exit( -1 ); } else { /* we have a PGM image */ fclose( f ); pgmimage = read_pgm_file( infile ); XSIZE = pgmimage->ImageWidth; YSIZE = pgmimage->ImageHeight; } /*************************************************************/ /* Initialize any global variables */ edges = NULL ; canny() ; } /* Routine to do a majority of the leg-work in implementing the edge detection */ void canny() { double *gx, *gy ; /* Gradient array for X and Y direction */ double *mag ; /* Magnitude of gradient array */ /* Convolve image with a 2-D discrete gaussian using an array of dimensions mask x mask, and a s.d. of sigma */ /* Convolve returning with gx & gy as the X and Y gradient, and mag being the magnitude of that */ convolve(pgmimage->data, mask, sigma, &gx, &gy, &mag) ; local_extrema(mask, gx, gy, mag, low_threshold, high_threshold) ; join_edges(gx, gy) ; /* Create the output */ write_file(edges, outfile) ; /* Free up memory */ free(gx) ; free(gy) ; free(mag) ; }