现在的位置: 首页 > 综合 > 正文

边缘检测之Canny算法详谈

2014年10月25日 ⁄ 综合 ⁄ 共 6454字 ⁄ 字号 评论关闭

在Canny算法前面,先稍微讲一下边缘检测,图像分割

点击打开链接(此处转载)

图像分割主要包括4种技术:并行边界分割技术、串行边界分割技术、并行区域分割技术和串行区域分割技术。

下面是分别对每一项做简单的介绍。

1.并行边界分割

不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘指的是图像中像素的值有突变的地方,而物体间的边界指的是现实场景中的存在于物体之间的边界。有可能有边缘的地方并非边界,也有可能边界的地方并无边缘,因为现实世界中的物体是三维的,而图像只具有二维信息,从三维到二维的投影成像不可避免的会丢失一部分信息;另外,成像过程中的光照和噪声也是不可避免的重要因素。正是因为这些原因,基于边缘的图像分割仍然是当前图像研究中的世界级难题,目前研究者正在试图在边缘提取中加入高层的语义信息。

在实际的图像分割中,往往只用到一阶和二阶导数,虽然,原理上,可以用更高阶的导数,但是,因为噪声的影响,在纯粹二阶的导数操作中就会出现对噪声的敏感现象,三阶以上的导数信息往往失去了应用价值。二阶导数还可以说明灰度突变的类型。在有些情况下,如灰度变化均匀的图像,只利用一阶导数可能找不到边界,此时二阶导数就能提供很有用的信息。二阶导数对噪声也比较敏感,解决的方法是先对图像进行平滑滤波,消除部分噪声,再进行边缘检测。不过,利用二阶导数信息的算法是基于过零检测的,因此得到的边缘点数比较少,有利于后继的处理和识别工作。

各种算子的存在就是对这种导数分割原理进行的实例化计算,是为了在计算过程中直接使用的一种计算单位;

 

Roberts算子:边缘定位准,但是对噪声敏感。适用于边缘明显且噪声较少的图像分割。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分析,由于Robert算子通常会在图像边缘附近的区域内 产生较宽的响应,故采用上述算子检测的边缘图像常需做细化处理,边缘定位的精度不是很高。

Prewitt算子:对噪声有抑制作用,抑制噪声的原理是通过像素平均,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位不如Roberts算子。

Sobel算子:Sobel算子和Prewitt算子都是加权平均,但是Sobel算子认为,邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小。

Isotropic Sobel算子:加权平均算子,权值反比于邻点与中心点的距离,当沿不同方向检测边缘时梯度幅度一致,就是通常所说的各向同性。

在边沿检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边沿的 ;另一个是检测垂直平边沿的 。Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。由于建筑物图像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
    由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数, 简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。  在观测一幅图像的时候,我们往往首先注意的是图像与背景不同的部分,正是这个部分将主体突出显示,基于该理论,我们可以给出阈值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解是最优的。

上面的算子是利用一阶导数的信息,属于梯度算子范畴。

Laplacian算子:这时二阶微分算子。其具有各向同性,即与坐标轴方向无关,坐标轴旋转后梯度结果不变。但是,其对噪声比较敏感,所以,图像一般先经过平滑处理,因为平滑处理也是用模板进行的,所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。

Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;最后Laplacian算子不能检测边缘的方向;所以Laplacian在分割中所起的作用包括:(1)利用它的零交叉性质进行边缘定位;(2)确定一个像素是在一条边缘暗的一面还是亮的一面;一般使用的是高斯型拉普拉斯算子(Laplacian of a Gaussian,LoG),由于二阶导数是线性运算,利用LoG卷积一幅图像与首先使用高斯型平滑函数卷积改图像,然后计算所得结果的拉普拉斯是一样的。所以在LoG公式中使用高斯函数的目的就是对图像进行平滑处理,使用Laplacian算子的目的是提供一幅用零交叉确定边缘位置的图像;图像的平滑处理减少了噪声的影响并且它的主要作用还是抵消由Laplacian算子的二阶导数引起的逐渐增加的噪声影响。

2.串行边界分割

并行边缘检测的方法,对图像的每一点上所做的处理不依赖于其它的点处理结果。串行边界分割在处理图像时不但利用了本身像素的信息,而且利用前面处理过像素的结果。对某个像素的处理,以及是否把它分类成为边界点,和先前对其它点的处理得到的信息有关。串行边界分割技术通常是通过顺序的搜索边缘点来工作的,一般有三个步骤1.起始边缘点的确定。2.搜索准则,将根据这个准则确定下一个边缘点。3.终止条件,设定搜索过程结束的条件。

边界跟踪是一种串行边界分割的方法。

