【MATLAB图像处理3】 canny边缘检测 (附源码)

canny边缘检测,相对于sobel是较为复杂的一种检测算法,也是迄今为止最优秀的一种边缘检测算法,但是不可否认,它也带来了大量的运算。

 

canny分四步:

1.对灰度图进行高斯滤波  (很简单)

2.. 求出梯度的幅值图像和角度图像(一般用sobel求,简单)

3.对梯度幅值图形进行非最大值抑制,并进行双阈值处理。(难)

4.连接分析来检测并连接边缘。(很难)

 

 

1、高斯滤波。

使用二维高斯公式,产生高斯滤波模版。公式就不写,源码里会有。然后用模版和图像进行卷积。这一步很简单,就不多说了

 

2、求梯度的赋值和角度

用sobel算子,x方向为[-1,-2,-1;               y方向的算子为x方向的转置。然后分别用这两个算子和图像做卷积。然后用公式 A=sqrt(x.^2+y.^2)就是梯度幅值图了。

                                            0, 0, 0

                                            1, 2, 1 ]

 

然后是求角度,没一点的角度为arctan[y/x],求出梯度角度图;

 

3、利用求出的梯度角度图,把各个梯度分别划分到水平,垂直,45°,-45°,四个方向上。然后把赋值图按所划分的四个方向,分别同邻近的两个点比较,若为最大值则保留,若不是,则变为0;这样就得到非最大值抑制图,然后设置一个大阈值和一个小阈值,再用小阈值图减去大阈值图。得到阈值图。

 

4、在大阈值图中定位下一个非0像素P;在小阈值图中用8连通的方式,连接到P,如此递归,连接所有连线。

 

下面是源码

