canny边缘检测

背景简述

Canny提出一种新的边缘检测方法[1][2],它对受白噪声影响的阶跃型边缘是最优的。Canny检测子的最优性与三个标准有关:第一、检测标准:不失去重要的边缘,不应有虚假的边缘;第二、定位标准:实际边缘与检测到的边缘位置之间的偏差最小;第三、单位应标准:将多个响应降低为单个边缘响应。这一点被第一个标准部分地覆盖了。因为当有两个响应对应于单个边缘时,其中之一应该被是虚假的。这第三个标准解决受噪声影响的边缘问题,起亦制非平滑边缘检测算子的作用。

基本理论

首先,Canny算子是针对1D信号和前两个最优标准表达的。用微积分方法可以得到完整的解。如果我们加上第三个标准,需要通达数值优化的办法得到最优解。其最优滤波器可有有效地为标准差的高斯平滑滤波器的一阶微分,其误差小于20%。然后,将边缘检测算子映射到2D情况。阶跃边缘由位置、方向和可能的幅度(强度)来确定。

由于噪声引起的对单个边缘的虚假响应通常造成的所谓“纹状”问题。一般而言,该问题在边缘检测中是非常普遍。边缘检测算子的输出通常要做阈值化处理,以确定哪些边缘是突出的。纹状是指边缘轮廓断开的情形,是由算子输出超出或阈值的波动引起。我可以通过来Thresholding with hysteresis消除。在一般情况下,我选择具有最小尺度的算子,因为它定位最准确。

Canny提出了特征综合方法。首先标记出所有由最小尺度算子得到的突出边缘。而整个Canny边缘检测器算法分成如下四步:

  1. 噪声去除。因为这个检测器用到了微分算子,所以对于局部的不连续是敏感的,某区域的噪声点很容易造成边缘的模糊。在我做的这个应用里,因为要检测的是文本的边缘,而文本的背景是比较规则的变形后的正方形方格,所以如果用wiki里建议的高斯滤波器,会造成整个图像都变成一种颜色,即全黑或者全白。因此如果换一种观点,把这些变形后的方格也看成图的一部分,因为字体的纹理和方格的纹理不同,所以可以看作是两种区域组合成的图像。由此我改用一般的镜子,增强图像边缘。

  2. 计算图像的边缘梯度。这个是常规运算,用了Sobel算子,分别计算图像的x和y方向的梯度值,最后计算出图像各点的梯度值以及梯度角。计算得到梯度角需要进行近似,近似四个值{-45(或135), 0, 45,90}。

  3. 非最大梯度值点抑制第2步计算后得到两组值,第一组是各点的梯度值,第二组是各点梯度角的近似值。这一个非最大梯度值点抑制是比较不好理解的一步。遍历各点,做如下操作。(1)如果该点(x, y)的梯度角是0,如果其梯度值比北(x - 1, y)和南(x + 1, y)的梯度值大,则认为(x,y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(2)如果该点(x, y)的梯度角是90,如果其梯度值比西(x, y - 1)和东(x, y +1)的梯度值大,则认为(x, y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(3)如果该点(x,y)的梯度角是135(或-45),如果其梯度值比东北(x - 1, y + 1)和西南(x + 1, y -1)的梯度值大,则认为(x, y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(4)如果该点(x,y)的梯度角是45,如果其梯度值比西北(x - 1, y - 1)和东南(x + 1, y + 1)的梯度值大,则认为(x,y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255)。

  4. 产生边缘.在第3步里直接用边缘值和背景值对两种图像区域进行了划分。这么做对于图像不同区域像素值区别较大的场合比较方便,计算也快,但是对于图像不同区域像素。

参考代码

Opencv版Canny函数
[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. void canny (float s, IMAGE im, IMAGE mag, IMAGE ori){  
  2.     int width;  
  3.     float **smx,**smy;  
  4.     float **dx,**dy;  
  5.     int i,j,n;  
  6.     float gau[MAX_MASK_SIZE], dgau[MAX_MASK_SIZE], z;  
  7.   
  8.         // Create a Gaussian and a derivative of Gaussian filter mask  
  9.     for(i=0; i<MAX_MASK_SIZE; i++){  
  10.       gau[i] = meanGauss ((float)i, s);  
  11.       if (gau[i] < 0.005){  
  12.         width = i;  
  13.         break;  
  14.       }  
  15.       dgau[i] = dGauss ((float)i, s);  
  16.     }  
  17.   
  18.     n = width+width + 1;  
  19.     WIDTH = width/2;  
  20.     printf ("Smoothing with a Gaussian (width = %d) ...\n", n);  
  21.   
  22.     smx = f2d (im->info->nr, im->info->nc);  
  23.     smy = f2d (im->info->nr, im->info->nc);  
  24.   
  25.         //Convolution of source image with a Gaussian in X and Y directions   
  26.     seperable_convolution (im, gau, width, smx, smy);  
  27.   
  28.         //Now convolve smoothed data with a derivative  
  29.     printf ("Convolution with the derivative of a Gaussian...\n");  
  30.     dx = f2d (im->info->nr, im->info->nc);  
  31.     dxy_seperable_convolution (smx, im->info->nr, im->info->nc,dgau, width, dx, 1);  
  32.     free(smx[0]); free(smx);  
  33.   
  34.     dy = f2d (im->info->nr, im->info->nc);  
  35.     dxy_seperable_convolution (smy, im->info->nr, im->info->nc,  
  36.          dgau, width, dy, 0);  
  37.     free(smy[0]); free(smy);  
  38.   
  39.         // Create an image of the norm of dx,dy  
  40.     for (i=0; i<im->info->nr; i++)  
  41.       for (j=0; j<im->info->nc; j++)  
  42.       {  
  43.           z = norm (dx[i][j], dy[i][j]);  
  44.           mag->data[i][j] = (unsigned char)(z*MAG_SCALE);  
  45.       }  
  46.   
  47.         //Non-maximum suppression - edge pixels should be a local max  
  48.     nonmax_suppress (dx, dy, (int)im->info->nr, (int)im->info->nc, mag, ori);  
  49.   
  50.     free(dx[0]); free(dx);  
  51.     free(dy[0]); free(dy);  
  52. }  

摘自   http://blog.csdn.net/songzitea/article/details/8827781
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值