边缘检测算子之Canny

1.1Canny算法简介

Canny 边缘检测算子是 JohnF. Canny 在 1986 年提出的一个多级边缘检测算子。Canny算法与简单的基于拉普拉斯算法的不同点之一是在Canny算法中,首先在x和y方向求一阶导数,然后组合为4个方向的导数。这些方向导数达到局部最大值的点就是组成边缘的候选点。

然而,Canny算法最重要的一个新特点是其试图将独立边的候选像素拼装成轮廓。轮廓的形成是对这些像素运用滞后性阈值。这意味着有两个阈值,上限和下限。如果一个像素的梯度大于上限阈值,则被认为是边缘像素,如果低于下限阈值,则被抛弃,如果介于二者之间,只有当其与高于上限阈值的像素连接时才会被接受。

Canny推荐的上下限阈值为2:1到3:1之间。

1.2Canny流程

Canny 提出了三个严格的边缘检测标准:1)最优检测标准,即对边缘点和非边缘点具有较高的区分概率;2)最优定位准则,即判定的边缘点的位置应尽可能靠近真实边缘的中心位置;3)单边响应准则,即对于每个检测出的边缘点,应当仅有一个响应,最大可能地抑制伪边缘的出现。Canny 算子对数字图像进行边缘检测主要分为四步进行:1)对图像进行二维高斯滤波;2)通过一阶微分计算图像的灰度梯度幅值和方向;3)对计算出的梯度幅值进行非极大值抑制(Non-MaximaSuppression, NMS);4)通过人为设定的高低阈值确定图像的边缘。

(1)二维高斯滤波

(2)计算图像灰度的梯度幅值和方向

(3)对图像的梯度幅值进行非极大值抑制

图像中,梯度值较大的点不一定就是图像中的边缘点,为了进一步的剔除这些点对边缘检测的影响,细化图像中的屋脊带,更准确地定位图像中的边缘点,需要对一阶微分计算后的图像数据进行非极大值抑制,只保留幅值局部变化最大的点。非极大值抑制在像素的 3×3 邻域上,沿梯度方向进行梯度幅值的插值,并将中心像素的梯度值与沿梯度方向相邻的 2 个梯度幅值的插值结果进行比较,若像素点本身的梯度幅值H[i,j]比梯度方向上的 2 个插值小,则将H[i,j]对应的边缘标志位赋值为 0,反之,则认为该像素为初选边缘点,H[i,j]的值保持不变。通过非极大值抑制,可以把图像梯度幅值矩阵H[i,j]中的宽屋脊带细化到一个像素宽,并且保留了屋脊的梯度幅值。

(4)双阈值确定图像边缘

假设图像梯度幅值矩阵H[i,j]经非极大值抑制后的图像为Q[i,j],此时Q[i,j]中仍可能含有由于噪声和纹理存在的原因而检测到的假边缘。不同于前面所述的经典微分算子,Canny算子采用双阈值算法对图像做进一步处理,消除假边缘。假定设定的高低阈值分别为th和tl,通常情况下tl=0.5*th,那么,在图像边缘阵列 Q[i,j]中,梯度值大于th的点被标记为边缘点,梯度值小于tl的点则被视为非边缘点。对于梯度值介于th与tl之间的像素点,若其8邻域中存在已经被标记的边缘点,则该点也标记为边缘点,否则标记为非边缘点。

1.3Canny算子格式

采用 Canny 算法做边缘检测

 

void cvCanny( const CvArr* image, CvArr*edges, double threshold1, double threshold2, int aperture_size=3 );

image

单通道输入图像.

edges

单通道存储边缘的输出图像

threshold1

第一个阈值

threshold2

第二个阈值

aperture_size

Sobel 算子内核大小 (见 cvSobel).

函数 cvCanny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。threshold1和threshold2 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。

 

注意事项:因此cvLoadImage的第二给参数表示是否加载有颜色的图像,因设为0,表示单通道图像,故src = cvLoadImage(argv[1], 0 );

否则会出现编译错误,会提示canny.cpp不合法。

 

1.4范例

#include <highgui.h>

#include <cv.h>

#include <cxcore.h>  //人脸识别的一个库文件

 

//Canny:Implements Canny algorithm for edgedetection.

int main( int argc, char** argv )

{

       IplImage*src = NULL;

       IplImage*dst = NULL;

      

       //载入图像,转换为灰度图

       src= cvLoadImage( argv[1], 0 ); 

       //为canny边缘图像申请空间,1表示单通道灰度图

       dst= cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 1 );

       cvCanny(src, dst, 50, 150, 3 );//边缘检测

       cvNamedWindow("src", 1 );

       cvNamedWindow("canny", 1 );

       cvShowImage("src", src );

       cvShowImage("canny", dst );

       cvWaitKey(0);

 

       cvReleaseImage(&src );

       cvReleaseImage(&dst );

       cvDestroyAllWindows();

       return0;

 

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sobel算子Canny算子、Prewitt边缘检测算子和Roberts边缘检测算子都是常用的图像边缘检测算法,它们各有优缺点,下面对它们进行比较: 1. Sobel算子 Sobel算子是一种基于梯度的边缘检测算法,它可以在图像中检测到水平和垂直方向上的边缘。相对于其他算法,Sobel算子计算速度快,易于实现,同时在边缘检测中也有较好的效果。但是,Sobel算子只能检测到水平和垂直方向上的边缘,对于斜向边缘的检测效果不太好。 2. Canny算子 Canny算子是一种常用的边缘检测算法,它利用高斯滤波器平滑图像,然后计算梯度,最后使用非极大值抑制和双阈值处理来检测边缘。Canny算子可以检测到所有方向上的边缘,同时它通过双阈值处理可以控制检测到的边缘数量。但是,Canny算子的计算量比较大,运行速度比较慢。 3. Prewitt边缘检测算子 Prewitt算子也是一种基于梯度的边缘检测算法,它与Sobel算子类似,可以检测到水平和垂直方向上的边缘。相对于Sobel算子,Prewitt算子的计算量较小,但是在边缘检测中的效果不如Sobel算子。 4. Roberts边缘检测算子 Roberts算子是一种基于微分的边缘检测算法,它使用两个 $2\times 2$ 的卷积核来计算图像中每个像素点的梯度值,从而得到边缘信息。相对于其他算法,Roberts算子计算速度快,但其缺点是对噪声比较敏感,且检测到的边缘比较粗糙。 综上所述,不同的边缘检测算法有各自的优缺点,需要根据实际应用场景进行选择。在一些需要快速处理的场景中,可以选择Sobel算子或Roberts算子;在需要精确检测、对噪声抗干扰的场景中,可以选择Canny算子;在计算资源有限的场景中,可以选择Prewitt算子

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值