边界跟踪是由梯度图中一个边缘点出发,搜索并连接边缘点进而逐步检测所有边界的方法。在并行边界分割法中,边缘像素不一定能够组合成闭合的曲线,因为边界上有可能会遇到缺口。缺口可能太大而不能用一条直线或曲线连接,也有可能不是一条边界上的缺口。边界跟踪的方法者可以在一定程度上解决这些问题,对某些图像,这种方法的分割结果更好。具体算法是,先对原图像进行梯度运算,然后进行边界跟踪算法。1.起始点:对梯度图搜索,找到梯度最大点,做为边界跟踪的开始点。2.生长规则:在这个点的8邻域像素中,梯度最大的点被当做边界,同时,这个点还会做为下一个搜索的起始点。3.终止条件:按照2的准则一直搜索,直到梯度绝对值小于一个阈值时,搜索停止。有时为了保证边界的光滑性,每次只是在一定的范围的像素中选择,这样得到的边界点不但能保证连通性,还能保证光滑性。

 

3.并行区域分割

并行区域分割主要有两种方法:阈值分割聚类

直接的阈值分割一般不能适用于复杂景物的正确分割,如自然场景,因为复杂景物的图像,有的区域很难判断究竟是前景还是背景。不过,阈值分割在处理前景和背景有很强的对比的图像时特别有用,此时需要的计算复杂度小。当物体的灰度级比较集中时,简单的设置灰度级阈值提取物体是一个有效的办法。

阈值方法分为全局阈值局部阈值两种,如果分割过程中对图像上每个像素所使用的阈值都相等,则为全局阈值方法;如果每个像素所使用的阈值可能不同,则为局部阈值方法。最佳全局阈值的确定的常用方法一般有下面几种:试验法,直方图法,最小误差法(这种方法是假设背景和前景的灰度分布都是正态分布的)。当光照不均匀、有突发噪声,或者背景灰度变化比较大时,整幅图像分割将没有合适的单一门限,因为单一的阈值不能兼顾图像各个像素的实际情况。这时,可对图像按照坐标分块,对每一块分别选一阈值进行分割,这种与坐标相关的阈值称为动态阈值方法,也称为自适应阈值方法。这类方法的时间和空间复杂度比较大,但是抗噪声能力比较强,对采用全局阈值不容易分割的图像有较好的效果。自适应阈值选取的比较简单的方法时对每一个像素确定以它为中心的一个邻域窗口,计算窗口内像素的最大和最小值,然后取它们的均值做为阈值。对图像分块后的每一个子块可以采用直方图分析,如果某个子块内有目标和背景,则直方图呈双峰。如果块内只有目标或背景,则直方图没有双峰,可根据邻域各块分割得到的参数插值进行分割。实际的自适应阈值分割完全可以根据图像的实际性质,对每个像素设定阈值,但这个过程要考虑到实际的要求和计算的复杂度问题。

4.串行区域分割

串行区域分割一般可分为两种方法:一种是区域生长,二是分裂合并。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于1.初始点(种子点)的选取2.生长准则3.终止条件。

区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取。分裂合并差不多是区域生长的逆过程:从整个图像出发,不断分裂得到各个子区域,然后再把前景区域合并,实现目标的提取。分裂合并的假设是对于一幅图像,前景区域由一些相互连通的像素组成,因此,如果把一幅图像分裂到像素级,那么就可以判定该像素是否为前景像素,当所有像素点或者子区域完成判断后,把前景区域或像素合并就可得到前景目标。

前面啰嗦的有点多,不过,仔细看看确实有用

在OpenCV中读图像进行边缘检测的步骤

1 对原始图像进行灰度化

        Canny算法通常处理的图像为灰度图,因此如果摄像机获取的是彩色图像,那首先就得进行灰度化。对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。以RGB格式的彩图为例,通常灰度化采用的方法主要有:

        方法1:Gray=(R+G+B)/3;

        方法2:Gray=0.299R+0.587G+0.114B;(这种参数考虑到了人眼的生理特点)

2 对图像进行高斯滤波

        图像高斯滤波的实现可以用两个一维高斯核分别两次加权实现,也可以通过一个二维高斯核一次卷积实现。

        1)高斯核实现

      
上式为离散化的一维高斯函数,确定参数就可以得到一维核向量。


        上式为离散化的二维高斯函数,确定参数就可以得到二维核向量。

        注意1:关于参数Sigma的取值详见上篇博文。

        注意2:在求的高斯核后,要对整个核进行归一化处理。

2)图像高斯滤波

        对图像进行高斯滤波,听起来很玄乎,其实就是根据待滤波的像素点及其邻域点的灰度值按照一定的参数规则进行加权平均。这样可以有效滤去理想图像中叠加的高频噪声。

        通常滤波和边缘检测是矛盾的概念,抑制了噪声会使得图像边缘模糊,这回增加边缘定位的不确定性;而如果要提高边缘检测的灵敏度,同时对噪声也提高了灵敏度。实际工程经验表明,高斯函数确定的核可以在抗噪声干扰和边缘检测精确定位之间提供较好的折衷方案。这就是所谓的高斯图像滤波

