OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
未找到匹配项
Canny 边缘检测

目标

本章我们将学习:

  • Canny 边缘检测的概念
  • OpenCV的相关函数:cv.Canny()

理论

Canny 边缘检测是一种流行的边缘检测算法。它由 John F. Canny 于…开发。

  1. 它是一个多阶段算法,我们将逐步学习每个阶段。
  2. 噪声抑制

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

  3. 查找图像的强度梯度

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

    \[ 边缘梯度 \; (G) = \sqrt{G_x^2 + G_y^2} \\ 角度 \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) \]

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

  4. 非极大值抑制

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

图像

点 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 核的大小。默认为 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查找图像中的边缘。

请查看下面的结果

图像

补充资源

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

练习

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