美文网首页
图像卷积与边缘检测

图像卷积与边缘检测

作者: Byte猫 | 来源:发表于2019-05-22 23:53 被阅读0次

    什么是边缘检测

    边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。

    所谓边缘,就是图像中强度发生突变的区域,通常暗示着物体边界的存在。


    灰度变化不明显的部分会被过滤掉

    边缘检测的一般流程


    先灰度化,再用低通滤波器降噪,用高通滤波器提取边缘,最后二值化。
    低通滤波器见前面我发布的图像预处理,下面讲的都是高通滤波器。

    滤波器与卷积操作

    为了提取到图像的边缘,我们需要滤波器的帮助。这类滤波器以矩阵的形式存在,通常被称为卷积核,就是一些值网格,能够对图像进行修改。



    对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值。这样就完成了滤波过程。这种计算被称为图像卷积。



    卷积核上的每一位乘数被称为权值,它们决定了这个像素的分量有多重。它们的总和加起来如果等于1,不会改变图像的灰度强度。如果大于1,会增加灰度强度,使得图像变亮。如果小于1,会减少灰度强度,使得图像变暗。如果和为0,图像不会变黑,但也会非常暗(凸出边缘)。



    滤波器的大小应该是奇数,这样它才有一个中心,例如3x3,5x5或者7x7。有中心了,也有了半径的称呼,例如5x5大小的核的半径就是2。

    几种经典的过滤器

    1、索贝尔过滤器

    索贝尔过滤器常用于边缘检测和发现图像中的强度模式。向图像中应用索贝尔过滤器就相当于沿着 x 或 y 方向求图像的(近似)导数。
    Sobel_x和 Sobel_y的运算符分别如下所示:


    接下来,我们看看将这两种过滤器应用到大脑图像的示例。

    在上图中,可以看到在 x 和 y 方向计算的梯度检测出大脑的边缘并选出其他边缘。沿着 x 方向计算的梯度强调的是接近垂直方向的边缘,沿着 y 方向计算的梯度强调的是接近水平方向的边缘 。
    大小
    索贝尔还会检测哪些边缘最强,这一点体现在梯度大小上;大小越大,边缘越强。梯度的大小或绝对值是单个 x 和 y 梯度平方值的平方根。对于 x 和 y 方向的梯度,大小是平方和的平方根。

    方向
    在很多情形下,我们需要查找特定方向的边缘。例如,我们可能需要查找仅朝上或朝左的线条。通过单独计算 x 和 y 方向的图像梯度方向,我们可以判断该梯度的方向!
    梯度方向是指 y 梯度除以 x 梯度的反正切:
    # coding = utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2 as cv
    
    # 图像读取并灰度化
    image_stripes = cv.imread('images/stripes.jpg')
    image_stripes = cv.cvtColor(image_stripes, cv.COLOR_BGR2RGB)
    gray_stripes = cv.cvtColor(image_stripes, cv.COLOR_RGB2GRAY)
    
    sobel_x = np.array([[ -1, 0, 1], 
                       [ -2, 0, 2], 
                       [ -1, 0, 1]])
    
    sobel_y = np.array([[ -1, -2, -1], 
                       [ 0, 0, 0], 
                       [ 1, 2, 1]])
    
    filtered_image1 = cv.filter2D(gray_stripes, -1, sobel_x)
    filtered_image2 = cv.filter2D(gray_stripes, -1, sobel_y)
    

    2、拉普拉斯过滤器

    Laplace算子是一种各向同性算子,二阶微分算子,在只关心边缘的位置而不考虑其周围的像素灰度差值时比较合适。
    Laplace算子对孤立象素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图象。存在噪声情况下,使用Laplacian算子检测边缘之前需要先进行低通滤波。

    # coding = utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2 as cv
    
    # 图像读取并灰度化
    image_stripes = cv.imread('tools/33.jpg')
    image_stripes = cv.cvtColor(image_stripes, cv.COLOR_BGR2RGB)
    gray_stripes = cv.cvtColor(image_stripes, cv.COLOR_RGB2GRAY)
    
    laplacian=np.array([[0, 1, 0],
                        [1,-4, 1],
                        [0, 1, 0]])
    
    filtered_image = cv.filter2D(gray_stripes, -1, laplacian)
    

    了解更多

    3、Canny过滤器

    Canny边缘检测是一种非常流行的边缘检测算法,是John Canny在1986年提出的。它是一个多阶段的算法,即由多个步骤构成。
    首先,图像降噪。我们知道梯度算子可以用于增强图像,本质上是通过增强边缘轮廓来实现的,也就是说是可以检测到边缘的。但是,它们受噪声的影响都很大。那么,我们第一步就是想到要先去除噪声,因为噪声就是灰度变化很大的地方,所以容易被识别为伪边缘。
    第二步,计算图像梯度,得到可能边缘。计算图像梯度能够得到图像的边缘,因为梯度是灰度变化明显的地方,而边缘也是灰度变化明显的地方。当然这一步只能得到可能的边缘。因为灰度变化的地方可能是边缘,也可能不是边缘。这一步就有了所有可能是边缘的集合。
    第三步,非极大值抑制。通常灰度变化的地方都比较集中,将局部范围内的梯度方向上,灰度变化最大的保留下来,其它的不保留,这样可以剔除掉一大部分的点。将有多个像素宽的边缘变成一个单像素宽的边缘。即“胖边缘”变成“瘦边缘”。
    第四步,双阈值筛选。通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(low),高阈值(high)。灰度变化大于high的,设置为强边缘像素,低于low的,剔除。在low和high之间的设置为弱边缘。进一步判断,如果其领域内有强边缘像素,保留,如果没有,剔除。这样做的目的是只保留强边缘轮廓的话,有些边缘可能不闭合,需要从满足low和high之间的点进行补充,使得边缘尽可能的闭合。

    # coding = utf-8
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2 as cv
    
    # 图像读取并灰度化
    image_stripes = cv.imread('tools/33.jpg')
    image_stripes = cv.cvtColor(image_stripes, cv.COLOR_BGR2RGB)
    gray_stripes = cv.cvtColor(image_stripes, cv.COLOR_RGB2GRAY)
    
    lower = 50
    upper = 100
    
    edges = cv.Canny(gray_stripes, lower, upper)
    plt.imshow(edges)
    plt.show()
    

    相关文章

      网友评论

          本文标题:图像卷积与边缘检测

          本文链接:https://www.haomeiwen.com/subject/pyqszqtx.html