CV——自己实现Canny算子

本文详细介绍了Canny边缘检测算法的实现过程,包括图像预处理、梯度计算、非极大值抑制和双阈值检测等步骤。通过MATLAB代码展示了每个阶段的操作,但结果显示边缘不够平滑,可能在边缘连接步骤存在改进空间。

基本步骤

1、 图像与高斯平滑滤波器卷积
在这里插入图片描述

2、 利用一阶有限差分计算偏导数阵列P与Q
在这里插入图片描述
3、 计算梯度幅值与方向角
在这里插入图片描述
4、非极大值抑制(NMS)

  1. 模块梯度方向分为4个,垂直,水平,正对角线,副对角线

  2. 模块梯度方向离散化
    在这里插入图片描述
    -22.5~22.5为0
    22.5~67.5 为1
    67.5~112.5 为2
    112.5~157为3
    以此类推
    0代表水平,1代表副对角,2代表垂直,3代表正对角

  3. 梯度方向两边比较 p大于自身梯度方向两邻点的梯度,则保留,否则去除;

5、阈值化与边缘连接

  1. 设置两个阈值,一个高阈值,一个低阈值
  2. 根据高阈值的边缘点梯度方向,进行边缘连接,找不到点去低阈值找
  3. 从高阈值对应的点到低阈值图像的8领域找,找到就将其选为边缘点

代码

% 1、读入图像实现高斯滤波平滑
src=imread('lena.png');
gausFilter = fspecial('gaussian', [3,3], 1);
src= imfilter(src, gausFilter, 'replicate');
[Ax,Ay,~] = size(src);%获取图像尺寸
src = double(src);%类型转double


% 2、梯度大小方向计算  梯度方向离散化
m = zeros(Ax, Ay);%用来存储梯度大小
theta = zeros(Ax, Ay);%用来存储梯度方向
sector = zeros(Ax, Ay);%用来存储离散梯度值
for x = 1:(Ax-1)
    for y = 1:(Ay-1)
        gx =  src(x+1, y)-src(x+1, y)-src(x, y+1)+src(x+1, y+1);%水平差分
        gy =  src(x, y+1)-src(x, y)+src(x+1, y+1)-src(x+1, y);%垂直差分
        m(x,y) = (gx^2+gy^2)^0.5 ;%梯度大小
        theta(x,y) = atand(gx/gy);%梯度方向
        tem = theta(x,y);
        if (tem<67.5)&&(tem>22.5)%副对角
            sector(x,y) = 0;    
        elseif (tem<22.5)&&(tem>-22.5)%水平
            sector(x,y) = 3;    
        elseif (tem<-22.5)&&(tem>-67.5)%正对角
            sector(x,y) = 2;    
        else%垂直
            sector(x,y) = 1;    
        end  
    end    
end


% 3、非极大值抑制
canny = zeros(Ax, Ay);
for x = 2:(Ax-1)
    for y = 2:(Ay-1)        
        if 0 == sector(x,y) %副对角
            if (m(x,y)>m(x-1,y+1) )&&(m(x,y)>m(x+1,y-1))
                canny(x,y) = m(x,y);
            else
                canny(x,y) = 0;
            end
        elseif 1 == sector(x,y) %垂直
            if (m(x,y)>m(x-1,y))&&(m(x,y)>m(x+1,y))
                canny(x,y) = m(x,y);
            else
                canny(x,y) = 0;
            end
        elseif 2 == sector(x,y) %正对角
            if (m(x,y)>m(x-1,y-1))&&(m(x,y)>m(x+1,y+1))
                canny(x,y) = m(x,y);
            else
                canny(x,y) = 0;
            end
        elseif 3 == sector(x,y) %水平
            if (m(x,y)>m(x,y+1))&&( m(x,y)>m(x,y-1))
                canny(x,y) = m(x,y);
            else
                canny(x,y) = 0;
            end
        end        
    end
end


% 4、双阈值检测
high = zeros(Ax, Ay);
low = zeros(Ax,Ay);
highTh = 35;
lowTh = 20;
for x = 2:(Ax-1)
    for y = 2:(Ay-1)        
        if canny(x,y)>highTh
            high(x,y) = 1;
        end
        if canny(x,y)>lowTh
            low(x,y) = 1;
        end
    end
end


% 5、边缘连接——高阈值没有 低阈值8领域找查找
A=high;
for x = 2:(Ax-1)
    for y = 2:(Ay-1)
        tem =[low(x-1,y-1), low(x-1,y), low(x-1,y+1);
              low(x,y-1),   low(x,y),   low(x,y+1);
              low(x+1,y-1), low(x+1,y), low(x+1,y+1)];
        temMax = max(tem);
        if (high(x,y)==0) 
            if(temMax==1)
                A(x,y)=1;
            end
        end
    end
end


% 显示化结果
subplot(2,3,1),imshow(theta),title('梯度方向矩阵');
subplot(2,3,2),imshow(sector),title('梯度方向离散化矩阵');
subplot(2,3,3),imshow(canny),title("非极大值抑制后");
subplot(2,3,4),imshow(low),title("低阈值");
subplot(2,3,5),imshow(high),title("高阈值");
subplot(2,3,6),imshow(A),title("canny结果");

结果

在这里插入图片描述

  1. 实现的效果不是很好,边缘不够平滑
  2. 可能连接步骤理解的不够深刻,实现起来太粗暴
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值