代码是AI辅助生成。
边缘检测是一种图像处理技术,用于识别图像中物体或区域的边界(边缘)。OpenCV提供了多种经典的边缘检测算法实现,广泛应用于图像处理、目标识别、特征提取等任务。
本文只是一个简单的学习笔记,请读者用不同的图像、参数进行试验,亲自感受。
1、边缘是如何被检测出来的?
像素强度的突然变化是边缘的特征,在相邻像素中寻找这种变化来检测边缘。
本文主要列出两种重要的边缘检测算法:
- Canny 边缘检测
- Sobel 边缘检测
2、Canny 边缘检测
Canny 边缘检测算法 是由 John F. Canny 在 1986 年提出的一种多阶段边缘检测算法,是计算机视觉中最经典、最常用的边缘检测算法之一。
Canny算法包含5个关键步骤:
- 高斯滤波去噪
- 计算梯度幅值和方向
- 非极大值抑制
- 双阈值检测
- 滞后边缘跟踪
2.1 cv2.Canny() 函数
cv2.Canny() 是 OpenCV 中用于执行 Canny 边缘检测 的核心函数,能够从图像中提取出清晰、连续的边缘轮廓。
函数定义
edges = cv2.Canny(image, threshold1, threshold2, apertureSize=None, L2gradient=None)
-
返回值
返回一个 二值图像(NumPy 数组)
像素值
255表示检测到的边缘点,0表示非边缘点 -
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| image | NumPy 数组 | 输入图像,灰度图(Grayscale)。如果是彩色图用 cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 转换 |
| threshold1 | float | 低阈值,用于弱边缘检测 |
| threshold2 | float | 高阈值,用于强边缘检测,必须大于 threshold1。强梯度超过此值才被认为是"真实边缘" |
| pertureSize | int (可选) | Sobel 算子的孔径大小,用于计算图像梯度。默认为 3,可选 3~7 的奇数 |
| L2gradient | bool (可选) | 是否使用更精确的 L2 范数计算梯度幅值 |
2.2 代码示例
import cv2
import numpy as np
# 1.读取图像并转为灰度图
img = cv2.imread('img/dog.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2.应用 Canny 边缘检测
canny = cv2.Canny(gray, threshold1=50, threshold2=150, apertureSize=3, L2gradient=False)
# 显示结果
cv2.imshow('Canny Edge Detection', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

3、Sobel 边缘检测
Sobel 边缘检测是一种经典的基于梯度的图像边缘检测方法,广泛应用于计算机视觉和图像处理领域。它通过计算图像在水平和垂直方向上的梯度来检测边缘。
Sobel 算子能够检测出由像素强度突然变化所形成的边缘。Sobel就是通过一个"卷积核"在图像上滑动,计算:"中心像素与其周围像素在水平和垂直方向上,灰度值变化得有多剧烈?" 变化剧烈的地方,就被标记为边缘。
3.1 cv2.Sobel() 函数
cv2.Sobel() 是 OpenCV 中用于图像梯度计算的函数,常用于边缘检测。它通过卷积操作计算图像在 x 方向(水平) 和/或 y 方向(垂直) 的梯度,从而突出灰度变化剧烈的区域。
函数定义
dst = cv2.Sobel(src, ddepth, dx, dy, ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
- 返回值
dst:输出图像,与输入图像尺寸相同。
| 参数 | 类型 | 说明 |
|---|---|---|
| src | NumPy 数组 | 输入图像,灰度图 |
| ddepth | int(输出图像深度) | 输出图像的数据深度,常用值 cv2.CV_8U cv2.CV_16S cv2.CV_32F cv2.CV_64F |
| dx | int | x 方向导数阶数(0 或 1) dx=1 表示检测垂直边缘(左右变化);dx=0 不启用 |
| dy | int | y 方向导数阶数(0 或 1) dy=1 表示检测水平边缘(上下变化);dy=0 不启用 |
| ksize | int(可选) | Sobel 核大小,默认为 3 必须是大于 1 的奇数(3, 5, 7...) 更大的值会增强抗噪能力但可能模糊边缘 |
| scale | float(可选) | 缩放因子,卷积结果乘以此值,默认为 1 |
| delta | float(可选) | 加到结果中的偏移量,默认为 0 |
| borderType | int(可选) | 边界填充方式 cv2.BORDER_REFLECT cv2.BORDER_REPLICATE cv2.BORDER_CONSTANT |
3.2 代码示例
python
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像并转为灰度图
img = cv2.imread('img/dog.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 计算 x 方向梯度(垂直边缘)
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobel_x = np.uint8(np.absolute(sobel_x))
# 计算 y 方向梯度(水平边缘)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
sobel_y = np.uint8(np.absolute(sobel_y))
# 合成总梯度幅值(L1 范数)
sobel_combined = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
# 显示结果
titles = ['Original', 'Sobel X', 'Sobel Y', 'Sobel Combined']
images = [gray, sobel_x, sobel_y, sobel_combined]
for i in range(4):
plt.subplot(2, 2, i+1), plt.imshow(images[i], cmap='gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
