Escolar Documentos
Profissional Documentos
Cultura Documentos
---------------------------
This text file contains the source code for the "Rothwell" edge detector. It
was written by Mike Heath (heath@csee.usf.edu) using some pieces of an
implementation of the Rothwell edge detector (implemented in C++) which
we received from Charlie Rothwell.
There are two 'C' source code files in this text file. They are named
"Topology.c", and "pgm_io.c". They were written and compiled under SunOS
4.1.3. Since then they have also been compiled under Solaris. To make an
executable program: (1) Separate this file into two files with
the previously specified names, and then (2) compile the code using
gcc -o Topology Topology.c pgm_io.c -lm
(Note: You can also use optimization such as -O3)
The resulting program, Topology, will process images in the PGM format.
Parameter selection is left up to the user. A broad range of parameters to
use as a starting point are: sigma 0.50-2.00, lowthresh 3.0-18.0 and,
alpha 0.80-0.95.
If you are using a Unix system, PGM file format conversion tools can be found
at ftp://wuarchive.wustl.edu/graphics/graphics/packages/pbmplus/.
Otherwise, it would be easy for anyone to rewrite the image I/O procedures
because they are listed in the separate file pgm_io.c.
If you want to check your compiled code, you can download grey-scale and edge
images from http://marathon.csee.usf.edu/edge/edge_detection.html. You can use
the parameters given in the edge filenames and check whether the edges that
are output from your program match the edge images posted at that address.
Mike Heath
(09/24/99)
<------------------------- begin Topology.c --------------------------->
/*******************************************************************************
* Program: Topology
* Purpose: This program contains an implementation of the Edge Detector
* described in the technical report: "Driving Vision by Topology" by Charlie
* Rothwell, Joe Mundy, Bill Hoffman and Van-Duc Nguyen. A shorter version of
* the report was published as a paper with the same name.
* This implementation of the program was also aided by the code Charlie Rothwell
* sent us. He sent us the edge detector modulules of a larger vision package
* that was coded in C++. This program just pulled together those modules into
* a complete edge detector program coded in 'C'. I tried to use as much of his
* code as possible to both simplify the coding task and to make sure that this
* implementation is consistent with theirs.
* Name: Mike Heath
* Date: 5/2/96
*
* To Compile: gcc -O2 -o Topology Topology.c pgm_io.c -lm
*
* NOTE: ALL OF THE 2-DIMENSIONAL ARRAYS IN THIS PROGRAM ARE STORED TRANSPOSED
* FROM THE USUAL WAY ARRAYS ARE STORED. I HAVE, WITH SOME PAIN, FOLLED THIS
* METHOD.
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define GAUSS_TAIL 0.015 /* As recommended in the technical report. */
#define FAR 65535
#define DUMMYTHETA 10000.0
typedef struct{
int x;
int y;
float thin;
}XYFLOAT;
int read_pgm_image(char *infilename, unsigned char **image, int *rows,
int *cols);
int write_pgm_image(char *outfilename, unsigned char *image, int rows,
int cols, char *comment, int maxval);
void Sub_pixel_interpolation(float **_grad, float **_dx, float **_dy, int cols,
int rows, int kwidth, float _low, float ALPHA, float ***_thresh, int ***_dist
,
float ***_theta);
void Thicken_threshold(float **_thresh, int **_dist, int x, int y, float _low,
int kwidth);
void Compute_gradient(float **dx, float **dy, int cols, int rows, int kwidth,
float ***grad);
void Compute_x_gradient(float **smoothedimage, int cols, int rows, int kwidth,
float ***dx);
void Compute_y_gradient(float **smoothedimage, int cols, int rows, int kwidth,
float ***dy);
void Smooth_image(float **image, int cols, int rows,
float ***smoothedimage, float sigma, int *kwidth, float gauss_tail);
void Set_kernel(float **kernel, float sigma, int width, int k_size);
int **Make_int_image(int x, int y);
void Set_int_image(int **image, int val, int cols, int rows);
void Copy_int_image(int **image1, int **image2, int cols, int rows);
void Free_int_image(int ***ptr);
float **Make_float_image(int x, int y);
void Set_float_image(float **image, float val, int cols, int rows);
void Copy_float_image(float **image1, float **image2, int cols, int rows);
void Free_float_image(float ***ptr);
void Set_thresholds(int **_dist, float **_grad, float **_thresh, float ***_thin,
int cols, int rows, float _low);
void Forward_chamfer(int m, int n, int **dist, float **param);
void Backward_chamfer(int m, int n, int **dist, float **param);
void Alt1_chamfer(int m, int n, int **dist, float **param);
void Alt2_chamfer(int m, int n, int **dist, float **param);
int Minimum4(int a, int b, int c, int d);
int Minimum5(int a, int b, int c, int d, int e);
int compare(XYFLOAT *xyf1, XYFLOAT *xyf2);
void Thin_edges(float **_thin, float **_thresh, int cols, int rows, int kwidth);
/*******************************************************************************
* Sets up the Gaussian convolution kernel.
*******************************************************************************/
void Set_kernel(float **kernel, float sigma, int width, int k_size)
{
int i,x;
float s2 = 2.0*sigma*sigma;
float det = sigma*sqrt(2.0*M_PI);
if(((*kernel) = (float *) calloc(k_size, sizeof(float))) == NULL){
fprintf(stderr, "Error allocating the smoothing filter array.\n");
exit(1);
}
for(i=0,x=(-width);i<k_size;i++,x++) (*kernel)[i] = exp(-x*x/s2)/det;
}
/*******************************************************************************
* Returns an m*n array of ints
*******************************************************************************/
int **Make_int_image(int x, int y)
{
int **image;
int i;
if((image = (int **) calloc(x, sizeof(int *))) == NULL){
fprintf(stderr, "Error allocating an array in Make_int_image().\n");
exit(1);
}
if((image[0] = (int *) calloc(x*y, sizeof(int))) == NULL){
fprintf(stderr, "Error allocating an array in Make_int_image().\n");
exit(1);
}
for(i=0;i<x;i++) image[i] = image[0] + (y * i);
return(image);
}
/*******************************************************************************
* Sets an int image to val.
*******************************************************************************/
void Set_int_image(int **image, int val, int cols, int rows)
{
int x, y;
int *ptr = image[0];
/* copy first col */
for(y=0;y<rows;y++) ptr[y] = val;
for(x=1;x<cols;x++){
ptr = image[x];
memcpy((char*)ptr, (char*)image[x-1], rows*sizeof(int));
}
}
/*******************************************************************************
* Copies int image1 to image2.
*******************************************************************************/
void Copy_int_image(int **image1, int **image2, int cols, int rows)
{
memcpy((char*)image2[0], (char*)image1[0], cols*rows*sizeof(int));
}
/*******************************************************************************
* Frees an m*n array of ints
*******************************************************************************/
void Free_int_image(int ***ptr)
{
free((*ptr)[0]);
free(*ptr);
*ptr = NULL;
}
/*******************************************************************************
* Returns an m*n array of floats
*******************************************************************************/
float **Make_float_image(int x, int y)
{
float **image;
int i;
if((image = (float **) calloc(x, sizeof(float *))) == NULL){
fprintf(stderr, "Error allocating an array in Make_float_image().\n");
exit(1);
}
if((image[0] = (float *) calloc(x*y, sizeof(float))) == NULL){
fprintf(stderr, "Error allocating an array in Make_float_image().\n");
exit(1);
}
for(i=0;i<x;i++) image[i] = image[0] + (y * i);
return(image);
}
/*******************************************************************************
* Sets a floating point image to val.
*******************************************************************************/
void Set_float_image(float **image, float val, int cols, int rows)
{
int x, y;
float *ptr = image[0];
/* copy first col */
for(y=0;y<rows;y++) ptr[y] = val;
for(x=1;x<cols;x++){
ptr = image[x];
memcpy((char*)ptr, (char*)image[x-1], rows*sizeof(float));
}
}
/*******************************************************************************
* Copies float image1 to image2.
*******************************************************************************/
void Copy_float_image(float **image1, float **image2, int cols, int rows)
{
memcpy((char*)image2[0], (char*)image1[0], cols*rows*sizeof(float));
}
/*******************************************************************************
* Frees an m*n array of floats
*******************************************************************************/
void Free_float_image(float ***ptr)
{
free((*ptr)[0]);
free(*ptr);
*ptr = NULL;
}
<--------------------------- end Topology.c --------------------------->
<--------------------------- begin pgm_io.c --------------------------->
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/******************************************************************************
* Function: read_pgm_image
* Purpose: This function reads in an image in PGM format. The image can be
* read in from either a file or from standard input. The image is only read
* from standard input when infilename = NULL. Because the PGM format includes
* the number of columns and the number of rows in the image, these are read
* from the file. Memory to store the image is allocated in this function.
* All comments in the header are discarded in the process of reading the
* image. Upon failure, this function returns 0, upon sucess it returns 1.
******************************************************************************/
int read_pgm_image(char *infilename, unsigned char **image, int *rows,
int *cols)
{
FILE *fp;
char buf[71];
/***************************************************************************
* Open the input image file for reading if a filename was given. If no
* filename was provided, set fp to read from standard input.
***************************************************************************/
if(infilename == NULL) fp = stdin;
else{
if((fp = fopen(infilename, "r")) == NULL){
fprintf(stderr, "Error reading the file %s in read_pgm_image().\n",
infilename);
return(0);
}
}
/***************************************************************************
* Verify that the image is in PGM format, read in the number of columns
* and rows in the image and scan past all of the header information.
***************************************************************************/
fgets(buf, 70, fp);
if(strncmp(buf,"P5",2) != 0){
fprintf(stderr, "The file %s is not in PGM format in ", infilename);
fprintf(stderr, "read_pgm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
do{ fgets(buf, 70, fp); }while(buf[0] == '#'); /* skip all comment lines */
sscanf(buf, "%d %d", cols, rows);
do{ fgets(buf, 70, fp); }while(buf[0] == '#'); /* skip all comment lines */
/***************************************************************************
* Allocate memory to store the image then read the image from the file.
***************************************************************************/
if(((*image) = (unsigned char *) malloc((*rows)*(*cols))) == NULL){
fprintf(stderr, "Memory allocation failure in read_pgm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
if((*rows) != fread((*image), (*cols), (*rows), fp)){
fprintf(stderr, "Error reading the image data in read_pgm_image().\n");
if(fp != stdin) fclose(fp);
free((*image));
return(0);
}
if(fp != stdin) fclose(fp);
return(1);
}
/******************************************************************************
* Function: write_pgm_image
* Purpose: This function writes an image in PGM format. The file is either
* written to the file specified by outfilename or to standard output if
* outfilename = NULL. A comment can be written to the header if coment != NULL.
******************************************************************************/
int write_pgm_image(char *outfilename, unsigned char *image, int rows,
int cols, char *comment, int maxval)
{
FILE *fp;
/***************************************************************************
* Open the output image file for writing if a filename was given. If no
* filename was provided, set fp to write to standard output.
***************************************************************************/
if(outfilename == NULL) fp = stdout;
else{
if((fp = fopen(outfilename, "w")) == NULL){
fprintf(stderr, "Error writing the file %s in write_pgm_image().\n",
outfilename);
return(0);
}
}
/***************************************************************************
* Write the header information to the PGM file.
***************************************************************************/
fprintf(fp, "P5\n%d %d\n", cols, rows);
if(comment != NULL)
if(strlen(comment) <= 70) fprintf(fp, "# %s\n", comment);
fprintf(fp, "%d\n", maxval);
/***************************************************************************
* Write the image data to the file.
***************************************************************************/
if(rows != fwrite(image, cols, rows, fp)){
fprintf(stderr, "Error writing the image data in write_pgm_image().\n");
if(fp != stdout) fclose(fp);
return(0);
}
if(fp != stdout) fclose(fp);
return(1);
}
/******************************************************************************
* Function: read_ppm_image
* Purpose: This function reads in an image in PPM format. The image can be
* read in from either a file or from standard input. The image is only read
* from standard input when infilename = NULL. Because the PPM format includes
* the number of columns and the number of rows in the image, these are read
* from the file. Memory to store the image is allocated in this function.
* All comments in the header are discarded in the process of reading the
* image. Upon failure, this function returns 0, upon sucess it returns 1.
******************************************************************************/
int read_ppm_image(char *infilename, unsigned char **image_red,
unsigned char **image_grn, unsigned char **image_blu, int *rows,
int *cols)
{
FILE *fp;
char buf[71];
int p, size;
/***************************************************************************
* Open the input image file for reading if a filename was given. If no
* filename was provided, set fp to read from standard input.
***************************************************************************/
if(infilename == NULL) fp = stdin;
else{
if((fp = fopen(infilename, "r")) == NULL){
fprintf(stderr, "Error reading the file %s in read_ppm_image().\n",
infilename);
return(0);
}
}
/***************************************************************************
* Verify that the image is in PPM format, read in the number of columns
* and rows in the image and scan past all of the header information.
***************************************************************************/
fgets(buf, 70, fp);
if(strncmp(buf,"P6",2) != 0){
fprintf(stderr, "The file %s is not in PPM format in ", infilename);
fprintf(stderr, "read_ppm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
do{ fgets(buf, 70, fp); }while(buf[0] == '#'); /* skip all comment lines */
sscanf(buf, "%d %d", cols, rows);
do{ fgets(buf, 70, fp); }while(buf[0] == '#'); /* skip all comment lines */
/***************************************************************************
* Allocate memory to store the image then read the image from the file.
***************************************************************************/
if(((*image_red) = (unsigned char *) malloc((*rows)*(*cols))) == NULL){
fprintf(stderr, "Memory allocation failure in read_ppm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
if(((*image_grn) = (unsigned char *) malloc((*rows)*(*cols))) == NULL){
fprintf(stderr, "Memory allocation failure in read_ppm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
if(((*image_blu) = (unsigned char *) malloc((*rows)*(*cols))) == NULL){
fprintf(stderr, "Memory allocation failure in read_ppm_image().\n");
if(fp != stdin) fclose(fp);
return(0);
}
size = (*rows)*(*cols);
for(p=0;p<size;p++){
(*image_red)[p] = (unsigned char)fgetc(fp);
(*image_grn)[p] = (unsigned char)fgetc(fp);
(*image_blu)[p] = (unsigned char)fgetc(fp);
}
if(fp != stdin) fclose(fp);
return(1);
}
/******************************************************************************
* Function: write_ppm_image
* Purpose: This function writes an image in PPM format. The file is either
* written to the file specified by outfilename or to standard output if
* outfilename = NULL. A comment can be written to the header if coment != NULL.
******************************************************************************/
int write_ppm_image(char *outfilename, unsigned char *image_red,
unsigned char *image_grn, unsigned char *image_blu, int rows,
int cols, char *comment, int maxval)
{
FILE *fp;
long size, p;
/***************************************************************************
* Open the output image file for writing if a filename was given. If no
* filename was provided, set fp to write to standard output.
***************************************************************************/
if(outfilename == NULL) fp = stdout;
else{
if((fp = fopen(outfilename, "w")) == NULL){
fprintf(stderr, "Error writing the file %s in write_pgm_image().\n",
outfilename);
return(0);
}
}
/***************************************************************************
* Write the header information to the PGM file.
***************************************************************************/
fprintf(fp, "P6\n%d %d\n", cols, rows);
if(comment != NULL)
if(strlen(comment) <= 70) fprintf(fp, "# %s\n", comment);
fprintf(fp, "%d\n", maxval);
/***************************************************************************
* Write the image data to the file.
***************************************************************************/
size = (long)rows * (long)cols;
for(p=0;p<size;p++){ /* Write the image in pixel interleaved format. */
fputc(image_red[p], fp);
fputc(image_grn[p], fp);
fputc(image_blu[p], fp);
}
if(fp != stdout) fclose(fp);
return(1);
}
<----------------------------- end pgm_io.c --------------------------->