canny 算子实现图像边缘检测(详细过程附源码Word文档下载推荐.docx
《canny 算子实现图像边缘检测(详细过程附源码Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《canny 算子实现图像边缘检测(详细过程附源码Word文档下载推荐.docx(12页珍藏版)》请在冰豆网上搜索。
i=imread('
light.jpg'
);
k=rgb2y(i);
%获取h分量,即亮度分量
根据边缘的定义,边缘检测的目的是标识数字图像中亮度变化明显的点。
(参考维基百科);
又根据公式Brightness=0.3*R+0.6*G+0.1*B;
计算出亮度分量y;
functionk=rgb2y(z)
%i必须为rgb三维矩阵
[m,n,p]=size(z);
k=zeros(m,n);
z=double(z);
fori=1:
m
forj=1:
n
k(i,j)=0.3*z(i,j,1)+0.6*z(i,j,2)+0.1*z(i,j,3);
end
end
functionj=gaosi(i);
%i必须为二维double矩阵
j=i;
[h,w]=size(i);
form=2;
h-1
forn=2:
w-1
j(m,n)=(i(m,n-1)+2*i(m,n)+i(m,n+1))/4;
%横向高斯滤波
利用上面自定义的gaosi函数对图像进行二维3x3滤波,
k1=gaosi(k);
%横向滤波
k1=k1'
;
%对图像进行转置,为下一步纵向滤波作准备(纵向滤波==转置后横向滤波)
k1=gaosi(k1);
%还原
利用上式,易知p,q分别为计算出的横向、纵向的微分近似,由此再计算出梯度的大小和方向。
%计算梯度的大小和方向
[h,w]=size(k);
form=2:
zz1=k1(m,n-1)+k1(m+1,n-1);
zz2=k1(m,n)+k1(m+1,n);
zz3=k1(m,n-1)+k1(m,n);
zz4=k1(m+1,n-1)+k1(m+1,n);
kp(m,n)=0.5*(zz2-zz1);
kq(m,n)=0.5*(zz3-zz4);
kfu(m,n)=sqrt((kp(m,n)^2)+(kq(m,n)^2));
%梯度大小
kjiao(m,n)=atan(kq(m,n)/(kp(m,n)+0.001));
%梯度方向,0.001防止分母为0
1.先将梯度方向归类为四个主要方向,左右、上下、左斜、右斜。
%非极大值抑制
%首先将梯度方向划分为4个方向0,45,90,135(以及他们的反向延长线)
ifkjiao(m,n)>
=3/8*pi
kjiao(m,n)=2;
elseifkjiao(m,n)>
=1/8*pi
kjiao(m,n)=1;
elseifkjiao(m,n)>
=-1/8*pi
kjiao(m,n)=0;
=-3/8*pi
kjiao(m,n)=3;
else
kjiao(m,n)=2;
end
end
根据划分后的4个方向,判断该点是否是8邻域的局部最大值(梯度方向),比如,梯度方向为左右方向的点,判断其是否比左右两点的值来的大,如果不是,使该点的值为0.
%按照各个方向分别判断
k2=k1;
ifkjiao(m,n)==0
ifk1(m,n)>
k1(m,n-1)&
&
k1(m,n)>
k1(m,n+1);
elsek2(m,n)=0;
end
end
ifkjiao(m,n)==1
k1(m+1,n-1)&
k1(m-1,n+1);
ifkjiao(m,n)==2
k1(m-1,n)&
k1(m+1,n);
ifkjiao(m,n)==3
k1(m-1,n-1)&
k1(m+1,n+1);
用两个阈值t1和t2(t2>
t1,一般取t2=2*t1),我们把梯度值小于t1的像素的灰度设为0,得到图像1,然后我们把梯度值小于t2的像素的灰度设为0,得到图像2。
由于图像2的阈值较高,噪音较少(但同时也损失了有用的边缘信息,而图像1的阈值较低,保留了较多信息,因此我们可以以图像2为基础,以图像1为补充来连接图像的边缘。
%两次阈值分割
k3=k2;
%以t1为阈值分割后的矩阵
k4=k2;
%以t2为阈值分割后的矩阵
t1=50;
t2=2*t1;
ifkfu(m,n)<
t1
k3(m,n)=0;
t2
k4(m,n)=0;
a.扫描图像2,当我们遇到一个非零值的像素p时(跟踪以p为开始点的轮廓线直到该轮廓线的终点q;
b.在图像1中,考察与图像2中p点位置对应的点p'
的8邻域,如果在p'
点的8邻域中有非零像素q'
存在,将其包括到图像2中,作为点r,从r开始(重复第a步,直到我们在图像1和图像2中都无法继续为止;
c.我们已经结束了对包含p的轮廓线的连接,将这条轮廓标记为已访问过,回到第a步,寻找下一条轮廓线,重复第(a)(b)(c)步直到图像2中再也找不到新轮廓线为止.
findline.m:
function[ff,flag1]=findline(k3,k4,flag,m,n)
flag1=flag;
m1=m+1;
n1=n+1;
while(m~=m1||n~=n1)%若m和n都不发生变化,表明line已到终点
flagg=0;
fori=1:
3
if(flagg==1)break;
end
forj=1:
ifk3(m-2+i,n-2+j)~=0
k4(m-2+i,n-2+j)=255;
m1=m-2+i;
n1=n-2+j;
%新的[m,n]点
flag1(m,n)=1;
%标记已检测过
flagg=1;
break;
end
m=m1;
n=n1;
ff=k4;
主函数里写上:
figure;
subplot(221);
imshow(i);
title('
原图像'
subplot(222);
imshow(k3,[]);
阈值为50的分割图像'
subplot(223);
imshow(k4,[]);
阈值为100的分割图像'
flag=zeros(h,w);
%标记该点是否以检测过,1表示检测过
ifk4(m,n)~=0&
flag(m,n)==0
[k4,flag]=findline(k3,k4,flag,m,n);
end
subplot(224);
修正后的分割图像'
至此,程序完成。
效果如下:
至于程序中阈值的求取,大家自己定义就好了。
希望前辈们能给点学习图像处理的经验,谢谢了。