Code:
/*
source code provided by Bill Green.
http://www.pages.drexel.edu/~weg22/can_tut.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define M_PI 3.14159
//the largest image this program can handle is 756*756
const int MAXIMA=512;
int COLS;
int ROWS;
void readInputImage(unsigned char *Original, FILE *source)
{
int pos=
fread(Original, sizeof(char), COLS*ROWS, source);
printf("\nTotally, %10d characters are read in.", pos);
return;
}
void writeImage(unsigned char *Image, int size, FILE *destination)
{
int pos=
fwrite(Image, sizeof(char), size, destination);
printf("\nTotally, %10d characters are written out.", pos);
return;
}
int parseInt(unsigned char arg[])
{
int i, integer=0;
for(i=0; i<strlen(arg); i++)
{
//Convert the argument into integer
//Report an error if any non-digit unsigned character is found
if(isdigit((int)arg[i]))
{
integer=integer*10+((int) arg[i]-48);
// printf("\niteration = %d",iteration);
}
else
{
fprintf(stderr,"\nArgument error. An integer needed.\n");
exit(-1); /* bail out. */
}
}
return integer;
}
/*reference:
Bill Green, Canny Edge Detection Tutorial
http://www.pages.drexel.edu/~weg22/can_tut.html
*/
void Gausian(unsigned char *Original, unsigned char *postGausian)
{
unsigned char mask[5][5];
int r, c, i, j;//,k;
int SUM;
/* 5x5 Gaussian mask. */
mask[0][0] = 2; mask[0][1] = 4; mask[0][2] = 5; mask[0][3] = 4; mask[0][4] = 2;
mask[1][0] = 4; mask[1][1] = 9; mask[1][2] = 12; mask[1][3] = 9; mask[1][4] = 4;
mask[2][0] = 5; mask[2][1] = 12; mask[2][2] = 15; mask[2][3] = 12; mask[2][4] = 5;
mask[3][0] = 4; mask[3][1] = 9; mask[3][2] = 12; mask[3][3] = 9; mask[3][4] = 4;
mask[4][0] = 2; mask[4][1] = 4; mask[4][2] = 5; mask[4][3] = 4; mask[4][4] = 2;
for( r=0; r<ROWS; r++)
{
for(c=0; c<COLS ; c++)
{
// printf("at ROW %d, COL %d.\n", r,c);
SUM=0;
if(r==0 || r==1 || r==ROWS-2 || r==ROWS-1)
SUM = Original[r*COLS+c];
else if(c==0 || c==1 || c==COLS-2 || c==COLS-1)
SUM = Original[r*COLS+c];
/* Convolution starts here */
else
{
for(i=-2; i<=2; i++) {
for(j=-2; j<=2; j++) {
SUM = SUM + (int)(Original[(r+i)*COLS+c+j] * mask[i+2][j+2]/115);
}
}
}
if(SUM>255) SUM=255;
if(SUM<0) SUM=0;
postGausian[r*COLS+c] = (unsigned char)(SUM);
}
}
}
/*reference:
Bill Green, Canny Edge Detection Tutorial
http://www.pages.drexel.edu/~weg22/can_tut.html
*/
void Canny(unsigned char *Gausian, unsigned char *postCanny)
{
int GX[3][3], GY[3][3];
int sumX, sumY, SUM;
int r,c, i, j;
double ORIENT;
int edgeDirection;
int highThreshold, lowThreshold;
int leftPixel, rightPixel;
int P1, P2, P3, P4, P5, P6, P7, P8;
/* 3x3 GX Sobel mask. Ref: www.cee.hw.ac.uk/hipr/html/sobel.html */
GX[0][0] = -1; GX[0][1] = 0; GX[0][2] = 1;
GX[1][0] = -2; GX[1][1] = 0; GX[1][2] = 2;
GX[2][0] = -1; GX[2][1] = 0; GX[2][2] = 1;
/* 3x3 GY Sobel mask. Ref: www.cee.hw.ac.uk/hipr/html/sobel.html */
GY[0][0] = 1; GY[0][1] = 2; GY[0][2] = 1;
GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0;
GY[2][0] = -1; GY[2][1] = -2; GY[2][2] = -1;
for(r=0; r<=(ROWS-1); r++)
{
for(c=0; c<=(COLS-1); c++)
{
sumX = 0;
sumY = 0;
/* image boundaries */
if(r==0 || r==ROWS-1)
SUM = 0;
else if(c==0 || c==COLS-1)
SUM = 0;
/* Convolution starts here */
else {
/***********************************
* X gradient approximation
***********************************/
for(i=-1; i<=1; i++) {
for(j=-1; j<=1; j++) {
sumX = sumX + (int)(Gausian[(r+i)*COLS+c+j] * GX[i+1][j+1]);
}
}
/**************************
* Y gradient approximation
**************************/
for(i=-1; i<=1; i++) {
for(j=-1; j<=1; j++) {
sumY = sumY + (int)(int)(Gausian[(r+i)*COLS+c+j]* GY[i+1][j+1]);
}
}
/***********************************************
* GRADIENT MAGNITUDE APPROXIMATION (Myler p.218)
***********************************************/
SUM = abs(sumX) + abs(sumY);
if(SUM>255) SUM=255;
if(SUM<0) SUM=0;
}
/***************************
* Magnitude orientation
***************************/
/* Cannot divide by zero*/
if(sumX == 0) {
if(sumY==0) ORIENT = 0.0;
else if (sumY<0) {
sumY = -sumY;
ORIENT = 90.0;
}
else ORIENT = 90.0;
}
/* Can't take invtan of angle in 2nd Quad */
else if(sumX<0 && sumY>0) {
sumX = -sumX;
ORIENT = 180 - ((atan((float)(sumY)/(float)(sumX))) * (180/M_PI));
}
/* Can't take invtan of angle in 4th Quad */
else if(sumX>0 && sumY<0) {
sumY = -sumY;
ORIENT = 180 - ((atan((float)(sumY)/(float)(sumX))) * (180/M_PI));
}
/* else angle is in 1st or 3rd Quad */
else ORIENT = (atan((float)(sumY)/(float)(sumX))) * (180/M_PI);
/***************************************************
* Find edgeDirection by assigning ORIENT a value of
* either 0, 45, 90 or 135 degrees, depending on which
* value ORIENT is closest to
****************************************************/
if(ORIENT < 22.5) edgeDirection = 0;
else if(ORIENT < 67.5) edgeDirection = 45;
else if(ORIENT < 112.5) edgeDirection = 90;
else if(ORIENT < 157.5) edgeDirection = 135;
else edgeDirection = 0;
/***************************************************
* Obtain values of 2 adjacent pixels in edge
* direction.
****************************************************/
if(edgeDirection == 0) {
leftPixel = (int)(Gausian[r*COLS + c - 1]);
rightPixel = (int)(Gausian[r*COLS + c + 1]);
}
else if(edgeDirection == 45) {
// leftPixel = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols - 1));
// rightPixel = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols + 1));
leftPixel = (int)(Gausian[(r+1)*COLS + c - 1]);
rightPixel = (int)(Gausian[(r-1)*COLS + c + 1]);
}
else if(edgeDirection == 90) {
// leftPixel = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols));
// rightPixel = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols));
leftPixel = (int)(Gausian[(r-1)*COLS + c ]);
rightPixel = (int)(Gausian[(r+1)*COLS + c ]);
}
else {
// leftPixel = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols - 1));
// rightPixel = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols + 1));
leftPixel = (int)(Gausian[(r-1)*COLS + c - 1 ]);
rightPixel = (int)(Gausian[(r+1)*COLS + c + 1 ]);
}
/*********************************************
* Compare current magnitude to both adjacent
* pixel values. And if it is less than either
* of the 2 adjacent values - suppress it and make
* a nonedge.
*********************************************/
if(SUM < leftPixel || SUM < rightPixel) SUM = 0;
else {
/**********************
* Hysteresis
**********************/
highThreshold = 120;
lowThreshold = 40;
if(SUM >= highThreshold)
SUM = Gausian[r*COLS + c ]; /* edge */
else if(SUM < lowThreshold)
SUM = 0; /* nonedge */
/* SUM is between T1 & T2 */
else {
/* Determine values of neighboring pixels */
/*
P1 = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols - 1));
P2 = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols));
P3 = (int)(*(gaussImage.data + r*originalImage.cols + c - originalImage.cols + 1));
P4 = (int)(*(gaussImage.data + r*originalImage.cols + c - 1));
P5 = (int)(*(gaussImage.data + r*originalImage.cols + c + 1));
P6 = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols - 1));
P7 = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols));
P8 = (int)(*(gaussImage.data + r*originalImage.cols + c + originalImage.cols + 1));
*/
P1 = (int)(Gausian[(r-1)*COLS + c - 1 ]);
P2 = (int)(Gausian[(r-1)*COLS + c ]);
P3 = (int)(Gausian[(r-1)*COLS + c + 1 ]);
P4 = (int)(Gausian[(r)*COLS + c - 1 ]);
P5 = (int)(Gausian[(r)*COLS + c + 1 ]);
P6 = (int)(Gausian[(r+1)*COLS + c - 1 ]);
P7 = (int)(Gausian[(r+1)*COLS + c ]);
P8 = (int)(Gausian[(r+1)*COLS + c + 1 ]);
/* Check to see if neighboring pixel values are edges */
if(P1 > highThreshold || P2 > highThreshold || P3 > highThreshold || P4 > highThreshold ||
P5 > highThreshold || P6 > highThreshold || P7 > highThreshold || P8 > highThreshold)
SUM = Gausian[r*COLS + c ]; /* make edge */
else SUM = 0; /* make nonedge */
}
}
postCanny[r*COLS+c] = (unsigned char)(SUM);
}
}
}
int main(int argc, unsigned char *argv[]) {
// Declare the FILE pointer and variables
FILE *inp_imge,*outp_imge, *test_imge;
unsigned char imge_name [21], output_name[21],test_name[21] ;
int iteration;
unsigned char Original[MAXIMA*MAXIMA];
unsigned char postGausian[MAXIMA*MAXIMA];
unsigned char postCanny[MAXIMA*MAXIMA];
//End of Declaration
//
if(argc < 5)
{
printf(
"This program need 5 parameters to run. Pease answer the questions \n");
printf("Input image filename ? \n");
scanf("%20s",imge_name);
printf("Output image filename ? \n");
scanf("%20s",output_name);
printf("Input image Width(pixels) ? \n");
scanf("%d",&COLS);
printf("Input image Length(pixels) ? \n");
scanf("%d",&ROWS);
}
else
{
strcpy(imge_name, argv[1]);
strcpy(output_name, argv[2]);
COLS = parseInt(argv[3]);
ROWS = parseInt(argv[4]);
}
// We now attempt to open the image file and read from it
if( (inp_imge = fopen ( imge_name , "rb" )) == NULL)
{
printf("File open failed.");
exit(1);
}
outp_imge= fopen ( output_name, "wb");
test_imge= fopen ("Gausian.raw", "wb");
readInputImage(Original, inp_imge);
fclose(inp_imge);
// printf("COLS= %d, ROWS= %d \n",COLS, ROWS);
// printf("at writting out test imge\n");
strcpy(postGausian, Original);
// printf("\nStop at strcpy");
Gausian(Original, postGausian);
// printf("Gausian procedure complete. Now write the results.\n");
writeImage(postGausian,ROWS*COLS,test_imge);
fclose(test_imge);
Canny(postGausian, postCanny);
writeImage(postCanny,ROWS*COLS,outp_imge);
fclose(outp_imge);
return 0;
}