0


关于通过matlab实现Canny边缘处理的一些笔记

最近看了一些神经网络处理图像的视频,受到卷积核的启发,突然对图像处理感兴趣,于是就单从边缘检测算法入手,学习了比较高级的Canny边缘处理,也通过matlab实现了Canny边缘处理。


相比较于通过soble算子sx和sy处理,提取水平和竖直边缘信息,平方和相加开根号得到的边缘提取图像,canny边缘算法具有一下优势:

1.解决了边缘过宽问题

左图为普通边缘处理,右图为Canny算法处理

可以看到明显的单层边界线

2.去除了部分噪点


下面记录一下主要流程和相关函数

1.导入并处理rgb图片

如A = imread('Figure.jpg') , 从目录下的文件中找到图片,导入。

此时A为三维rgb数据,判断维度函数为 **ndims(A)**,返回值为维度。

导入图片矩阵格式一般为int8,需要再转化为double形式,否则矩阵计算中会出现问题,比如sqrt(imgx.^2+imgy.^2)计算中报错,显示输入数据格式不对。

使用**im2double(A)**函数转化为double形式。

随后将rgb图片转化为灰度值图片:

使用 B = rgb2gray(A);

部分代码如下

  1. %判断是否为rgb图片,是则转化为灰度图
  2. if ndims(preimg)==3
  3. preimg=im2double(preimg);
  4. grayimg=rgb2gray(preimg); %转化为灰度图
  5. else
  6. grayimg=preimg;
  7. end

2.高斯滤波

对图像进行平滑模糊处理,更容易检测出边缘

利用高斯分布的矩阵,卷积原图

fspecial函数生成高斯分布矩阵H

  1. %高斯滤波
  2. H=fspecial('gaussian',[2*k+1,2*k+1],c);
  3. imgG=imfilter(grayimg, H, 'replicate');

k为高斯矩阵外围层数,c为方差

k根据图像实际情况调整,实际上k越大代表一个像素与周围像素关联性越大,所以边缘较清晰的k值小。

c越大,图像越模糊

k值均为7,上图方差为1,下图为5

可以看出,高斯处理不足导致边界检测模糊,很难形成一条线

3.计算梯度和梯度方向

使用soble算子sx,sy计算在x方向和y方向梯度(imgx,imgy)以及梯度方向G_d

梯度方向通过atan函数求得

  1. %梯度计算
  2. sx=[1 0 -1;2 0 -2;1 0 -1];
  3. imgx=imfilter(imgG,sx,'replicate');
  4. sy=[1 2 1; 0 0 0;-1 -2 -1];
  5. imgy=imfilter(imgG,sy,'replicate');
  6. %梯度值
  7. G=sqrt(imgx.^2+imgy.^2);
  8. %梯度方向
  9. G_d=atand(imgy./imgx);
  10. %给空值赋0
  11. for y=1:size(G,1)
  12. for x=1:size(G,2)
  13. if ismissing(G_d(y,x))
  14. G_d(y,x)=90;
  15. end
  16. end
  17. end

这里会有个小问题,就是imgx值为0时,得到梯度方向为NaN,此时通过ismissing函数判断数据是否为NaN,手动设置为90度。

之后判断梯度方向,从上下,到/,到左右,到\依次定义为1,2,3,4

注意:这里的梯度角度和开始设置的x,y方向有关

  1. %判断梯度方向
  2. %梯度方向分别为上下,左右,/,\,
  3. G_s=zeros(size(grayimg,1),size(grayimg,2));
  4. for y=1:size(G_d,1)
  5. for x=1:size(G_d,2)
  6. if (G_d(y,x)> 67.5 & G_d(y,x)<= 90 )| (G_d(y,x)< -67.5 & G_d(y,x)>= -90)
  7. G_s(y,x)=1;
  8. end
  9. if (G_d(y,x)> 22.5 & G_d(y,x)<= 67.5 )
  10. G_s(y,x)=2;
  11. end
  12. if (G_d(y,x)>= -22.5 & G_d(y,x)<= 22.5 )
  13. G_s(y,x)=3;
  14. end
  15. if (G_d(y,x)>= -66.5 & G_d(y,x)< -22.5 )
  16. G_s(y,x)=4;
  17. end
  18. end
  19. end

从而得到方向矩阵G_s

4.非极大值抑制NMS

这一步操作是为了减小边缘粗细

判断梯度方向上的值的大小,如果比梯度方向值小,则令其值为0

也就是挑选出边缘上梯度最大的一条线,从而减小边缘粗细

  1. %非极大值抑制
  2. %添加0
  3. G0=zeros(size(G,1)+2,size(G,2)+2);
  4. G0(2:(size(G,1)+1),2:(size(G,2)+1))=G;
  5. G_d=G;
  6. for y=1:size(G,1)
  7. for x=1:size(G,2)
  8. if G_s(y,x)==1
  9. if G0(y+1,x+1) < max(G0(y+1+1,x+1),G0(y+1-1,x+1))
  10. G_d(y,x)=0;
  11. end
  12. end
  13. if G_s(y,x)==2
  14. if G0(y+1,x+1) < max(G0(y+1-1,x+1+1),G0(y+1+1,x+1-1))
  15. G_d(y,x)=0;
  16. end
  17. end
  18. if G_s(y,x)==3
  19. if G0(y+1,x+1) < max(G0(y+1,x+1-1),G0(y+1,x+1+1))
  20. G_d(y,x)=0;
  21. end
  22. end
  23. if G_s(y,x)==4
  24. if G0(y+1,x+1) < max(G0(y+1+1,x+1+1),G0(y+1-1,x+1-1))
  25. G_d(y,x)=0;
  26. end
  27. end
  28. end
  29. end

这里添加0边是为了在之后比较时数组不超界

5.双阈值处理

为了减小噪声,过滤部分无关信息,采用双阈值处理,大于阈值时保持不变,小于阈值时置0,在阈值中间时,判断周围8格内是否有大于阈值的像素,如果有则不变,否则置0

这里高阈值一般在0.3到0.5,较暗图像取0.1

低阈值一般小于0.1,这个随具体情况而定

  1. %双阈值处理
  2. G_t=G_d;
  3. %加个边
  4. G0=zeros(size(G,1)+2,size(G,2)+2);
  5. G0(2:(size(G,1)+1),2:(size(G,2)+1))=G_d;
  6. for y=1:size(G_d,1)
  7. for x=1:size(G_d,2)
  8. if G_d(y,x)>=TH
  9. elseif G0(y,x)<= TL
  10. G_t(y,x)=0;
  11. elseif G0(y,x)> TL & G0(y,x)< TH
  12. if (G0(y+1,x+1)>=TH | G0(y+1,x)>=TH | G0(y+1,x-1)>=TH | G0(y,x+1)>=TH ...
  13. | G0(y,x-1)>=TH | G0(y-1,x+1)>=TH | G0(y-1,x)>=TH | G0(y-1,x-1)>=TH)
  14. else
  15. G_t(y,x)=0;
  16. end
  17. end
  18. end
  19. end

这里同样加了0边,防止超界

最后封装函数,变量设为preimg(图片矩阵),TH、TL为阈值,k,c为高斯处理时矩阵层数和方差。

函数默认TH、TL、k、c分别为0.5、0.1、1、1, 一般较大的图片k值设置为4-15,c值1-10

可以通过结果修改参数,以达到最好的效果!


本文转载自: https://blog.csdn.net/npu_noj/article/details/127564082
版权归原作者 故意装菜 所有, 如有侵权,请联系我们删除。

“关于通过matlab实现Canny边缘处理的一些笔记”的评论:

还没有评论