Python OpenCV实现边缘检测

江屿
江屿
发布时间:2026-10-14 | 5人浏览过
原创

本文详细介绍Python中使用OpenCV进行边缘检测的三种核心算法:Sobel、Laplacian和Canny。内容涵盖Sobel算子的梯度计算与Scharr优化、Laplacian二阶导数检测,以及Canny算法的去噪、梯度计算、非极大值抑制和滞后阈值四个步骤。通过具体代码示例展示各函数的参数设置与实现效果,帮助开发者掌握不同场景下的边缘检测技巧。

本文分享利用Python和OpenCV库进行图像边缘检测的具体实现方法,供读者参考学习。

1. Sobel 算子检测

Sobel算子结合了高斯平滑与微分运算,具备较强的抗噪能力,应用场景广泛。特别是在对处理效率要求较高,且对细微纹理细节不敏感的场景下,该算法表现优异。

针对不连续函数,其数学表达如下:

假设待处理图像为I,需在两个正交方向上进行求导运算。

水平方向变化:使用奇数大小的卷积模板对图像I进行卷积运算,得到结果Gx。例如,当模板尺寸设定为3时,Gx的计算方式为:

垂直方向变化:同样使用奇数大小的卷积模板对图像I进行卷积运算,得到结果Gy。例如,当模板尺寸设定为3时,Gy的计算方式为:

在图像的每个像素点,综合上述两个方向的结果,计算得到:

梯度幅值的极大值位置即对应图像的边缘区域。

当卷积核大小为3时,Sobel算子可能产生较明显的误差。为解决此问题,可采用Scharr函数。该函数仅适用于大小为3的核,运算速度与Sobel相当,但精度更高。其计算方法为:

cv.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType) 参数说明: src:输入图像 ddepth:输出图像的深度 dx、dy:求导的阶数,0表示该方向不求导,取值范围为0或1。 ksize:Sobel算子的卷积核大小,必须为奇数(1、3、5、7),默认值为3。若设为-1,则代表使用3x3的Scharr算子。 scale:缩放导数的比例常数,默认无缩放。 borderType:图像边界填充模式,默认值为cv.BORDER_DEFAULT。

需分别对x和y两个方向调用cv.Sobel()函数。随后,对每个方向的输出调用cv.convertScaleAbs()函数将其转换为uint8格式,最后通过cv2.addWeighted()函数将两个方向的结果加权组合。

2. Laplacian 算子检测

Laplacian算子利用二阶导数来检测图像边缘。由于图像是二维的,需从两个方向进行求导:

不连续函数的二阶导数表达式为:

所使用的卷积核模板为:

cv.Laplacian(src, ddepth, ksize) 参数说明: src:待处理的图像 ddepth:输出图像的深度,-1表示与原图像深度一致,目标图像深度必须大于等于原图像深度。 ksize:算子的卷积核大小,必须为1、3、5或7。

对Laplacian函数的返回值调用cv.convertScaleAbs(res),即可获得最终边缘图像。

3. Canny 边缘检测

Canny边缘检测算法主要包含以下四个步骤:

1)去噪处理。由于边缘检测易受噪声干扰,首先使用5*5的高斯滤波器对图像进行去噪。

2)计算图像梯度。在平滑后的图像上使用Sobel算子计算水平和垂直方向的一阶导数(Gx和Gy)。根据这两个梯度图,计算边缘的梯度幅值和方向,公式如下:

若某像素点属于边缘,其梯度方向必然垂直于边缘走向。梯度方向通常分为四类:垂直、水平以及两个对角线方向。

3)非极大值抑制。在获取梯度的方向和大小后,扫描整个图像以排除非边界点。检查每个像素点,判断该点的梯度值是否在其梯度方向上的相邻点中为最大值。

如图所示,A点位于图像边缘。在其梯度变化方向上选取像素B和C,检查A点的梯度是否为极大值。若为极大值则保留,否则抑制该点。最终得到的结果是细化的二值边缘图像。

4)滞后阈值处理。此步骤用于确定真正的边缘。设定两个阈值:minVal(低阈值)和maxVal(高阈值)。若图像灰度梯度高于maxVal,则视为真实边缘;低于minVal的边缘将被丢弃。若梯度值介于两者之间,则判断该点是否与已确定的真实边缘点相连。若相连,则视为边缘点;否则丢弃。较低的minVal有助于连接间断边缘,较高的maxVal用于检测显著边缘。具体过程如下图所示:

A点灰度梯度高于maxVal,因此确认为真实边缘点。C点虽低于maxVal但高于minVal,且与A点相连,故也被视为真实边缘点。B点因低于maxVal且未与真实边缘点相连,将被丢弃。因此,合理选择maxVal和minVal对获得理想检测效果至关重要。

cv.Canny(image, threshold1, threshold2) 参数说明: image:输入的灰度图像 threshold1:minVal,较低阈值 threshold2:maxVal,较高阈值

示例:分别使用Sobel、Laplacian和Canny算法对下图进行边缘检测。


import matplotlib
import cv2 as cv
import matplotlib.pyplot as plt
 
font = {
    "family": "Microsoft YaHei"
}
matplotlib.rc("font", **font)
 
img = cv.imread("./image/horse.jpg", 0)
 
# Sobel
x = cv.Sobel(img, cv.CV_16S, 1, 0)
y = cv.Sobel(img, cv.CV_16S, 0, 1)
absx = cv.convertScaleAbs(x)
absy = cv.convertScaleAbs(y)
res = cv.addWeighted(absx, 0.5, absy, 0.5, 0)
plt.imshow(res, cmap=plt.cm.gray)
plt.title("Sobel")
plt.show()
 
# Schaar
x = cv.Sobel(img, cv.CV_16S, 1, 0, ksize=-1)
y = cv.Sobel(img, cv.CV_16S, 0, 1, ksize=-1)
absx = cv.convertScaleAbs(x)
absy = cv.convertScaleAbs(y)
res = cv.addWeighted(absx, 0.5, absy, 0.5, 0)
plt.imshow(res, cmap=plt.cm.gray)
plt.title("Schaar")
plt.show()
 
# Laplacian
res = cv.Laplacian(img, cv.CV_16S)
res = cv.convertScaleAbs(res)
plt.imshow(res, cmap=plt.cm.gray)
plt.title("Laplacian")
plt.show()
 
# Canny
res = cv.Canny(img, 0, 100)
plt.imshow(res, cmap=plt.cm.gray)
plt.title("Canny")
plt.show()

运行输出结果:

以上内容为本文的全部介绍,希望能为读者的学习与工作提供有益帮助,欢迎继续支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表