[plain] view plain copy
print ?
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  2. %%函数功能:canny边缘检测%%%%%%%%%%%%%%%%%%%%%  
  3. %%作者:张小胖疯了%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  4. %%时间:2013.9.28%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  5. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  6. clear all;close all; clc;  
  7. src=imread('D:\Documents\Desktop\lenna.JPG');  %读入图形  
  8. [m,n,q]=size(src);  
  9. src_gray=my_gray(src);                         %变为灰度图  
  10.   
  11. src_gaussion=my_gaussian(src_gray,3,9);         %高斯滤波  
  12.   
  13. [src_sobel,src_sobel_x,src_sobel_y]=my_sobel(src_gaussion);   %%%%%%%sobel梯度检测  
  14. figure(1);  
  15. imshow(src_sobel);  
  16.   
  17. %%%%%%%%%%%%%%把梯度划分为4个方向%%%%%%%%%%%%%%%%%%%%%%%  
  18.  new_angel_img=zeros(m,n);                                
  19. for i=1:m  
  20.     for j=1:n  
  21.         Mx=src_sobel_x(i,j);  
  22.         My=src_sobel_y(i,j);  
  23.           
  24.         if My~=0  
  25.             o=atan(Mx/My);      %边缘的法线弧度  
  26.         elseif My==0 && Mx>0  
  27.             o=pi/2;  
  28.         else  
  29.             o=-pi/2;              
  30.         end  
  31.           
  32.         if( ( o>=( -22.5/180*pi ) && o<( 22.5/180*pi ) ) || ( o>=( 157.5/180*pi ) && o<=pi ) || ( o<=( -157.5/180*pi ) && o>=-pi ) )  
  33.             d1=0;  
  34.         elseif (  ( o>= ( 22.5/180*pi ) && o<( 67.5/180*pi ) ) ||  (   o>=( -157.5/180*pi ) && o<(-112.5/180*pi )  )   )  
  35.             d1=-45;  
  36.         elseif ( ( o>=(67.5/180*pi) && o<(112.5/180*pi) ) || ( o>=(-112.5/180*pi) && o<-67.5/180*pi ) )     
  37.             d1=90;  
  38.         else        
  39.             d1=45;  
  40.          end  
  41.             new_angel_img(i,j)=d1;  
  42.     end  
  43. end  
  44.   
  45.   
  46. canny_dst=src_sobel;  
  47. %%%%%%%%%%%%%%%%%%非最大值抑制%%%%%%%%%%%%%%%%%%%%%%%5  
  48. for i=3:m-2  
  49.     for j=3:n-2  
  50.         if( new_angel_img(i,j)==0 )  
  51.             A=[canny_dst(i-1,j),canny_dst(i+1,j)];  
  52.             if( abs(canny_dst(i,j))< max( abs(A) ) )  
  53.                 canny_dst(i,j)=0;  
  54.             end  
  55.         elseif( new_angel_img(i,j)==-45 )  
  56.             A=[canny_dst(i-1,j-1),canny_dst(i+1,j+1)];  
  57.             if( abs(canny_dst(i,j))< max( abs(A) ))  
  58.                 canny_dst(i,j)=0;  
  59.             end  
  60.         elseif( new_angel_img(i,j)==90 )  
  61.             A=[canny_dst(i,j-1),canny_dst(i,j+1)];  
  62.             if( abs(canny_dst(i,j))< max( abs(A) ) )  
  63.                 canny_dst(i,j)=0;  
  64.             end              
  65.         elseif( new_angel_img(i,j)==45 )  
  66.             A=[canny_dst(i-1,j+1),canny_dst(i+1,j-1)];  
  67.             if( abs(canny_dst(i,j))< max( abs(A) ) )  
  68.                canny_dst(i,j)=0;  
  69.             end    
  70.         end  
  71.     end  
  72. end  
  73.   
  74. figure(2);  
  75. imshow(canny_dst);  
  76.   
  77. gh=zeros(m,n);  
  78. gl=zeros(m,n);  
  79. gl1=zeros(m,n);  
  80. for i=1:m  
  81.    for j=1:n  
  82.        if( canny_dst(i,j)>=100 )  
  83.             gh(i,j)=1;  
  84.         else  
  85.           gh(i,j)=0;  
  86.       end  
  87.         if( canny_dst(i,j)>=30)  
  88.            gl(i,j)=1;  
  89.         else  
  90.            gl(i,j)=0;  
  91.        end  
  92.   end  
  93. end  
  94. gl1=gl;  
  95. gl1=logical(gl1);  
  96. gh=logical(gh);  
  97. figure(3);  
  98. imshow(gl1);  
  99.   
  100.   
  101. figure(4);  
  102. imshow(gh);  
  103. %%%%%%%%%%%%%%%%%%%%%%%%递归连接%%%%%%%%%%%%%%%%%%%  
  104. up=100;     %上阈值  
  105. low=33;    %下阈值  
  106. set(0,'RecursionLimit',10000);  %设置最大递归深度  
  107. for i=1:m  
  108.     for j=1:n  
  109.       if canny_dst(i,j)>up &&canny_dst(i,j)~=255  %判断上阈值  
  110.             canny_dst(i,j)=255;  
  111.             canny_dst=connect(canny_dst,i,j,low);  
  112.       end  
  113.     end  
  114. end  
  115. figure(5);  
  116. imshow(canny_dst==255);  
  117.   
  118.  BW2 = edge(src_gaussion,'canny');  
  119. figure(6);  
  120. imshow(BW2);  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%函数功能:canny边缘检测%%%%%%%%%%%%%%%%%%%%%
%%作者:张小胖疯了%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%时间:2013.9.28%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all;close all; clc;
src=imread('D:\Documents\Desktop\lenna.JPG');  %读入图形
[m,n,q]=size(src);
src_gray=my_gray(src);                         %变为灰度图

src_gaussion=my_gaussian(src_gray,3,9);         %高斯滤波

[src_sobel,src_sobel_x,src_sobel_y]=my_sobel(src_gaussion);   %%%%%%%sobel梯度检测
figure(1);
imshow(src_sobel);

%%%%%%%%%%%%%%把梯度划分为4个方向%%%%%%%%%%%%%%%%%%%%%%%
 new_angel_img=zeros(m,n);                              
