00001 #ifndef CANNYEDGE_C 00002 #define CANNYEDGE_C 00003 00004 #include "BeoSub/CannyEdge.H" 00005 00006 #include "Util/Types.H" 00007 #include "Util/log.H" 00008 #include "Image/ColorOps.H" 00009 #include "Image/Image.H" 00010 #include "Image/MathOps.H" 00011 #include "Image/DrawOps.H" 00012 #include "Image/FilterOps.H" 00013 #include "Image/Transforms.H" 00014 #include "Raster/Raster.H" 00015 #include "rutz/shared_ptr.h" 00016 #include "BeoSub/hysteresis.H" 00017 #include "VFAT/segmentImageTrackMC.H" 00018 #include <cstdio> 00019 #include <cstdlib> 00020 #include <cstring> 00021 #include <iostream> //needed for segmentImageTrackMC! 00022 #include <math.h> 00023 #include <list> 00024 #include "Image/MatrixOps.H" 00025 00026 /******************************************************************************* 00027 * PROCEDURE: cannyEdge 00028 * PURPOSE: Simple wrapper for Mike's canny edge detection implementation 00029 * NAME: Rand Voorhies 00030 * DATE: 6/21/06 00031 *******************************************************************************/ 00032 int cannyEdge(Image<byte> &inputImage, float sigma, float tlow, float thigh, Image<byte> &outputImage) { 00033 unsigned char *edge; 00034 int ret = canny(inputImage.getArrayPtr(), inputImage.getHeight(), inputImage.getWidth(), sigma, tlow, thigh, &edge, NULL); 00035 outputImage = Image<unsigned char>(edge, inputImage.getWidth(), inputImage.getHeight()); 00036 free(edge); 00037 return ret; 00038 } 00039 00040 /******************************************************************************* 00041 * PROCEDURE: canny 00042 * PURPOSE: To perform canny edge detection. 00043 * NAME: Mike Heath 00044 * DATE: 2/15/96 00045 //Pradeep: returns the centroid of the "white" pixels 00046 *******************************************************************************/ 00047 int canny(unsigned char *image, int rows, int cols, float sigma, 00048 float tlow, float thigh, unsigned char **edge, char *fname) 00049 { 00050 FILE *fpdir=NULL; /* File to write the gradient image to. */ 00051 unsigned char *nms; /* Points that are local maximal magnitude. */ 00052 short int *smoothedim, /* The image after gaussian smoothing. */ 00053 *delta_x, /* The first devivative image, x-direction. */ 00054 *delta_y, /* The first derivative image, y-direction. */ 00055 *magnitude; /* The magnitude of the gadient image. */ 00056 float *dir_radians=NULL; /* Gradient direction image. */ 00057 00058 /**************************************************************************** 00059 * Perform gaussian smoothing on the image using the input standard 00060 * deviation. 00061 ****************************************************************************/ 00062 gaussian_smooth(image, rows, cols, sigma, &smoothedim); 00063 00064 00065 /**************************************************************************** 00066 * Compute the first derivative in the x and y directions. 00067 ****************************************************************************/ 00068 derrivative_x_y(smoothedim, rows, cols, &delta_x, &delta_y); 00069 00070 00071 00072 00073 /**************************************************************************** 00074 * This option to write out the direction of the edge gradient was added 00075 * to make the information available for computing an edge quality figure 00076 * of merit. 00077 ****************************************************************************/ 00078 if(fname != NULL){ 00079 /************************************************************************* 00080 * Compute the direction up the gradient, in radians that are 00081 * specified counteclockwise from the positive x-axis. 00082 *************************************************************************/ 00083 radian_direction(delta_x, delta_y, rows, cols, &dir_radians, -1, -1); 00084 00085 /************************************************************************* 00086 * Write the gradient direction image out to a file. 00087 *************************************************************************/ 00088 if((fpdir = fopen(fname, "wb")) == NULL){ 00089 fprintf(stderr, "Error opening the file %s for writing.\n", fname); 00090 exit(1); 00091 } 00092 fwrite(dir_radians, sizeof(float), rows*cols, fpdir); 00093 fclose(fpdir); 00094 free(dir_radians); 00095 } 00096 00097 /**************************************************************************** 00098 * Compute the magnitude of the gradient. 00099 ****************************************************************************/ 00100 magnitude_x_y(delta_x, delta_y, rows, cols, &magnitude); 00101 00102 /**************************************************************************** 00103 * Perform non-maximal suppression. 00104 ****************************************************************************/ 00105 if((nms = (unsigned char *) calloc(rows*cols,sizeof(unsigned char)))==NULL){ 00106 fprintf(stderr, "Error allocating the nms image.\n"); 00107 exit(1); 00108 } 00109 00110 non_max_supp(magnitude, delta_x, delta_y, rows, cols, nms); 00111 00112 /**************************************************************************** 00113 * Use hysteresis to mark the edge pixels. 00114 ****************************************************************************/ 00115 if((*edge=(unsigned char *)calloc(rows*cols,sizeof(unsigned char))) ==NULL){ 00116 fprintf(stderr, "Error allocating the edge image.\n"); 00117 exit(1); 00118 } 00119 //printf("\n%d %d %d %d %d %d\n", magnitude, nms, rows, cols, tlow, thigh); 00120 int centroid = apply_hysteresis(magnitude, nms, rows, cols, tlow, thigh, *edge); 00121 /**************************************************************************** 00122 * Free all of the memory that we allocated except for the edge image that 00123 * is still being used to store out result. 00124 ****************************************************************************/ 00125 free(smoothedim); 00126 free(delta_x); 00127 free(delta_y); 00128 free(magnitude); 00129 free(nms); 00130 return centroid; 00131 } 00132 00133 /******************************************************************************* 00134 * Procedure: radian_direction 00135 * Purpose: To compute a direction of the gradient image from component dx and 00136 * dy images. Because not all derriviatives are computed in the same way, this 00137 * code allows for dx or dy to have been calculated in different ways. 00138 * 00139 * FOR X: xdirtag = -1 for [-1 0 1] 00140 * xdirtag = 1 for [ 1 0 -1] 00141 * 00142 * FOR Y: ydirtag = -1 for [-1 0 1]' 00143 * ydirtag = 1 for [ 1 0 -1]' 00144 * 00145 * The resulting angle is in radians measured counterclockwise from the 00146 * xdirection. The angle points "up the gradient". 00147 *******************************************************************************/ 00148 void radian_direction(short int *delta_x, short int *delta_y, int rows, 00149 int cols, float **dir_radians, int xdirtag, int ydirtag) 00150 { 00151 int r, c, pos; 00152 float *dirim=NULL; 00153 double dx, dy; 00154 00155 /**************************************************************************** 00156 * Allocate an image to store the direction of the gradient. 00157 ****************************************************************************/ 00158 if((dirim = (float *) calloc(rows*cols, sizeof(float))) == NULL){ 00159 fprintf(stderr, "Error allocating the gradient direction image.\n"); 00160 exit(1); 00161 } 00162 *dir_radians = dirim; 00163 00164 for(r=0,pos=0;r<rows;r++){ 00165 for(c=0;c<cols;c++,pos++){ 00166 dx = (double)delta_x[pos]; 00167 dy = (double)delta_y[pos]; 00168 00169 if(xdirtag == 1) dx = -dx; 00170 if(ydirtag == -1) dy = -dy; 00171 00172 dirim[pos] = (float)angle_radians(dx, dy); 00173 } 00174 } 00175 } 00176 00177 /******************************************************************************* 00178 * FUNCTION: angle_radians 00179 * PURPOSE: This procedure computes the angle of a vector with components x and 00180 * y. It returns this angle in radians with the answer being in the range 00181 * 0 <= angle <2*PI. 00182 *******************************************************************************/ 00183 double angle_radians(double x, double y) 00184 { 00185 double xu, yu, ang; 00186 00187 xu = fabs(x); 00188 yu = fabs(y); 00189 00190 if((xu == 0) && (yu == 0)) return(0); 00191 00192 ang = atan(yu/xu); 00193 00194 if(x >= 0){ 00195 if(y >= 0) return(ang); 00196 else return(2*M_PI - ang); 00197 } 00198 else{ 00199 if(y >= 0) return(M_PI - ang); 00200 else return(M_PI + ang); 00201 } 00202 } 00203 00204 /******************************************************************************* 00205 * PROCEDURE: magnitude_x_y 00206 * PURPOSE: Compute the magnitude of the gradient. This is the square root of 00207 * the sum of the squared derivative values. 00208 * NAME: Mike Heath 00209 * DATE: 2/15/96 00210 *******************************************************************************/ 00211 void magnitude_x_y(short int *delta_x, short int *delta_y, int rows, int cols, 00212 short int **magnitude) 00213 { 00214 int r, c, pos, sq1, sq2; 00215 00216 /**************************************************************************** 00217 * Allocate an image to store the magnitude of the gradient. 00218 ****************************************************************************/ 00219 if((*magnitude = (short *) calloc(rows*cols, sizeof(short))) == NULL){ 00220 fprintf(stderr, "Error allocating the magnitude image.\n"); 00221 exit(1); 00222 } 00223 00224 for(r=0,pos=0;r<rows;r++){ 00225 for(c=0;c<cols;c++,pos++){ 00226 sq1 = (int)delta_x[pos] * (int)delta_x[pos]; 00227 sq2 = (int)delta_y[pos] * (int)delta_y[pos]; 00228 (*magnitude)[pos] = (short)(0.5 + sqrt((float)sq1 + (float)sq2)); 00229 } 00230 } 00231 00232 } 00233 00234 /******************************************************************************* 00235 * PROCEDURE: derrivative_x_y 00236 * PURPOSE: Compute the first derivative of the image in both the x any y 00237 * directions. The differential filters that are used are: 00238 * 00239 * -1 00240 * dx = -1 0 +1 and dy = 0 00241 * +1 00242 * 00243 * NAME: Mike Heath 00244 * DATE: 2/15/96 00245 *******************************************************************************/ 00246 void derrivative_x_y(short int *smoothedim, int rows, int cols, 00247 short int **delta_x, short int **delta_y) 00248 { 00249 int r, c, pos; 00250 00251 /**************************************************************************** 00252 * Allocate images to store the derivatives. 00253 ****************************************************************************/ 00254 if(((*delta_x) = (short *) calloc(rows*cols, sizeof(short))) == NULL){ 00255 fprintf(stderr, "Error allocating the delta_x image.\n"); 00256 exit(1); 00257 } 00258 if(((*delta_y) = (short *) calloc(rows*cols, sizeof(short))) == NULL){ 00259 fprintf(stderr, "Error allocating the delta_x image.\n"); 00260 exit(1); 00261 } 00262 00263 /**************************************************************************** 00264 * Compute the x-derivative. Adjust the derivative at the borders to avoid 00265 * losing pixels. 00266 ****************************************************************************/ 00267 for(r=0;r<rows;r++){ 00268 pos = r * cols; 00269 (*delta_x)[pos] = smoothedim[pos+1] - smoothedim[pos]; 00270 pos++; 00271 for(c=1;c<(cols-1);c++,pos++){ 00272 (*delta_x)[pos] = smoothedim[pos+1] - smoothedim[pos-1]; 00273 } 00274 (*delta_x)[pos] = smoothedim[pos] - smoothedim[pos-1]; 00275 } 00276 00277 /**************************************************************************** 00278 * Compute the y-derivative. Adjust the derivative at the borders to avoid 00279 * losing pixels. 00280 ****************************************************************************/ 00281 for(c=0;c<cols;c++){ 00282 pos = c; 00283 (*delta_y)[pos] = smoothedim[pos+cols] - smoothedim[pos]; 00284 pos += cols; 00285 for(r=1;r<(rows-1);r++,pos+=cols){ 00286 (*delta_y)[pos] = smoothedim[pos+cols] - smoothedim[pos-cols]; 00287 } 00288 (*delta_y)[pos] = smoothedim[pos] - smoothedim[pos-cols]; 00289 } 00290 } 00291 00292 /******************************************************************************* 00293 * PROCEDURE: gaussian_smooth 00294 * PURPOSE: Blur an image with a gaussian filter. 00295 * NAME: Mike Heath 00296 * DATE: 2/15/96 00297 *******************************************************************************/ 00298 void gaussian_smooth(unsigned char *image, int rows, int cols, float sigma, 00299 short int **smoothedim) 00300 { 00301 int r, c, rr, cc, /* Counter variables. */ 00302 windowsize, /* Dimension of the gaussian kernel. */ 00303 center; /* Half of the windowsize. */ 00304 float *tempim, /* Buffer for separable filter gaussian smoothing. */ 00305 *kernel, /* A one dimensional gaussian kernel. */ 00306 dot, /* Dot product summing variable. */ 00307 sum; /* Sum of the kernel weights variable. */ 00308 00309 /**************************************************************************** 00310 * Create a 1-dimensional gaussian smoothing kernel. 00311 ****************************************************************************/ 00312 make_gaussian_kernel(sigma, &kernel, &windowsize); 00313 center = windowsize / 2; 00314 00315 /**************************************************************************** 00316 * Allocate a temporary buffer image and the smoothed image. 00317 ****************************************************************************/ 00318 if((tempim = (float *) calloc(rows*cols, sizeof(float))) == NULL){ 00319 fprintf(stderr, "Error allocating the buffer image.\n"); 00320 exit(1); 00321 } 00322 if(((*smoothedim) = (short int *) calloc(rows*cols, 00323 sizeof(short int))) == NULL){ 00324 fprintf(stderr, "Error allocating the smoothed image.\n"); 00325 exit(1); 00326 } 00327 00328 /**************************************************************************** 00329 * Blur in the x - direction. 00330 ****************************************************************************/ 00331 for(r=0;r<rows;r++){ 00332 for(c=0;c<cols;c++){ 00333 dot = 0.0; 00334 sum = 0.0; 00335 for(cc=(-center);cc<=center;cc++){ 00336 if(((c+cc) >= 0) && ((c+cc) < cols)){ 00337 dot += (float)image[r*cols+(c+cc)] * kernel[center+cc]; 00338 sum += kernel[center+cc]; 00339 } 00340 } 00341 tempim[r*cols+c] = dot/sum; 00342 } 00343 } 00344 00345 /**************************************************************************** 00346 * Blur in the y - direction. 00347 ****************************************************************************/ 00348 for(c=0;c<cols;c++){ 00349 for(r=0;r<rows;r++){ 00350 sum = 0.0; 00351 dot = 0.0; 00352 for(rr=(-center);rr<=center;rr++){ 00353 if(((r+rr) >= 0) && ((r+rr) < rows)){ 00354 dot += tempim[(r+rr)*cols+c] * kernel[center+rr]; 00355 sum += kernel[center+rr]; 00356 } 00357 } 00358 (*smoothedim)[r*cols+c] = (short int)(dot*BOOSTBLURFACTOR/sum + 0.5); 00359 } 00360 } 00361 00362 free(tempim); 00363 free(kernel); 00364 } 00365 00366 /******************************************************************************* 00367 * PROCEDURE: make_gaussian_kernel 00368 * PURPOSE: Create a one dimensional gaussian kernel. 00369 * NAME: Mike Heath 00370 * DATE: 2/15/96 00371 *******************************************************************************/ 00372 void make_gaussian_kernel(float sigma, float **kernel, int *windowsize) 00373 { 00374 int i, center; 00375 float x, fx, sum=0.0; 00376 00377 *windowsize = int(1 + 2 * ceil(2.5 * sigma)); 00378 center = (*windowsize) / 2; 00379 00380 if((*kernel = (float *) calloc((*windowsize), sizeof(float))) == NULL){ 00381 fprintf(stderr, "Error callocing the gaussian kernel array.\n"); 00382 exit(1); 00383 } 00384 00385 for(i=0;i<(*windowsize);i++){ 00386 x = (float)(i - center); 00387 fx = pow(2.71828, -0.5*x*x/(sigma*sigma)) / (sigma * sqrt(6.2831853)); 00388 (*kernel)[i] = fx; 00389 sum += fx; 00390 } 00391 00392 for(i=0;i<(*windowsize);i++) (*kernel)[i] /= sum; 00393 00394 } 00395 00396 00397 #endif