3 用一阶偏导的有限差分来计算梯度的幅值和方向

  
     关于图像灰度值得梯度可使用一阶有限差分来进行近似,这样就可以得图像在x和y方向上偏导数的两个矩阵。
常用的梯度算子有如下几种:

  
     1)Roberts算子


  
     上式为其x和y方向偏导数计算模板,可用数学公式表达其每个点的梯度幅值为:

  
     2)Sobel算子

  
     上式三个矩阵分别为该算子的x向卷积模板、y向卷积模板以及待处理点的邻域点标记矩阵,据此可用数学公式表达其每个点的梯度幅值为:

  
     3)Prewitt算子

  
     和Sobel算子原理一样,在此仅给出其卷积模板。

4 对梯度幅值进行非极大值抑制  
     图像梯度幅值矩阵中的元素值越大,说明图像中该点的梯度值越大,但这不不能说明该点就是边缘(这仅仅是属于图像增强的过程)。在Canny算法中,非极大值抑制是进行边缘检测的重要步骤,通俗意义上是指寻找像素点局部最大值,将非极大值点所对应的灰度值置为0,这样可以剔除掉一大部分非边缘的点(这是本人的理解)。


图1 非极大值抑制原理

  
     根据图1 可知,要进行非极大值抑制,就首先要确定像素点C的灰度值在其8值邻域内是否为最大。图1中蓝色的线条方向为C点的梯度方向,这样就可以确定其局部的最大值肯定分布在这条线上,也即出了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。因此,判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点。如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。这就是非极大值抑制的工作原理。

  
     作者认为,在理解的过程中需要注意以下两点:

  
     1)中非最大抑制是回答这样一个问题:“当前的梯度值在梯度方向上是一个局部最大值吗?” 所以,要把当前位置的梯度值与梯度方向上两侧的梯度值进行比较;

  
     2)梯度方向垂直于边缘方向。

  
     但实际上,我们只能得到C点邻域的8个点的值,而dTmp1和dTmp2并不在其中,要得到这两个值就需要对该两个点两端的已知灰度进行线性插值,也即根据图1中的g1和g2对dTmp1进行插值,根据g3和g4对dTmp2进行插值,这要用到其梯度方向,这是上文Canny算法中要求解梯度方向矩阵Thita的原因。

  
     完成非极大值抑制后,会得到一个二值图像,非边缘的点灰度值均为0,可能为边缘的局部灰度极大值点可设置其灰度为128。根据下文的具体测试图像可以看出,这样一个检测结果还是包含了很多由噪声及其他原因造成的假边缘。因此还需要进一步的处理。

5 用双阈值算法检测和连接边缘

        Canny算法中减少假边缘数量的方法是采用双阈值法。选择两个阈值(关于阈值的选取方法在扩展中进行讨论),根据高阈值得到一个边缘图像,这样一个图像含有很少的假边缘,但是由于阈值较高,产生的图像边缘可能不闭合,未解决这样一个问题采用了另外一个低阈值。

        在高阈值图像中把边缘链接成轮廓,当到达轮廓的端点时,该算法会在断点的8邻域点中寻找满足低阈值的点,再根据此点收集新的边缘,直到整个图像边缘闭合。

函数原型:

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
              double threshold2, int aperture_size=3 );
image
单通道输入图像.
edges
单通道存储边缘的输出图像
threshold1
第一个阈值
threshold2
第二个阈值
aperture_size
Sobel 算子内核大小,默认是3
//  根据《学习OpenCV》例 2-6 改编
    //  定义工作位图
	IplImage* pImg8u = NULL;
	IplImage* pImg8uSmooth = NULL;
	IplImage* pImgCanny = NULL;
 
	//**  输入待处理图像  **                //  修改部分 1

	if (workImg->nChannels==3) {
 		pImg8u=cvCreateImage(cvGetSize(workImg),IPL_DEPTH_8U,1);
		cvCvtColor(workImg,pImg8u,CV_BGR2GRAY);
		imageReplace(pImg8u,&workImg);
	}
 	pImg8u = workImg;

    //  建立辅助位图
	pImg8uSmooth=cvCreateImage(cvGetSize(pImg8u),IPL_DEPTH_8U,1);
	pImgCanny   =cvCreateImage(cvGetSize(pImg8u),IPL_DEPTH_8U,1);

	//  图像处理
 	cvSmooth(pImg8u,pImg8uSmooth,CV_GAUSSIAN,3,0,0);
	cvCanny(pImg8uSmooth,pImgCanny,100,200,3);

抱歉!评论已关闭.