for i=1:m
    for j=1:n
        Mx=src_sobel_x(i,j);
        My=src_sobel_y(i,j);
        
        if My~=0
            o=atan(Mx/My);      %边缘的法线弧度
        elseif My==0 && Mx>0
            o=pi/2;
        else
            o=-pi/2;            
        end
        
        if( ( o>=( -22.5/180*pi ) && o<( 22.5/180*pi ) ) || ( o>=( 157.5/180*pi ) && o<=pi ) || ( o<=( -157.5/180*pi ) && o>=-pi ) )
            d1=0;
        elseif (  ( o>= ( 22.5/180*pi ) && o<( 67.5/180*pi ) ) ||  (   o>=( -157.5/180*pi ) && o<(-112.5/180*pi )  )   )
            d1=-45;
        elseif ( ( o>=(67.5/180*pi) && o<(112.5/180*pi) ) || ( o>=(-112.5/180*pi) && o<-67.5/180*pi ) )   
            d1=90;
        else      
            d1=45;
         end
            new_angel_img(i,j)=d1;
    end
end


canny_dst=src_sobel;
%%%%%%%%%%%%%%%%%%非最大值抑制%%%%%%%%%%%%%%%%%%%%%%%5
for i=3:m-2
    for j=3:n-2
        if( new_angel_img(i,j)==0 )
            A=[canny_dst(i-1,j),canny_dst(i+1,j)];
            if( abs(canny_dst(i,j))< max( abs(A) ) )
                canny_dst(i,j)=0;
            end
        elseif( new_angel_img(i,j)==-45 )
            A=[canny_dst(i-1,j-1),canny_dst(i+1,j+1)];
            if( abs(canny_dst(i,j))< max( abs(A) ))
                canny_dst(i,j)=0;
            end
        elseif( new_angel_img(i,j)==90 )
            A=[canny_dst(i,j-1),canny_dst(i,j+1)];
            if( abs(canny_dst(i,j))< max( abs(A) ) )
                canny_dst(i,j)=0;
            end            
        elseif( new_angel_img(i,j)==45 )
            A=[canny_dst(i-1,j+1),canny_dst(i+1,j-1)];
            if( abs(canny_dst(i,j))< max( abs(A) ) )
               canny_dst(i,j)=0;
            end  
        end
    end
end

figure(2);
imshow(canny_dst);

gh=zeros(m,n);
gl=zeros(m,n);
gl1=zeros(m,n);
for i=1:m
   for j=1:n
       if( canny_dst(i,j)>=100 )
            gh(i,j)=1;
        else
          gh(i,j)=0;
      end
        if( canny_dst(i,j)>=30)
           gl(i,j)=1;
        else
           gl(i,j)=0;
       end
  end
end
gl1=gl;
gl1=logical(gl1);
gh=logical(gh);
figure(3);
imshow(gl1);


figure(4);
imshow(gh);
%%%%%%%%%%%%%%%%%%%%%%%%递归连接%%%%%%%%%%%%%%%%%%%
up=100;     %上阈值
low=33;    %下阈值
set(0,'RecursionLimit',10000);  %设置最大递归深度
for i=1:m
    for j=1:n
      if canny_dst(i,j)>up &&canny_dst(i,j)~=255  %判断上阈值
            canny_dst(i,j)=255;
            canny_dst=connect(canny_dst,i,j,low);
      end
    end
end
figure(5);
imshow(canny_dst==255);

 BW2 = edge(src_gaussion,'canny');
figure(6);
imshow(BW2);


%%%%%%%%高斯滤波函数%%%%%%%%%%%%%%%%%%%%%%

 

