63.Canny边缘检测算法

目录

        1 什么是Canny算子

        2 Canny边缘检测流程

        3 Canny具体步骤

        3.1 图像平滑

         3.2 计算图像中每个像素的梯度方向和幅值

         3.3 非极大值抑制

        3.4 双阈值求可能边

         3.5 消除孤立的弱边缘

        4 函数详解

        5 用C++编写代码进行实现

        1 什么是Canny算子

        Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。它在边缘检测过程中具有以下特点:

  • 低错误率:能够检测到大多数真实边缘,并且尽量减少错误检测。
  • 高定位精度:检测到的边缘位置相对精确。
  • 最小响应:每个边缘只有一个响应点。

        2 Canny边缘检测流程

        它包括如下五个步骤:

  1. 噪声抑制:通过使用高斯滤波器对图像进行平滑处理,降低噪声对边缘检测的影响。

  2. 计算梯度幅值和方向:利用Sobel算子计算图像在水平和垂直方向上的梯度,然后根据梯度幅值和方向计算每个像素点的梯度幅值和方向。

  3. 非极大值抑制:对图像中的梯度幅值进行非极大值抑制,即在每个像素点的梯度方向上比较幅值,并保留局部最大值,以细化边缘。

  4. 双阈值检测:根据设定的两个阈值(高阈值和低阈值),对梯度幅值进行阈值处理。高于高阈值的像素点被标记为强边缘,低于低阈值的像素点被排除,介于两个阈值之间的像素点被标记为弱边缘。

  5. 边缘连接:根据强边缘像素点的连通性,通过连接弱边缘像素点来形成完整的边缘。

        3 Canny具体步骤

        3.1 图像平滑

        图像平滑就是让图像之间的像素差距更小一些,能够更好地提取特征更加明显的边缘,所以图像平滑的目的就是去除部分噪声。 图像平滑操作,就是让临近的像素之间差距变小,图像模糊的作用不就是这样吗?所以图像平滑操作就是进行之前所讲的图像模糊(滤波)操作,而我们最常用的模糊操作,是高斯模糊。

         3.2 计算图像中每个像素的梯度方向和幅值

        Canny算法的基本思想是寻找一幅图像中灰度强度变化最强的位置。所谓变化最强,就是指梯度方向。 梯度求解:

        平滑后的图像中每个像素点的梯度可以由Sobel算子来获得。利用如下的核来分别求得沿水平(x)和垂直(y)方向的梯度G_X和G_Y。

 

         采用下列公式计算梯度和方向:

         3.3 非极大值抑制

        这一步的目的是将模糊的边界变得清晰(sharp)。通俗的讲,就是保留了每个像素点上梯度强度的极大值,而删掉其他的值。 具体操作分为如下几部:  

        a) 将其梯度方向近似为以下值中的一个: (0,45,90,135,180,225,270,315),即上下左右和45度方向。

        b) 比较该像素点,和其梯度方向正负方向的像素点的梯度强度。

        c) 如果该像素点梯度强度最大则保留,否则抑制(删除,即置为0)。 例:

        例子: 下图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留。

        3.4 双阈值求可能边

        经过非极大抑制后图像中仍然有很多噪声点。Canny算法中应用了一种叫双阈值的技术。即设定一个阈值上界和阈值下界(opencv中通常由人为指定的),图像中的像素点如果大于阈值上界则认为必然是边界(称为强边界,strong edge),小于阈值下界则认为必然不是边界,两者之间的则认为是候选项(称为弱边界,weak edge),需进行进一步处理。

         3.5 消除孤立的弱边缘

        在弱边缘的8领域范围寻找强边缘,如果8领域存在强边缘,就保留该弱边缘,否则就删除弱边缘,最终输出边缘检测结果。

        4 函数详解

        在OpenCV中,Canny求解边缘可以通过Canny()函数来实现。函数的定义如下:

void Canny( InputArray src, OutputArray edges, double threshold1,			           doubel threshold2, int apertureSize = 3, 					        bool L2gradient = false);
函数参数的含义:
src  --  输入图像
edges  --  输出边缘图像
threshold1  --  滞后过程的第一个阈值
threshold2  --  滞后过程的第二个阈值
apertureSize  --  Sobel算子核尺寸  
L2gradient  --  是否应使用更精确的L2范数来计算图像梯度幅值		    (true),或者是否应使用默认的L1范数(false)

        5 用C++编写代码进行实现

        下面是使用OpenCV中Canny()函数进行求取边缘的示例代码:

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char**argv)
{
Mat src = imread("E:/image/lena.png",0);
if (src.empty())
{
	printf("could not load image....");
	return -1;
}
Mat canny_low,canny_hight;
Canny(src, canny_low, 20, 40,3);
Canny(src, canny_hight, 100, 200, 3);
imshow("canny_low", canny_low);
imshow("canny_hight", canny_hight);
waitKey(0);
return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别叭叭儿—好好学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值