00001 /*! @file BeoSub/hysteresis.C [put description here] */ 00002 00003 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/hysteresis.C $ 00004 // $Id: hysteresis.C 6182 2006-01-31 18:41:41Z rjpeters $ 00005 00006 /******************************************************************************* 00007 * FILE: hysteresis.c 00008 * This code was re-written by Mike Heath from original code obtained indirectly 00009 * from Michigan State University. heath@csee.usf.edu (Re-written in 1996). 00010 *******************************************************************************/ 00011 00012 #include <stdio.h> 00013 #include <stdlib.h> 00014 00015 #define VERBOSE 0 00016 00017 #define NOEDGE 0 00018 #define POSSIBLE_EDGE 128 00019 #define EDGE 255 00020 00021 /******************************************************************************* 00022 * PROCEDURE: follow_edges 00023 * PURPOSE: This procedure edges is a recursive routine that traces edgs along 00024 * all paths whose magnitude values remain above some specifyable lower 00025 * threshhold. 00026 * NAME: Mike Heath 00027 * DATE: 2/15/96 00028 *******************************************************************************/ 00029 int follow_edges(unsigned char *edgemapptr, short *edgemagptr, short lowval, 00030 int cols) 00031 { 00032 short *tempmagptr; 00033 unsigned char *tempmapptr; 00034 int i; 00035 int x[8] = {1,1,0,-1,-1,-1,0,1}, 00036 y[8] = {0,1,1,1,0,-1,-1,-1}; 00037 00038 //derecursify this! and then collect statistics to recognize rectangles etc... similar to graph traversal with MSTs 00039 for(i=0;i<8;i++){ 00040 tempmapptr = edgemapptr - y[i]*cols + x[i]; 00041 tempmagptr = edgemagptr - y[i]*cols + x[i]; 00042 00043 if((*tempmapptr == POSSIBLE_EDGE) && (*tempmagptr > lowval)){ 00044 *tempmapptr = (unsigned char) EDGE; 00045 follow_edges(tempmapptr,tempmagptr, lowval, cols); 00046 } 00047 } 00048 00049 return 0; 00050 } 00051 00052 /******************************************************************************* 00053 * PROCEDURE: apply_hysteresis 00054 * PURPOSE: This routine finds edges that are above some high threshhold or 00055 * are connected to a high pixel by a path of pixels greater than a low 00056 * threshold. 00057 * NAME: Mike Heath 00058 * DATE: 2/15/96 00059 *******************************************************************************/ 00060 int apply_hysteresis(short int *mag, unsigned char *nms, int rows, int cols, 00061 float tlow, float thigh, unsigned char *edge) 00062 { 00063 int r, c, pos, numedges, highcount, lowthreshold, highthreshold, 00064 hist[32768]; 00065 short int maximum_mag = 0 ; 00066 00067 /**************************************************************************** 00068 * Initialize the edge map to possible edges everywhere the non-maximal 00069 * suppression suggested there could be an edge except for the border. At 00070 * the border we say there can not be an edge because it makes the 00071 * follow_edges algorithm more efficient to not worry about tracking an 00072 * edge off the side of the image. 00073 ****************************************************************************/ 00074 for(r=0,pos=0;r<rows;r++){ 00075 for(c=0;c<cols;c++,pos++){ 00076 if(nms[pos] == POSSIBLE_EDGE) edge[pos] = POSSIBLE_EDGE; 00077 else edge[pos] = NOEDGE; 00078 } 00079 } 00080 00081 for(r=0,pos=0;r<rows;r++,pos+=cols){ 00082 edge[pos] = NOEDGE; 00083 edge[pos+cols-1] = NOEDGE; 00084 } 00085 pos = (rows-1) * cols; 00086 for(c=0;c<cols;c++,pos++){ 00087 edge[c] = NOEDGE; 00088 edge[pos] = NOEDGE; 00089 } 00090 00091 /**************************************************************************** 00092 * Compute the histogram of the magnitude image. Then use the histogram to 00093 * compute hysteresis thresholds. 00094 ****************************************************************************/ 00095 for(r=0;r<32768;r++) hist[r] = 0; 00096 for(r=0,pos=0;r<rows;r++){ 00097 for(c=0;c<cols;c++,pos++){ 00098 if(edge[pos] == POSSIBLE_EDGE) hist[mag[pos]]++; 00099 } 00100 } 00101 00102 /**************************************************************************** 00103 * Compute the number of pixels that passed the nonmaximal suppression. 00104 ****************************************************************************/ 00105 for(r=1,numedges=0;r<32768;r++){ 00106 if(hist[r] != 0) maximum_mag = r; 00107 numedges += hist[r]; 00108 } 00109 00110 highcount = (int)(numedges * thigh + 0.5); 00111 00112 /**************************************************************************** 00113 * Compute the high threshold value as the (100 * thigh) percentage point 00114 * in the magnitude of the gradient histogram of all the pixels that passes 00115 * non-maximal suppression. Then calculate the low threshold as a fraction 00116 * of the computed high threshold value. John Canny said in his paper 00117 * "A Computational Approach to Edge Detection" that "The ratio of the 00118 * high to low threshold in the implementation is in the range two or three 00119 * to one." That means that in terms of this implementation, we should 00120 * choose tlow ~= 0.5 or 0.33333. 00121 ****************************************************************************/ 00122 r = 1; 00123 numedges = hist[1]; 00124 while((r<(maximum_mag-1)) && (numedges < highcount)){ 00125 r++; 00126 numedges += hist[r]; 00127 } 00128 highthreshold = r; 00129 lowthreshold = (int)(highthreshold * tlow + 0.5); 00130 00131 if(VERBOSE){ 00132 printf("The input low and high fractions of %f and %f computed to\n", 00133 tlow, thigh); 00134 printf("magnitude of the gradient threshold values of: %d %d\n", 00135 lowthreshold, highthreshold); 00136 } 00137 00138 /**************************************************************************** 00139 * This loop looks for pixels above the highthreshold to locate edges and 00140 * then calls follow_edges to continue the edge. 00141 ****************************************************************************/ 00142 for(r=0,pos=0;r<rows;r++){ 00143 for(c=0;c<cols;c++,pos++){ 00144 if((edge[pos] == POSSIBLE_EDGE) && (mag[pos] >= highthreshold)){ 00145 edge[pos] = EDGE; 00146 follow_edges((edge+pos), (mag+pos), lowthreshold, cols); 00147 } 00148 } 00149 } 00150 00151 /**************************************************************************** 00152 * Set all the remaining possible edges to non-edges and calculate the centroid. 00153 ****************************************************************************/ 00154 int centroid = 0; 00155 int numEdgePts = 0; 00156 for(r=0,pos=0;r<rows;r++){ 00157 for(c=0;c<cols;c++,pos++) 00158 if(edge[pos] != EDGE) edge[pos] = NOEDGE; 00159 else { 00160 centroid += pos; 00161 numEdgePts++; 00162 } 00163 } 00164 if(numEdgePts != 0){ 00165 centroid = centroid/numEdgePts; 00166 } 00167 else{ 00168 centroid = 0; 00169 } 00170 return centroid; 00171 } 00172 00173 /******************************************************************************* 00174 * PROCEDURE: non_max_supp 00175 * PURPOSE: This routine applies non-maximal suppression to the magnitude of 00176 * the gradient image. 00177 * NAME: Mike Heath 00178 * DATE: 2/15/96 00179 *******************************************************************************/ 00180 void non_max_supp(short *mag, short *gradx, short *grady, int nrows, int ncols, 00181 unsigned char *result) 00182 { 00183 int rowcount, colcount,count; 00184 short *magrowptr,*magptr; 00185 short *gxrowptr,*gxptr; 00186 short *gyrowptr,*gyptr,z1,z2; 00187 short m00,gx=0,gy=0; 00188 float mag1,mag2,xperp=0.0f,yperp=0.0f; 00189 unsigned char *resultrowptr, *resultptr; 00190 00191 00192 /**************************************************************************** 00193 * Zero the edges of the result image. 00194 ****************************************************************************/ 00195 for(count=0,resultrowptr=result,resultptr=result+ncols*(nrows-1); 00196 count<ncols; resultptr++,resultrowptr++,count++){ 00197 *resultrowptr = *resultptr = (unsigned char) 0; 00198 } 00199 00200 for(count=0,resultptr=result,resultrowptr=result+ncols-1; 00201 count<nrows; count++,resultptr+=ncols,resultrowptr+=ncols){ 00202 *resultptr = *resultrowptr = (unsigned char) 0; 00203 } 00204 00205 /**************************************************************************** 00206 * Suppress non-maximum points. 00207 ****************************************************************************/ 00208 for(rowcount=1,magrowptr=mag+ncols+1,gxrowptr=gradx+ncols+1, 00209 gyrowptr=grady+ncols+1,resultrowptr=result+ncols+1; 00210 rowcount<nrows-2; 00211 rowcount++,magrowptr+=ncols,gyrowptr+=ncols,gxrowptr+=ncols, 00212 resultrowptr+=ncols){ 00213 for(colcount=1,magptr=magrowptr,gxptr=gxrowptr,gyptr=gyrowptr, 00214 resultptr=resultrowptr;colcount<ncols-2; 00215 colcount++,magptr++,gxptr++,gyptr++,resultptr++){ 00216 m00 = *magptr; 00217 if(m00 == 0){ 00218 *resultptr = (unsigned char) NOEDGE; 00219 } 00220 else{ 00221 xperp = -(gx = *gxptr)/((float)m00); 00222 yperp = (gy = *gyptr)/((float)m00); 00223 } 00224 00225 if(gx >= 0){ 00226 if(gy >= 0){ 00227 if (gx >= gy) 00228 { 00229 /* 111 */ 00230 /* Left point */ 00231 z1 = *(magptr - 1); 00232 z2 = *(magptr - ncols - 1); 00233 00234 mag1 = (m00 - z1)*xperp + (z2 - z1)*yperp; 00235 00236 /* Right point */ 00237 z1 = *(magptr + 1); 00238 z2 = *(magptr + ncols + 1); 00239 00240 mag2 = (m00 - z1)*xperp + (z2 - z1)*yperp; 00241 } 00242 else 00243 { 00244 /* 110 */ 00245 /* Left point */ 00246 z1 = *(magptr - ncols); 00247 z2 = *(magptr - ncols - 1); 00248 00249 mag1 = (z1 - z2)*xperp + (z1 - m00)*yperp; 00250 00251 /* Right point */ 00252 z1 = *(magptr + ncols); 00253 z2 = *(magptr + ncols + 1); 00254 00255 mag2 = (z1 - z2)*xperp + (z1 - m00)*yperp; 00256 } 00257 } 00258 else 00259 { 00260 if (gx >= -gy) 00261 { 00262 /* 101 */ 00263 /* Left point */ 00264 z1 = *(magptr - 1); 00265 z2 = *(magptr + ncols - 1); 00266 00267 mag1 = (m00 - z1)*xperp + (z1 - z2)*yperp; 00268 00269 /* Right point */ 00270 z1 = *(magptr + 1); 00271 z2 = *(magptr - ncols + 1); 00272 00273 mag2 = (m00 - z1)*xperp + (z1 - z2)*yperp; 00274 } 00275 else 00276 { 00277 /* 100 */ 00278 /* Left point */ 00279 z1 = *(magptr + ncols); 00280 z2 = *(magptr + ncols - 1); 00281 00282 mag1 = (z1 - z2)*xperp + (m00 - z1)*yperp; 00283 00284 /* Right point */ 00285 z1 = *(magptr - ncols); 00286 z2 = *(magptr - ncols + 1); 00287 00288 mag2 = (z1 - z2)*xperp + (m00 - z1)*yperp; 00289 } 00290 } 00291 } 00292 else 00293 { 00294 if ((gy = *gyptr) >= 0) 00295 { 00296 if (-gx >= gy) 00297 { 00298 /* 011 */ 00299 /* Left point */ 00300 z1 = *(magptr + 1); 00301 z2 = *(magptr - ncols + 1); 00302 00303 mag1 = (z1 - m00)*xperp + (z2 - z1)*yperp; 00304 00305 /* Right point */ 00306 z1 = *(magptr - 1); 00307 z2 = *(magptr + ncols - 1); 00308 00309 mag2 = (z1 - m00)*xperp + (z2 - z1)*yperp; 00310 } 00311 else 00312 { 00313 /* 010 */ 00314 /* Left point */ 00315 z1 = *(magptr - ncols); 00316 z2 = *(magptr - ncols + 1); 00317 00318 mag1 = (z2 - z1)*xperp + (z1 - m00)*yperp; 00319 00320 /* Right point */ 00321 z1 = *(magptr + ncols); 00322 z2 = *(magptr + ncols - 1); 00323 00324 mag2 = (z2 - z1)*xperp + (z1 - m00)*yperp; 00325 } 00326 } 00327 else 00328 { 00329 if (-gx > -gy) 00330 { 00331 /* 001 */ 00332 /* Left point */ 00333 z1 = *(magptr + 1); 00334 z2 = *(magptr + ncols + 1); 00335 00336 mag1 = (z1 - m00)*xperp + (z1 - z2)*yperp; 00337 00338 /* Right point */ 00339 z1 = *(magptr - 1); 00340 z2 = *(magptr - ncols - 1); 00341 00342 mag2 = (z1 - m00)*xperp + (z1 - z2)*yperp; 00343 } 00344 else 00345 { 00346 /* 000 */ 00347 /* Left point */ 00348 z1 = *(magptr + ncols); 00349 z2 = *(magptr + ncols + 1); 00350 00351 mag1 = (z2 - z1)*xperp + (m00 - z1)*yperp; 00352 00353 /* Right point */ 00354 z1 = *(magptr - ncols); 00355 z2 = *(magptr - ncols - 1); 00356 00357 mag2 = (z2 - z1)*xperp + (m00 - z1)*yperp; 00358 } 00359 } 00360 } 00361 00362 /* Now determine if the current point is a maximum point */ 00363 00364 if ((mag1 > 0.0) || (mag2 > 0.0)) 00365 { 00366 *resultptr = (unsigned char) NOEDGE; 00367 } 00368 else 00369 { 00370 if (mag2 == 0.0) 00371 *resultptr = (unsigned char) NOEDGE; 00372 else 00373 *resultptr = (unsigned char) POSSIBLE_EDGE; 00374 } 00375 } 00376 } 00377 }