用于图像边缘检测的canny运算符(详细过程和源代码

电脑杂谈  发布时间:2020-03-27 13:19:44  来源:网络整理

matlab canny算子边缘检测函数代码_canny算子边缘检测 matlab_matlab canny算子三维图像边缘检测

Canny边缘检测方法是高斯函数的一阶导数,可以在噪声抑制和边缘检测之间实现良好的平衡.

环境: Windows XP + Matlab 2010b

时间: 2011年12月25日

canny算法检测边缘的主要步骤:

1)通过3x3高斯滤波器进行滤波以消除噪声;

2)对于每个像素,计算水平和垂直方向的微分近似值,以获得像素的梯度大小和方向;

3)梯度的“非最大抑制”(非局部最大值设置为0);

4)对梯度使用两次阈值;

5)连接边缘;

以下详细说明了这些步骤:

0)加载图像:

clear;
clc;
i=imread('light.jpg');
k=rgb2y(i);%获取h分量,即亮度分量

canny算子边缘检测 matlab_matlab canny算子边缘检测函数代码_matlab canny算子三维图像边缘检测

根据边缘的定义,边缘检测的目的是识别数字图像中亮度明显变化的点. (请参阅Wikipedia%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B);

亮度分量y的计算公式为: 亮度= 0.3 * R + 0.6 * G + 0.1 * B;

复制代码

{8: f: d: e: 5: e: 9: a: 8: 8: 0: f: 0: 5: 2: 2: 3: 6: d: 7: 7: 8: 5: a: d: 2: 8: 8: 8: 1: 1: 1: d)

复制代码

1)通过3x3高斯滤波器进行滤波以消除噪声;

复制代码

function j=gaosi(i);
%i必须为二维double矩阵
j=i;
[h,w]=size(i);
for m=2;h-1
for n=2:w-1
j(m,n)=(i(m,n-1)+2*i(m,n)+i(m,n+1))/4;%横向高斯滤波
end
end

复制代码

使用上面的自定义高斯函数对图像执行2D 3x3过滤,

k1=gaosi(k);%横向滤波
k1=k1';%对图像进行转置,为下一步纵向滤波作准备(纵向滤波==转置后横向滤波)
k1=gaosi(k1);
k1=k1';%还原

2)对于每个像素,计算水平和垂直方向的微分近似值,以获得像素的梯度大小和方向;

matlab canny算子边缘检测函数代码_canny算子边缘检测 matlab_matlab canny算子三维图像边缘检测

使用上面的公式,很容易知道p和q分别是计算的水平和垂直微分近似值,然后计算了梯度的大小和方向.

复制代码

%计算梯度的大小和方向
[h,w]=size(k);
for m=2:h-1
for n=2:w-1
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
end
end

复制代码

3)梯度的“非最大抑制”(非局部最大值设置为0);

1. 首先将梯度方向分为四个主要方向,左,右,上,下,左斜,右斜.

复制代码

%非极大值抑制
%首先将梯度方向划分为4个方向0,45,90,135(以及他们的反向延长线)
for m=2:h-1
for n=2:w-1
if kjiao(m,n)>=3/8*pi
kjiao(m,n)=2;
else if kjiao(m,n)>=1/8*pi
kjiao(m,n)=1;
else if kjiao(m,n)>=-1/8*pi
kjiao(m,n)=0;
else if kjiao(m,n)>=-3/8*pi
kjiao(m,n)=3;
else
kjiao(m,n)=2;
end
end
end
end
end
end

复制代码

根据分割后的4个方向,确定该点是否为8个邻域的局部最大值(梯度方向). 例如,如果渐变方向的点是左右,则确定它是否大于左右点的值. ,否则,将此点的值设为0.

复制代码

matlab canny算子三维图像边缘检测_matlab canny算子边缘检测函数代码_canny算子边缘检测 matlab

%按照各个方向分别判断
k2=k1;
for m=2:h-1
for n=2:w-1
if kjiao(m,n)==0
if k1(m,n)>k1(m,n-1)&&k1(m,n)>k1(m,n+1);
else k2(m,n)=0;
end
end
if kjiao(m,n)==1
if k1(m,n)>k1(m+1,n-1)&&k1(m,n)>k1(m-1,n+1);
else k2(m,n)=0;
end
end
if kjiao(m,n)==2
if k1(m,n)>k1(m-1,n)&&k1(m,n)>k1(m+1,n);
else k2(m,n)=0;
end
end
if kjiao(m,n)==3
if k1(m,n)>k1(m-1,n-1)&&k1(m,n)>k1(m+1,n+1);
else k2(m,n)=0;
end
end
end
end

复制代码

4)对梯度使用两次阈值;

使用两个阈值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;
for m=2:h-1
for n=2:w-1
if kfu(m,n)<t1
k3(m,n)=0;
end
if kfu(m,n)<t2
k4(m,n)=0;
end
end
end

复制代码

5)连接边缘;

a. 扫描图像2,当我们遇到非零值的像素p时(跟踪轮廓线从p开始直到轮廓线的结束点q;

b. 在图像1中,考虑点p的8个邻域与图像2中点p的位置相对应. 如果在点p的8个邻域中存在非零像素q',则将其包含在图像2中作为点r,从r开始(重复步骤a,直到在图像1和图像2中都无法继续;

c. 我们结束了包含p的轮廓线的连接,将该轮廓标记为已访问canny算子边缘检测 matlabcanny算子边缘检测 matlab,返回到步骤a,找到下一条轮廓线,然后重复(a)(b)(c))步骤,直到找不到新的轮廓线在图2中.

findline.m:

matlab canny算子三维图像边缘检测_canny算子边缘检测 matlab_matlab canny算子边缘检测函数代码

复制代码

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;
for i=1:3
if(flagg==1) break;
end
for j=1:3
if k3(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
end
end
m=m1;n=n1;
end
ff=k4;

复制代码

写入主要功能:

复制代码

figure;
subplot(221);imshow(i);title('原图像');
subplot(222);imshow(k3,[]);title('阈值为50的分割图像');
subplot(223);imshow(k4,[]);title('阈值为100的分割图像');
flag=zeros(h,w);%标记该点是否以检测过,1表示检测过
for m=2:h-1
for n=2:w-1
if k4(m,n)~=0&&flag(m,n)==0
[k4,flag]=findline(k3,k4,flag,m,n);
end
end
end
subplot(224);imshow(k4,[]);title('修正后的分割图像');

复制代码

这完成了整个过程.

效果如下:

关于程序中的阈值,您可以自己定义.

我希望我的前任可以给我一些图像处理方面的经验. 谢谢.


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-154198-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 韩璐璐
        韩璐璐

        1800~1900两千往上的风险比较大

      热点图片
      拼命载入中...