在OpenCV中自适应确定canny算法的分割门限

   在OpenCV中用canny算子进行边缘检测速度很快,不过有点不爽的就是高低阈值需要输入。在matlab中,如果不指定阈值的话,由函数自适应确定,因此仿照matlab中的做法,对canny函数进行了修改,以便当用户没有指定高低阈值时,由函数自适应确定阈值。
我在OpenCv原码库中增加了一个函数,用于确定高低阈值。

view plain copy to clipboard print ?
  1. // 仿照matlab,自适应求高低两个门限   
  2. CV_IMPL void AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high)  
  3. {  
  4.  CvSize size;  
  5.  IplImage *imge=0;  
  6.  int i,j;  
  7.  CvHistogram *hist;  
  8.  int hist_size = 255;  
  9.     float range_0[]={0,256};  
  10.     float* ranges[] = { range_0 };  
  11.  double  PercentOfPixelsNotEdges = 0.7;  
  12.  size = cvGetSize(dx);  
  13.  imge = cvCreateImage(size, IPL_DEPTH_32F, 1);  
  14.  // 计算边缘的强度, 并存于图像中   
  15.  float maxv = 0;  
  16.  for(i = 0; i < size.height; i++ )  
  17.  {  
  18.   const short* _dx = (short*)(dx->data.ptr + dx->step*i);  
  19.         const short* _dy = (short*)(dy->data.ptr + dy->step*i);  
  20.   float* _image = (float *)(imge->imageData + imge->widthStep*i);  
  21.   for(j = 0; j < size.width; j++)  
  22.   {  
  23.    _image[j] = (float)(abs(_dx[j]) + abs(_dy[j]));  
  24.    maxv = maxv < _image[j] ? _image[j]: maxv;  
  25.   }  
  26.  }  
  27.    
  28.  // 计算直方图   
  29.  range_0[1] = maxv;  
  30.  hist_size = (int)(hist_size > maxv ? maxv:hist_size);  
  31.  hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);  
  32.  cvCalcHist( &imge, hist, 0, NULL );  
  33.  int total = (int)(size.height * size.width * PercentOfPixelsNotEdges);  
  34.  float sum=0;  
  35.  int icount = hist->mat.dim[0].size;  
  36.    
  37.  float *h = (float*)cvPtr1D( hist->bins, 0 );  
  38.  for(i = 0; i < icount; i++)  
  39.  {  
  40.   sum += h[i];  
  41.   if( sum > total )  
  42.    break;   
  43.  }  
  44. // 计算高低门限   
  45.  *high = (i+1) * maxv / hist_size ;  
  46.  *low = *high * 0.4;  
  47.  cvReleaseImage( &imge );  
  48.  cvReleaseHist(&hist);  
  49. }  
  50.    
  51. 在把cvCanny函数进行以下修改。  
  52. 在函数体中,当程序用两个sobel算子计算完水平和垂直两个方向的梯度强度过后加入以下代码  
  53. // 自适应确定阈值   
  54.  if(low_thresh == -1 && high_thresh == -1)  
  55.  {  
  56.   AdaptiveFindThreshold(dx, dy, &low_thresh, &high_thresh);  
  57.  }  
// 仿照matlab,自适应求高低两个门限 CV_IMPL void AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high) { CvSize size; IplImage *imge=0; int i,j; CvHistogram *hist; int hist_size = 255; float range_0[]={0,256}; float* ranges[] = { range_0 }; double PercentOfPixelsNotEdges = 0.7; size = cvGetSize(dx); imge = cvCreateImage(size, IPL_DEPTH_32F, 1); // 计算边缘的强度, 并存于图像中 float maxv = 0; for(i = 0; i < size.height; i++ ) { const short* _dx = (short*)(dx->data.ptr + dx->step*i); const short* _dy = (short*)(dy->data.ptr + dy->step*i); float* _image = (float *)(imge->imageData + imge->widthStep*i); for(j = 0; j < size.width; j++) { _image[j] = (float)(abs(_dx[j]) + abs(_dy[j])); maxv = maxv < _image[j] ? _image[j]: maxv; } } // 计算直方图 range_0[1] = maxv; hist_size = (int)(hist_size > maxv ? maxv:hist_size); hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1); cvCalcHist( &imge, hist, 0, NULL ); int total = (int)(size.height * size.width * PercentOfPixelsNotEdges); float sum=0; int icount = hist->mat.dim[0].size; float *h = (float*)cvPtr1D( hist->bins, 0 ); for(i = 0; i < icount; i++) { sum += h[i]; if( sum > total ) break; } // 计算高低门限 *high = (i+1) * maxv / hist_size ; *low = *high * 0.4; cvReleaseImage( &imge ); cvReleaseHist(&hist); } 在把cvCanny函数进行以下修改。 在函数体中,当程序用两个sobel算子计算完水平和垂直两个方向的梯度强度过后加入以下代码 // 自适应确定阈值 if(low_thresh == -1 && high_thresh == -1) { AdaptiveFindThreshold(dx, dy, &low_thresh, &high_thresh); }

 
这样,在调用cvCanny函数时,指定高低门限为-1,则cvCanny函数就自适应确定门限。
 
最后,别忘了重新编译cv库,对lib和dll库进行更新。
that's all!

http://blog.chinaunix.net/u/30231/showart_233944.html

你可能感兴趣的:(在OpenCV中自适应确定canny算法的分割门限)