加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

边缘检测算法Canny的Matlab实现(部分转帖)

(2011-05-19 17:09:18)
标签:

杂谈

Canny 边缘检测器,对受白噪声影响的阶跃型边缘是最优的.

 

1.Canny边缘检测基本原理

(1)图象边缘检测必须满足两个条件:一能有效地抑制噪声;二必须尽量精确确定边缘的位置。
(2)根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。
(3)类似与Marr(LoG)边缘检测方法,也属于先平滑后求导数的方法。
 
2.Canny边缘检测算法:
step1:用高斯滤波器平滑图象;
step2:用一阶偏导的有限差分来计算梯度的幅值和方向;
step3:对梯度幅值进行非极大值抑制;
step4:用双阈值算法检测和连接边缘。
 
step1:高斯平滑函数
step3:非极大值抑制
仅仅得到全局的梯度并不足以确定边缘,因此为确定边缘,必须保留局部梯度最大的点,而抑制非极大值。(non-maxima suppression,NMS)
解决方法:利用梯度的方向。
图2非极大值抑制
四个扇区的标号为0到3,对应3*3邻域的四种可能组合。
    在每一点上,邻域的中心象素M与沿着梯度线的两个象素相比。如果M的梯度值不比沿梯度线的两个相邻象素梯度值大,则令M=0。
 
step4:阈值化
减少假边缘段数量的典型方法是对N[i,j]使用一个阈值。将低于阈值的所有值赋零值。但问题是如何选取阈值?
解决方法:双阈值算法。双阈值算法对非极大值抑制图象作用两个阈值τ1和τ2,且2τ1≈τ2,从而可以得到两个阈值边缘图象N1[i,j]和 N2[i,j]。由于N2[i,j]使用高阈值得到,因而含有很少的假边缘,但有间断(不闭合)。双阈值法要在N2[i,j]中把边缘连接成轮廓,当到达轮廓的端点时,该算法就在N1[i,j]的8邻点位置寻找可以连接到轮廓上的边缘,这样,算法不断地在N1[i,j]中收集边缘,直到将N2[i,j]连接起来为止。


1. 用高斯滤波器平滑图像.
2. 用一阶偏导有限差分计算梯度幅值和方向.
3. 对梯度幅值进行非极大值抑制 .
4. 用双阈值算法检测和连接边缘.

 

function can()

 

    I = imread('un.bmp');
   
    gray = rgb2gray(I);
   
    a = im2single(gray);
   
    [m,n] = size(a);
    % 用于输出的边界位图
    e = false(m,n);
   
    % Magic numbers
    GaussianDieOff = .0001; 
    PercentOfPixelsNotEdges = .7; % 用于阀值选择
    ThresholdRatio = .4;          % 低阀值相对高阀值的比值
    sigma = 1; %设置sigma
    thresh = [];
   
    % 设计滤波器 - a gaussian和它的导数
    pw = 1:30; % possible widths
    ssq = sigma^2;
    width = find(exp(-(pw.*pw)/(2*ssq))>GaussianDieOff,1,'last');%find函数很给力...
    if isempty(width)
    width = 1;  % the user entered a really small sigma
    end
   
    t = (-width:width);
    gau = exp(-(t.*t)/(2*ssq))/(2*pi*ssq);     % 高斯一维滤波
   
    % Find the directional derivative of 2D Gaussian (along X-axis)
    % Since the result is symmetric along X, we can get the derivative along
    % Y-axis simply by transposing the result for X direction.
    [x,y]=meshgrid(-width:width,-width:width);
    dgau2D=-x.*exp(-(x.*x+y.*y)/(2*ssq))/(pi*ssq);%二维高斯方向导数
   
    % Convolve the filters with the image in each direction
    % The canny edge detector first requires convolution with
    % 2D gaussian, and then with the derivitave of a gaussian.
    % Since gaussian filter is separable, for smoothing, we can use
    % two 1D convolutions in order to achieve the effect of convolving
    % with 2D Gaussian.  We convolve along rows and then columns.
   
    %用一阶高斯滤波器平滑图像
    aSmooth=imfilter(a,gau,'conv','replicate');   % run the filter accross rows
    aSmooth=imfilter(aSmooth,gau','conv','replicate'); % and then accross columns
   
    %应用方向导数
    ax = imfilter(aSmooth, dgau2D, 'conv','replicate');
    ay = imfilter(aSmooth, dgau2D', 'conv','replicate');
   
    %计算梯度幅值
    mag = sqrt((ax.*ax) + (ay.*ay));
    magmax = max(mag(:));
    if magmax>0
     mag = mag / magmax;   % normalize
    end
   
    % 选择高低两个阀值,用于双阀值算法检测和连接边缘.
    if isempty(thresh)
     counts=imhist(mag, 64);
     highThresh = find(cumsum(counts) > PercentOfPixelsNotEdges*m*n,...
                   1,'first') / 64;
     lowThresh = ThresholdRatio*highThresh;
     thresh = [lowThresh highThresh];
    elseif length(thresh)==1
     highThresh = thresh;
     if thresh>=1
      eid = sprintf('Images:%s:thresholdMustBeLessThanOne', mfilename);
      msg = 'The threshold must be less than 1.';
      error(eid,'%s',msg);
    end
     lowThresh = ThresholdRatio*thresh;
     thresh = [lowThresh highThresh];
     elseif length(thresh)==2
     lowThresh = thresh(1);
     highThresh = thresh(2);
     if (lowThresh >= highThresh) || (highThresh >= 1)
      eid = sprintf('Images:%s:thresholdOutOfRange', mfilename);
      msg = 'Thresh must be [low high], where low < high < 1.';
      error(eid,'%s',msg);
     end
    end
   
    % The next step is to do the non-maximum supression. 
    % We will accrue indices which specify ON pixels in strong edgemap
    % The array e will become the weak edge map.
    idxStrong = []; 
    for dir = 1:4
      idxLocMax = cannyFindLocalMaxima(dir,ax,ay,mag);
      idxWeak = idxLocMax(mag(idxLocMax) > lowThresh);
      e(idxWeak)=1;
      idxStrong = [idxStrong; idxWeak(mag(idxWeak) > highThresh)];
    end
   
    if ~isempty(idxStrong) % result is all zeros if idxStrong is empty
      rstrong = rem(idxStrong-1, m)+1;
      cstrong = floor((idxStrong-1)/m)+1;
      e = bwselect(e, cstrong, rstrong, 8);
      e = bwmorph(e, 'thin', 1);  % Thin double (or triple) pixel wide contours
    end
    
    imshow(e);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
  Local Function : cannyFindLocalMaxima
%
function idxLocMax = cannyFindLocalMaxima(direction,ix,iy,mag)

 [m,n] = size(mag);
 
 % Find the indices of all points whose gradient (specified by the
 % vector (ix,iy)) is going in the direction we're looking at. 
   idx = find((iy<=0 & ix>-iy)  | (iy>=0 & ix<-iy));
 
   % Exclude the exterior pixels
 if ~isempty(idx)
   v = mod(idx,m);
   extIdx = find(v==1 | v==0 | idx<=m | (idx>(n-1)*m));
   idx(extIdx) = [];
 end
 
 ixv = ix(idx); 
 iyv = iy(idx);  
 gradmag = mag(idx);
 
 % Do the linear interpolations for the interior pixels
  d = abs(iyv./ixv);
  gradmag1 = mag(idx+m).*(1-d) + mag(idx+m-1).*d;
  gradmag2 = mag(idx-m).*(1-d) + mag(idx-m+1).*d;
 
 idxLocMax = idx(gradmag>=gradmag1 & gradmag>=gradmag2);

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有