• OpenCVPython系列之Canny边缘检测


    上一个教程中我们谈到的拉普拉斯算子本质上属于图像的边缘检测,但是我们同时也看到,拉普拉斯算子有一定的局限性,对于复杂图像的边缘检测有些力不从心,本次我们将介绍一个在OpenCV中有着决定性地位的边缘检测——Canny算法。

    我们在前面已经了解过,边缘检测算法通常有四个步骤:

    (1)滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数的计算对噪声很敏感,因此必须使用滤波器来改善与噪声有关的边缘检测器的性能.需要指出,大多数滤波器在降低噪声的同时也导致了边缘强度的损失,因此,增强边缘和降低噪声之间需要折衷.

    (2)增强:增强边缘的基础是确定图像各点邻域强度的变化值.增强算法可以将邻域(或局部)强度值有显著变化的点突显出来.边缘增强一般是通过计算梯度幅值来完成的.

    (3)检测:在图像中有许多点的梯度幅值比较大,而这些点在特定的应用领域中并不都是边缘,所以应该用某种方法来确定哪些点是边缘点.最简单的边缘检测判据是梯度幅值阈值判据.

    (4)定位:如果某一应用场合要求确定边缘位置,则边缘的位置可在子像素分辨率上来估计,边缘的方位也可以被估计出来.

    在边缘检测算法中,前三个步骤用得十分普遍。这是因为大多数场合下,仅仅需要边缘检测器指出边缘出现在图像某一像素点的附近,而没有必要指出边缘的精确位置或方向.边缘检测误差通常是指边缘误分类误差,即把假边缘判别成边缘而保留,而把真边缘判别成假边缘而去掉.边缘估计误差是用概率统计模型来描述边缘的位置和方向误差的.我们将边缘检测误差和边缘估计误差区分开,是因为它们的计算方法完全不同,其误差模型也完全不同.

    Canny边缘检测算法

    JohnCanny于1986年提出Canny算子,它与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法。本节对根据上述的边缘检测过程对Canny检测算法的原理进行介绍。

    1、灰度化

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

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

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

    注意1:至于其他格式的彩色图像,可以根据相应的转换关系转为RGB然后再进行灰度化;

    注意2:在编程时要注意图像格式中RGB的顺序通常为BGR。

    2、高斯滤波

    f(x,y)表示数据(输入源数据),G(x,y)表示二维高斯函数(卷积操作数),fs(x,y)为卷积平滑后的图像。

    image.png

    image.png

    Guess过程:

    用坐标点(x,y)表示一个3x3的邻域,设中心点的坐标为(0,0),相邻的点以此类推。

    image.png

    计算权重矩阵。设定方差σ2=0.64的值,将对应各个坐标点(x,y)带入二维高斯公式G(x,y)中,得到一个权重矩阵,归一化权重矩阵(矩阵中各个点除以权重之和),得到标准的权重矩阵,即高斯模板。

    image.png

    计算高斯模糊。设在一幅图像中的3×3区域内,用各像素点的灰度值乘以对应点的权重。

    image.png

    image.png

    - 将得到的9个值求和,就是中心点的高斯模糊值。

    image.png

    简单来说就是使用Guess模板在原始图像中进行移位、相乘、相加的过程。

    3、计算幅值图像、角度图像

    求变化率时,对于一元函数,即求导;对于二元函数,求偏导。数字图像处理中,用一阶有限差分近似求取灰度值的梯度值(变化率)。

    例:计算一点x方向和y方向的梯度幅值和方向

    image.png

    上图中显示一段直的边缘线段放大后一部分,每个方块代表一个像素点,用一个方框强调点处边缘的幅值和方向。令灰色像素值为0,白色像素值为1。

    如图关于一点为中心的 3×3邻域,使用Prewittt卷积模板进行计算:

    image.png

    根据x方向和y方向的卷积模板,可知,在3x3的邻域中从底部一行像素值减去顶部一行的像素,得到x方向的偏导数(梯度);同样,从右边一列像素值减去左边一列的像素,得到y方向的偏导数。

    x方向的梯度:

    image.png

    y方向的梯度:

    image.png

    由此,可以得到该点梯度的幅值和方向:

    image.png

    如下图表示了中心点的梯度向量、方位角以及边缘方向。(任一点的边缘与梯度向量正交):

    image.png

    Canny算子的卷积模板为:

    image.png

    image.png

    4、对幅值图像进行非极大值抑制

    首先将角度划分成四个方向范围:水平(0°)、−45°、垂直(90°)、+45°如下图:

    image.png

    - 接着讨论对3x3区域的四个基本边缘方向进行非极大值抑制。

    image.png

    做法:若中心点(即:访问点)在沿其方向上邻域的梯度幅值最大,则保留;否则,抑制。

    5、双阈值检测和连接边缘

    选取系数TH和TL,比率为2:1或3:1。(一般取TH=0.3或0.2,TL=0.1);

    取出非极大值抑制后的图像中的最大梯度幅值,定义高低阈值。即:TH×Max,TL×Max (当然可以自己给定) ;

    将小于低阈值的点抛弃,赋0;将大于高阈值的点立即标记(这些点就是边缘点),赋1;

    将小于高阈值,大于低阈值的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋  1)。

    现在我们来看看函数原型:

    edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])

    必要参数:

    第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;

    第二个参数是阈值1;

    第三个参数是阈值2。

    其中较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来。

    可选参数中apertureSize就是Sobel算子的大小。而L2gradient参数是一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)。

    现在我们来看代码:

    import cv2
    import numpy as np
    
    img = cv2.imread("credit_card_.png",0)
    dst = cv2.Canny(img,150,200)
    cv2.imshow("img",img)
    cv2.imshow("res",dst)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    image.png

    可以看到,效果非常好,卡片数字边缘都被准确的识别出来了。大家对于Canny边缘检测一定要熟练的掌握,它具有非常重要的作用。

  • 相关阅读:
    Oracle-连接多个字段
    Oracle-like 多条件过滤
    SQL-Union、Union ALL合并两个或多个 SELECT 语句的结果集
    EXCEL-批量删除筛选出的行,并且保留首行
    EXCEL-REPLACE()替换字符串最后几位 删除字符串最后几位
    Oracle-常用表的查询、增加列、删除列、修改列值功能【增删改查】
    Excel-返回列表或数据库中的分类汇总(汇总可以实现要还是不要统计隐藏行功能) subtotal()
    Excel-统计各分数段人数 frequency()
    Excel-给出指定数值的日期 date()
    Class类的理解与获取Class的实例
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15656383.html
Copyright © 2020-2023  润新知