翻译及二次校对:cvtutorials.com
目标
在本章中,我们将了解到:
- • Canny边缘检测的概念
- • 用于检测的OpenCV函数:cv.Canny()
理论
Canny边缘检测是一种流行的边缘检测算法。它是由John F. Canny在2006年开发的。
- 1. 它是一个多阶段的算法,我们将对每个阶段进行分析。
- 2. 减少噪音
由于边缘检测容易受到图像中噪音的影响,第一步是用5x5高斯滤波器去除图像中的噪音。我们已经在前几章中看到了这一点。
- 1. 寻找图像的灰度梯度
然后用Sobel核对水平和垂直方向的平滑图像进行过滤,得到水平方向(Gx)和垂直方向(Gy)的第一导数。从这两幅图像中,我们可以找到每个像素的边缘梯度和方向,如下所示。
梯度方向总是垂直于边缘。它被圆整为四个角度之一,代表垂直、水平和两个对角线方向。
- 1. 非极大值抑制
在得到梯度大小和方向后,对图像进行全面扫描,以去除任何可能不构成边缘的不必要的像素。为此,在每一个像素点上,检查该像素点是否是梯度方向上其附近的局部最大值。请看下面的图片。
A点在边缘上(垂直方向)。梯度方向是对边缘的法线。B点和C点在梯度方向上。因此,A点与B点和C点一起被检查,看它是否形成一个局部最大值。如果是,它将被考虑到下一阶段,否则,它将被抑制(归为零)。
简而言之,你得到的结果是一个具有 "薄边缘 "的二进制图像。
- 1. 滞后阈值处理
这个阶段决定哪些是真正的边缘,哪些不是。为此,我们需要两个阈值,minVal和maxVal。任何灰度梯度大于maxVal的边缘都肯定是边缘,而那些低于minVal的边缘肯定是非边缘,所以被丢弃。那些位于这两个阈值之间的边,根据它们的连接性被分为边和非边。如果它们与 "确定的边缘 "像素相连,它们就被认为是边缘的一部分。否则,它们也会被丢弃。请看下面的图片。
边缘A高于maxVal,所以被认为是 "确定边缘"。虽然边C低于maxVal,但它与边A相连,所以也被认为是有效的边,我们得到了那个完整的曲线。但是边B,尽管它高于minVal,并且与边C在同一区域,但它没有与任何 "确定的边 "相连,所以它被丢弃了。因此,我们必须相应地选择minVal和maxVal以获得正确的结果,这一点非常重要。
这个阶段还在假设边缘是长线的基础上去除小像素的噪音。
所以我们最终得到的是图像中的强边缘。
OpenCV中的Canny边缘检测
OpenCV把上述所有的东西都放在一个函数中,即cv.Canny()。我们将看到如何使用它。第一个参数是我们的输入图像。第二个和第三个参数分别是我们的minVal和maxVal。第三个参数是aperture_size。它是用于寻找图像梯度的Sobel核的大小。最后一个参数是L2gradient,它指定了用于寻找梯度大小的方程式。如果它是True,它使用上面提到的更精确的方程,否则它使用这个函数。Edge_Gradient(G)=|Gx| |Gy|。默认情况下,它是False。
代码语言:javascript复制import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.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()
结果如下:
其他资源
- 1. 维基百科上的Canny边缘检测器
- 2. 《Canny边缘检测教程》,作者Bill Green,2002年。
练习
写一个小程序来寻找Canny边缘检测,其阈值可以用两个trackbar来改变。这样,你就可以了解阈值的影响。