[plain] view plain copy
print ?
  1. function d=my_gaussian(src,n,k)  
  2.   
  3. n1=(n+1)/2;                                         %%%%%%%%%%%%%计算高斯滤波模版中心  
  4. [m,l]=size(src);  
  5. b=zeros(n,n);                                       %%%%%%%%%%%%%空模版    
  6. I=zeros(m,l);  
  7. d=zeros(m,l);  
  8. img=zeros(m,l);  
  9. %%%%%%%%%%%%%%%%%计算高斯滤波模版的各个系数  
  10. for i=1:n  
  11.     for j=1:n  
  12.           b(i,j)=(exp(-((i-n1)^2 +(j-n1)^2)/(2*k)))/(2*pi*k);  
  13.     end  
  14. end  
  15.   
  16. b = b/sum(b(:));   %%%%%%%%%%%%%%%%%%%%%%对系数进行归一化 (这个地方必须归一化,不然整体灰度会底)      
  17. I=double(src);  
  18. img=conv2(I,b,'same');                %%%%%%%%%%%%图像与高斯滤波模版卷积,输出与输入图像大小相同的图像  
  19. d=uint8(img);                             %%%%%%%%%%转为无符号整型,用来显示  
  20.   
  21. end  
function d=my_gaussian(src,n,k)

n1=(n+1)/2;                                         %%%%%%%%%%%%%计算高斯滤波模版中心
[m,l]=size(src);
b=zeros(n,n);                                       %%%%%%%%%%%%%空模版  
I=zeros(m,l);
d=zeros(m,l);
img=zeros(m,l);
%%%%%%%%%%%%%%%%%计算高斯滤波模版的各个系数
for i=1:n
    for j=1:n
          b(i,j)=(exp(-((i-n1)^2 +(j-n1)^2)/(2*k)))/(2*pi*k);
    end
end

b = b/sum(b(:));   %%%%%%%%%%%%%%%%%%%%%%对系数进行归一化 (这个地方必须归一化,不然整体灰度会底)    
I=double(src);
img=conv2(I,b,'same');                %%%%%%%%%%%%图像与高斯滤波模版卷积,输出与输入图像大小相同的图像
d=uint8(img);                             %%%%%%%%%%转为无符号整型,用来显示

end


 

%%%%%%%%%%%%%%递归连接%%%%%%%%%%%%%%

[plain] view plain copy
print ?
  1. function nedge=connect(nedge,y,x,low)       %种子定位后的连通分析  
  2.     neighbour=[-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1];  %八连通搜寻  
  3.     [m n]=size(nedge);  
  4.     for k=1:8  
  5.         yy=y+neighbour(k,1);  
  6.         xx=x+neighbour(k,2);  
  7.         if yy>=1 &&yy<=m &&xx>=1 && xx<=n    
  8.             if nedge(yy,xx)>=low && nedge(yy,xx)~=255   %判断下阈值  
  9.                 nedge(yy,xx)=255;  
  10.                 nedge=connect(nedge,yy,xx,low);  
  11.             end  
  12.         end          
  13.     end   
  14.   
  15. end  
function nedge=connect(nedge,y,x,low)       %种子定位后的连通分析
    neighbour=[-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1];  %八连通搜寻
    [m n]=size(nedge);
    for k=1:8
        yy=y+neighbour(k,1);
        xx=x+neighbour(k,2);
        if yy>=1 &&yy<=m &&xx>=1 && xx<=n  
            if nedge(yy,xx)>=low && nedge(yy,xx)~=255   %判断下阈值
                nedge(yy,xx)=255;
                nedge=connect(nedge,yy,xx,low);
            end
        end        
    end 

end


原图:

【MATLAB图像处理3】 canny边缘检测 (附源码)_第1张图片

 

 梯度赋值图:

【MATLAB图像处理3】 canny边缘检测 (附源码)_第2张图片

 

非最大值抑制图:

 

【MATLAB图像处理3】 canny边缘检测 (附源码)_第3张图片

 

阈值化后:

【MATLAB图像处理3】 canny边缘检测 (附源码)_第4张图片

 

连接后:

【MATLAB图像处理3】 canny边缘检测 (附源码)_第5张图片

 

MATLAB自带函数效果:

 

【MATLAB图像处理3】 canny边缘检测 (附源码)_第6张图片

 

很明显自己写的函数跟MATLAB有很大差距,差距主要在非最大值抑制时的细化,和最后的连接。

还有努力啊。

你可能感兴趣的:(Matlab)