图像边缘检测概论

来源:互联网 发布:ipython在linux安装 编辑:程序博客网 时间:2024/04/30 17:27

一、概论

下面将学习opencv中边缘检测的各种算子和滤波器:

包括canny算子,sobel算子,scharr算子。

什么叫做边缘检测呢?

边缘检测的目标是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反应了属性的重要事件和变化,包括:

(1) 、深度上的不连续

(2) 、表面方向的不连续

(3) 、物质属性变化

(4) 、场景照明变化

边缘检测剔除了大量认为与图像特征不相关的数据,只保留了图像中较为重要的属性。边缘检测和视角有关,视角不一样,边缘检测的结果就不一样。

检测方法:

许多边缘检测的方法,可以分为两类:基于搜索和基于零交叉

    对于基于搜索的边缘检测,首先计算边缘强度,通常用一阶导数表示,用计算值估计边缘的局部方向。

    对于零交叉的方法,是找到由图像得到的二阶导数的零交叉点来定位边缘。

   许多边缘检测的方法依赖于图像梯度的计算,用不同种类的滤波器来估计x方向和y方向的梯度。

   计算一阶导数:许多边缘检测都是基于高亮的一阶导数,这样就可以得到原始图像亮度的梯度。用这个梯度我们可以在图像的亮度梯度中寻找峰值,我们用l(x)表示点x的亮度,l’(x)表示点x的一阶导数(亮度梯度),我们可以用下面的方法来计算亮梯度:

 

 

   计算二阶导数:其他的边缘检测操作如基于亮度的二阶导数,这在数学上就是求一阶导数的变化率,也就是图像亮度的变化率,在二阶导数中检测过零点将得到梯度中的最大值,在二阶导数中的峰值检测是边线检测,边线是双重边缘,这样我们就可以在边缘的一边看到一个亮度梯度,在另一边看到相反的梯度,这样如果图像中有边线出现的话,我们就能在亮度梯度上看到非常大的变化,我们可以通过在二阶导数中寻找过零点来寻找边线。我们用I(x)来表示点x的亮度,I``(x)表示点x的亮度的二阶导数,那么可以这样计算:

 

 

 

所以,下面介绍边缘检测的一般步骤 :

(1) 、滤波:边缘检测算法是基于图像亮度的一阶导数和二阶导数,但是导数的计算对噪声很敏感,所以需要滤波器来改善图像,但是我们需要注意,大多数滤波器都会在降低噪声的同时导致边缘强度的减弱。

(2) 、增强:增强边缘的基础是确定图像各个点的邻域强度的变化值,可以将邻域强度值有显著变化的点突出出来,便于安装增强一般是通过计算梯度幅度来完成的。

(3) 、检测:在图像中有许多点的梯度幅度比较大,但是不都是我们需要的边缘,所以应该检测哪些点是边缘,可以通过设定梯度幅度阈值来检测。

(4) 、定位:确定边缘位置,但是大多数应用只需要指出边缘出现在图像的哪些区域,不需要指出图像边缘的精确位置或者方向。

 

二、几种边缘检测算子

 1、canny算子

   特点:

   (1)、低错误率:标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的干扰

   (2)、高定位性:标志出的边缘和图像中的边缘尽可能的接近

  (3)、最小响应:图像中的边缘只能标志一次,并且可能存在的噪声不应该标志为边缘

 

Canny边缘检测的步骤:

(1)、消除噪声:可以使用高斯平滑滤波器卷积降噪

(2)、计算梯度幅值和方向

<1>、运用一对卷积阵列(分别作用于x方向和y方向)

 

     

     <2>、使用下面的公式计算梯度幅值和方向

 

 

梯度方向将近似到四个可能的角度:0,45,90,135

 

(3)、非极大值抑制:仅仅保留了一些有可能是边缘的线条

(4)、滞后阈值:这是最后一步,滞后阈值需要两个阈值,一个高阈值一个低阈值

  <1>、如果某一像素的幅值超过高阈值,保留

  <2>、如果小于低阈值,不保留

  <3>、在中间,只有当这个像素连接到一个高于高阈值的像素时才保留

----------高低阈值比大概应该在<2:1 or 3:1>--------

 

(5)、函数详解:

```

void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false )

```

· 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。

· 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和类型。

· 第三个参数,double类型的threshold1,第一个滞后性阈值。

· 第四个参数,double类型的threshold2,第二个滞后性阈值。

· 第五个参数,int类型的apertureSize,表示应用Sobel算子的孔径大小,其有默认值3。

· 第六个参数,bool类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false。

 

2 、sobel算子

   (1)、分别在x和y两个方向求导

      <1>、水平变化,用I与一个奇数大小的内核做卷积,比如当内核大小为3x3时,可以这样就算Gx:

      <2>、垂直变化,用I与一个奇数大小的内核做卷积,比如当内核大小为3x3时,可以这样计算Gy:

 

 

 

 

   (2)、在图像的每一个点,结合上面两个方向上的计算结果求出近似梯度:

也可以使用更简单的公式来计算:

 

   (2)、函数详解:

void Sobel (

InputArray src,//输入图

 OutputArray dst,//输出图

 int ddepth,//输出图像的深度

 int dx,

 int dy,

 int ksize=3,

 double scale=1,

 double delta=0,

 int borderType=BORDER_DEFAULT );

 

· 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。

· 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。

· 第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合:

o 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

o 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_64F, 取ddepth = -1/CV_64F

· 第四个参数,int类型dx,x 方向上的差分阶数。

· 第五个参数,int类型dy,y方向上的差分阶数。

· 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。

· 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。

· 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。

· 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

 

3、laplace算子

 

定义:

 

函数详解:

 void Laplacian(InputArray src,OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, intborderType=BORDER_DEFAULT );

· 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。

· 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和通道数。

· 第三个参数,int类型的ddept,目标图像的深度。

· 第四个参数,int类型的ksize,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,且有默认值1。

· 第五个参数,double类型的scale,计算拉普拉斯值的时候可选的比例因子,有默认值1。

· 第六个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。

· 第七个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate()处得到更详细的信息。

 

  4、滤波器

void Scharr(

InputArray src, //源图

 OutputArray dst, //目标图

 int ddepth,//图像深度

 int dx,// x方向上的差分阶数

 int dy,//y方向上的差分阶数

 double scale=1,//缩放因子

 double delta=0,// delta值

 intborderType=BORDER_DEFAULT )// 边界模式

 

· 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。

· 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。

· 第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合:

o 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

o 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_64F, 取ddepth = -1/CV_64F

· 第四个参数,int类型dx,x方向上的差分阶数。

· 第五个参数,int类型dy,y方向上的差分阶数。

· 第六个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。

· 第七个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。

· 第八个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

 

 

 

 

 

0 0