CannyEdge.C

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
Generated on Sun May 8 08:40:19 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3