OpenCV(Python3)_15(Canny边缘检测)

目标

在本章中,我们将会了解

理论

Canny边缘检测是一种流行的边缘检测算法。

降噪

由于边缘检测容易受到图像中的噪声影响,因此第一步是使用5x5高斯滤波器去除图像中的噪声。我们在前面的章节已经看到了这一点。因为噪声也集中于高频信号,很容易被识别为伪边缘。应用高斯模糊去除噪声,降低伪边缘的识别。但是由于图像边缘信息也是高频信号,高斯模糊的半径选择很重要,过大的半径很容易让一些弱边缘检测不到。

寻找图像的强度梯度

图像的边缘可以指向不同方向,因此经典Canny算法用了四个梯度算子来分别计算水平,垂直和对角线方向的梯度。但是通常都不用四个梯度算子来分别计算四个方向。常用的边缘差分算子(如Rober,Prewitt,Sobel)计算水平和垂直方向的差分Gx和Gy。这样就可以如下计算梯度模和方向:梯度方向总是垂直于边缘。它被四舍五入为表示垂直,水平和两个对角线方向的四个角度之一。

                            


梯度方向总是垂直于边缘。它被四舍五入为表示垂直,水平和两个对角线方向的四个角度之一。

非最大抑制

非最大值抑制是一种边缘细化方法。通常得出来的梯度边缘不止一个像素宽,而是多个像素宽。就像我们所说Sobel算子得出来的边缘粗大而明亮,从上面Lena图的Sobel结果可以看得出来。因此这样的梯度图还是很“模糊”。而准则3要求,边缘只有一个精确的点宽度。非最大值抑制能帮助保留局部最大梯度而抑制所有其他梯度值。这意味着只保留了梯度变化中最锐利的位置。算法如下:

  1. 比较当前点的梯度强度和正负梯度方向点的梯度强度。
  2. 如果当前点的梯度强度和同方向的其他点的梯度强度相比较是最大,保留其值。否则抑制,即设为0。比如当前点的方向指向正上方90°方向,那它需要和垂直方向,它的正上方和正下方的像素比较。

注意,方向的正负是不起作用的,比如东南方向和西北方向是一样的,都认为是对角线的一个方向。前面我们把梯度方向近似到水平,垂直和两个对角线四个方向,所以每个像素根据自身方向在这四个方向之一进行比较,决定是否保留。

                                              nms.jpg

点A在边缘上(在垂直方向上)。梯度方向与边缘垂直。B点和C点处于梯度方向。因此,点A,与点B和C进行比较,点A是否形成局部最大值。如果是这样,它被认为是边缘,否则,它被抑制(归零)。

滞后阈值

这个阶段决定哪些边缘是真正的边缘,哪些不是边缘。为此,我们需要两个阈值minVal和maxVal。强度梯度大于maxVal的任何边缘肯定是边缘,低于minVal的边缘肯定是非边缘,因此被丢弃。那些位于这两个阈值之间的点,则基于这些点是否与真正的边缘部分相连接如果它们连接到“真正边缘”像素,则它们被认为是边缘的一部分。否则,他们也被丢弃。看到下面的图片:

             

边缘A在maxVal之上,因此被视为“真正的边缘”。虽然边C低于maxVal,但它连接到边A,所以也被认为是有效边缘,我们得到了完整的曲线。但是边B虽然高于minVal,但它并没有连接到任何“真正的边缘”,因此被丢弃。因此,我们必须相应地选择minVal和maxVal以获得正确结果,这一点非常重要。

由于我们假设边缘都是一些较长的线段,因而这个阶段一些小的噪声点也会被消除。

所以我们最终得到的是图像中的边缘。

OpenCV中Canny边缘检测

OpenCV将所有上述内容放在单一函数cv.Canny()中我们将看到如何使用它。第一个参数是我们的输入图像。第二和第三个参数分别是我们的minVal和maxVal。第三个参数是用于设置查找图像梯度的Sobel内核的大小,默认情况下它是3。最后一个参数是L2gradient,它指定了寻找梯度幅度的公式。如果它是True,它使用上面提到的更精确的等式,否则,它使用下面这个方程:

                             

默认值是False。

程序:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('lena.jpg',0)
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()

结果:

                                                     

猜你喜欢

转载自blog.csdn.net/qq_27806947/article/details/80766762