【文档翻译】OpenCV-Canny Edge Detection

原文 https://docs.opencv.org/3.1.0/da/d22/tutorial_py_canny.html

1. Goal

本章节我们将学到:

  1. Canny 边缘检测的概念;
  2. OpenCV 函数 cv2.Canny() 的使用;

2. Theory

Canny 边缘检测是一个相当流行的边缘检测算法,它由 John F. Canny 提出。该算法是一个多步骤的算法,接下来我们将介绍其中的每一个步骤。

2.1 Noise Reduction

由于边缘检测对图像中的噪点非常敏感,所以第一步就是过滤到图像中的噪声。这一步通过一个 5x5 的高斯滤波完成,即对图像进行模糊处理。

2.2 Finding Intensity Gradient of the Image

模糊处理后的图像用一个 Sobel 算子对其在垂直和水平方向计算一阶偏导 $G_x$ 和 $G_y$。通过 $G_x$ 和 $G_y$ 就可以得到图像中每一个像素的梯度及其方向,梯度及其方向计算如下:

梯度方向永远垂直于边,它可以是四个角点之一,分别代表垂直、水平和两条对角线方向。

2.3 Non-maximum Suppression

当得到梯度大小及其方向后,将对整幅图像进行扫描以排除掉那些不会是构成边的像素。为了达到这个目的,在每一个像素都将检查该像素在其梯度方向上是否是局部最大值。

794

点 A 位于垂直方向的边上,其梯度方向垂直于边。点 B 和 C 在点 A 的梯度方向上。如果在点 A、B、C 中,A 为最大值(局部最大值),那么进行下一步。如果不是,则该点被排除(置为0)。

2.4 Hysteresis Thresholding

这一步判断在上一步得出的边界中,哪些是真正的边,哪些不是。为了达到这个目的,需要两个阈值 minVal 和 maxVal。任何梯度值大于 maxVal 的边界都将被当做真正的边,梯度值小于 minVal 的边界都将被忽略。处于 minVal 和 maxVal 之间的边界将根据他是否与真正的边连同来判断。如果其与真正的边相连,那么它将被当做真正的边,如果没有真正的边与之相连,那么它也将被忽略。如下图所示:

1179

边 A 中像素梯度大于 maxVal 的部分是真正的边,边 C 是边 A 中小于 maxVal 的部分,但它与边 A 相连,所以它也当做是真正的边。这样就得到的完整的曲线边界。但是边 B 与边 C 一样位于 minVal 和 maxVal 之间,但是由于它没有真正的边与其相连,所以边 B 将被忽略。因此采用恰当的 minVal 和 maxVal 值对于获取正确的结果十分重要。

由于这一步中假设边是长边,所以该步骤中也能过滤掉一些小的像素噪声。

3. Canny Edge Detection in OpenCV

OpenCV 将上述的所有步骤都封装到了一个函数中,cv2.Canny()。接下来将描述如何使用该函数。

1
2
Python:
edges = cv.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] )

第一个参数 image 是输入的图像,第二个和第三个参数是 minVal 和 maxVal 的值。第四个参数是输出的灰度图像,其与输入图像大小一致,第五个参数是 Sobel 算子的大小,默认是 3。最后一个参数默认为 false,即使用 $norm = |dI/dx| + |dI/dy|$ 来近似计算梯度大小。如果为 true 则使用 $norm = \sqrt{(dI/dx)^2 + (dI/dy)^2}$ 来更加精确的计算梯度大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.ijpg', 0)
edges = cv2.Canny(img, 100, 200)

plt.subplot(121), plt.imshow(img, "gray")
plt.title("Origin Image"), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(edges, "gray")
plt.title("Edgee Image"), plt.xticks([]), plt.yticks([])

plt.imshow()

结果如下:

3560