目标
- Canny边缘检测的基本概念。
- OpenCV 函数:cv.Canny()。
理论
Canny Edge Detection 是一种流行的边缘检测算法。
1、这是一个多阶段算法,我们将经历每个阶段。
2、降噪:由于边缘检测容易受到图像中噪声的影响,因此第一步是使用 5x5 高斯滤波器去除图像中的噪声。我们已经在前面的章节中看到了这一点。
3、寻找图像的强度梯度:然后在水平和垂直方向上使用 Sobel 核对平滑后的图像进行滤波,以获得水平方向 (Gx) 和垂直方向 (Gy) 的一阶导数。从这两幅图像中,我们可以找到每个像素的边缘梯度和方向如下:
4、非极大值抑制(NMS):在获得梯度幅度和方向后,对图像进行全面扫描以去除可能不构成边缘的任何不需要的像素。为此,在每个像素处,检查像素是否在梯度方向上是其邻域中的局部最大值。检查下图:
A点在边缘(垂直方向)。梯度方向垂直于边缘。 B点和C点在梯度方向上。因此,A 点与 B 点和 C 点一起检查,看它是否形成局部最大值。如果是,则考虑下一阶段,否则,它被抑制(置零)。
简而言之,你得到的结果是具有“薄边缘”的二值图像。
5、迟滞阈值:这个阶段决定哪些边都是真正的边,哪些不是。为此,我们需要两个阈值,minVal 和 maxVal。任何强度梯度大于 maxVal 的边肯定是边,而那些小于 minVal 的边肯定是非边,因此被丢弃。位于这两个阈值之间的那些根据它们的连通性被分类为边缘或非边缘。如果它们连接到“确定边缘”像素,则它们被认为是边缘的一部分。否则,它们也被丢弃。见下图:
边 A 高于 maxVal,因此被视为“确定边”。尽管边 C 低于 maxVal,但它连接到边 A,因此也被视为有效边,我们得到了完整的曲线。但是边 B,虽然它高于 minVal 并且与边 C 在同一区域,但它没有连接到任何“确定边”,因此被丢弃。因此,我们必须相应地选择 minVal 和 maxVal 以获得正确的结果,这一点非常重要。
OpenCV的Canny边缘检测
OpenCV 将上述所有内容放在单个函数 cv.Canny() 中。我们将看到如何使用它。第一个参数是我们的输入图像。第二个和第三个参数分别是我们的 minVal 和 maxVal。第四个参数是 aperture_size。它是用于查找图像梯度的 Sobel 内核的大小。默认情况下它是 3。最后一个参数是 L2gradient,它指定了寻找梯度大小的方程。如果为真,则使用上面提到的更准确的等式,否则使用此函数:,默认情况下,它是false的。
import cv2 as cv
def nothing(x):
pass
img = cv.imread('smallsong.jpg')
cv.namedWindow('image')
cv.createTrackbar('maxVal','image',0,200,nothing)
cv.createTrackbar('minVal','image',0,200,nothing)
while(1):
k = cv.waitKey(1) & 0xFF
if k == 27:
break
maxVal = cv.getTrackbarPos('maxVal', 'image')
minVal = cv.getTrackbarPos('minVal', 'image')
if maxVal > minVal:
edges = cv.Canny(img, maxVal, minVal)
cv.imshow('image', edges)
else:
print('error')
cv.destroyAllWindows()
上面的代码我改了,加了trackbar,可以看到阈值梯度不同带来的不同结果,这也是参考文档上的作业。