OpenCV 4.12.0
开源计算机视觉
加载中...
搜索中...
无匹配项
Canny 边缘检测

目标

在本章中,我们将学习

  • Canny 边缘检测的概念
  • OpenCV 中实现该功能的函数:cv.Canny()

理论

Canny 边缘检测是一种流行的边缘检测算法。它由 John F. Canny 在

  1. 这是一个多阶段算法,我们将逐步了解每个阶段。
  2. 噪声降低

    由于边缘检测容易受到图像中噪声的影响,因此第一步是使用 5x5 高斯滤波器去除图像中的噪声。我们已经在前面的章节中见过这个。

  3. 查找图像的强度梯度

    然后使用 Sobel 算子在水平和垂直方向上对平滑后的图像进行滤波,以获得水平方向(\(G_x\))和垂直方向(\(G_y\))的一阶导数。从这两个图像中,我们可以找到每个像素的边缘梯度和方向,如下所示

    \[ Edge\_Gradient \; (G) = \sqrt{G_x^2 + G_y^2} \\ Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) \]

    梯度方向始终垂直于边缘。它被四舍五入为代表垂直、水平和两个对角线方向的四个角度之一。

  4. 非极大值抑制

    获得梯度幅度和方向后,对图像进行完整扫描,以去除任何可能不构成边缘的无关像素。为此,在每个像素处,检查该像素是否是其梯度方向上邻域中的局部最大值。查看下面的图像

image

点 A 位于边缘上(垂直方向)。梯度方向与边缘垂直。点 B 和 C 位于梯度方向上。因此,检查点 A 与点 B 和 C,以查看它是否形成局部最大值。如果是,则将其考虑用于下一阶段,否则,它将被抑制(设置为零)。

简而言之,您得到的结果是一个带有“细边缘”的二值图像。

  1. 迟滞阈值处理

    此阶段决定哪些边缘是真正的边缘,哪些不是。为此,我们需要两个阈值 minVal 和 maxVal。强度梯度大于 maxVal 的任何边缘肯定是边缘,而低于 minVal 的边缘肯定是非边缘,因此被丢弃。介于这两个阈值之间的边缘根据它们的连通性分类为边缘或非边缘。如果它们连接到“确定边缘”像素,则认为它们是边缘的一部分。否则,它们也会被丢弃。查看下面的图像

image

边缘 A 高于 maxVal,因此被认为是“确定边缘”。虽然边缘 C 低于 maxVal,但它连接到边缘 A,因此也被认为是有效边缘,我们得到了完整的曲线。但是边缘 B 虽然高于 minVal 并且与边缘 C 处于同一区域,但它未连接到任何“确定边缘”,因此被丢弃。因此,我们必须相应地选择 minVal 和 maxVal 才能获得正确的结果,这一点非常重要。

此阶段还消除了小的像素噪声,因为假设边缘是长线。

因此,我们最终得到的是图像中的强边缘。

OpenCV 中的 Canny 边缘检测

OpenCV 将上述所有内容都放在单个函数 cv.Canny() 中。我们将看看如何使用它。第一个参数是我们的输入图像。第二个和第三个参数分别是我们的 minVal 和 maxVal。第四个参数是 aperture_size。它是用于查找图像梯度的 Sobel 核的大小。默认值为 3。最后一个参数是 L2gradient,它指定用于查找梯度幅度的方程。如果为 True,它将使用上面提到的更精确的方程,否则它将使用此函数:\(Edge\_Gradient \; (G) = |G_x| + |G_y|\)。默认情况下,它是 False。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "无法读取文件,请检查 os.path.exists()"
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('原始图像'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('边缘图像'), plt.xticks([]), plt.yticks([])
plt.show()
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件加载图像。
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false)
使用 Canny 算法 canny86 在图像中查找边缘。

请参阅下面的结果

image

补充资源

  1. 维基百科 上的 Canny 边缘检测器
  2. Bill Green 于 2002 年编写的 Canny 边缘检测教程

练习

  1. 编写一个小型应用程序来查找 Canny 边缘检测,其阈值可以使用两个轨迹栏进行更改。这样,您可以了解阈值的影响。