Python利用OpenCV和skimage实现图像边缘检测

七月
七月
发布时间:2026-10-16| 6人浏览过
原创

本文详细介绍如何在Python中使用OpenCV和skimage库进行图像边缘检测。重点解析Canny算法的多步处理流程,包括高斯滤波、梯度计算、非最大抑制及滞后阈值。通过具体代码示例对比两个库的参数配置与实现差异,帮助开发者掌握边缘检测的核心技巧与最佳实践。

一、简介

提取图像边缘信息是数字图像处理的基础任务之一,对后续高层语义信息的提取具有关键影响。尽管大部分经典边缘检测算法诞生于上世纪,OpenCV采用的Canny算法由John F. Canny于1986年提出,标志着该领域研究曾进入瓶颈期。然而,相较于人眼视觉系统,现有算法在复杂场景下的表现仍有提升空间。

Canny算法是一种多步处理流程,能高效检测各类输入图像的边缘。其核心步骤包括:

  • 首先应用高斯滤波平滑图像,以有效去除噪声干扰。
  • 接着计算高斯滤波器的导数,获取图像像素在x和y方向上的梯度值。
  • 随后应用非最大抑制(non-maximum suppression)技术,剔除边缘误检点,确保检测到的边缘尽可能细。
  • 采用双阈值法确定潜在的边界像素,区分强边缘和弱边缘。
  • 最后利用滞后阈值方法,保留梯度幅值高于高阈值的像素,忽略低于低阈值的像素,并通过连接弱边缘实现完整的边缘追踪。

Canny算法旨在寻找最优边缘检测方案,其“最优”定义包含以下三个标准:

  • 最优检测:算法应尽可能多地标识真实边缘,同时最小化漏检真实边缘和误检非边缘的概率。
  • 最优定位:检测到的边缘点位置应尽可能接近实际边缘点,或因噪声导致的偏差最小化。
  • 检测点与边缘点一一对应:算法输出的每个边缘点应对应唯一的实际边缘点,避免重复响应。

为满足上述要求,Canny引入了变分法(calculus of variations)来寻找优化特定功能的函数。最优检测模型由四个指数项表示,可通过高斯函数的一阶导数进行近似计算。

二、opencv 实践

cv2.Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None):
# 用自定义梯度
cv2.Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges
  • image:表示输入的8位图像数据。
  • threshold1:设定的低阈值,用于滞后阈值判断。
  • threshold2:设定的高阈值,用于确定强边缘。
  • edges:输出的边缘图像,为单通道8位图像。
  • apertureSize:指定Sobel算子的孔径大小,默认为3。
  • L2gradient:布尔值,若为True则使用更精确的L2范数计算梯度幅值(即两个方向导数平方和开方),否则使用L1范数(直接相加绝对值)。
def opencv_canny(image):
    # 高斯模糊  降低噪声
    blurred = cv.GaussianBlur(image, (5, 5), 0)
    # 转为灰度图像
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    # 计算x y 方向梯度
    grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
    grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
    edge_output = cv.Canny(grad_x, grad_y,  60, 120)
    # 英文字体   Times New Roman
    plt.rcParams['font.sans-serif'] = ['Times New Roman']

    # 可视化结果
    plt.figure(figsize=(8, 4), dpi=500)
    plt.subplot(121)
    plt.imshow(gray, cmap='gray')
    plt.title('Original Image', fontsize=18)
    plt.xticks([]), plt.yticks([])
    plt.subplot(122)
    plt.imshow(edge_output, cmap='gray')
    plt.title('Edge Image', fontsize=18)
    plt.xticks([]), plt.yticks([])
    plt.savefig("002.png", dpi=500)
    plt.show()


if __name__ == "__main__":
    # 读取图像  传入
    src = cv.imread("Lenna.png")
    opencv_canny(src)

运行上述代码后,可得到如下处理结果:

三、skimage 实践

import numpy as np
from skimage.io import imread
from skimage.feature import canny
import matplotlib.pyplot as plt

# 读取图像
img = imread("Lenna.png", as_gray=True)
# 高斯模糊  降低噪声
img = cv.GaussianBlur(img, (5, 5), 0)

# Canny边缘检测
edges = canny(img, sigma=1.6)

# 可视化结果
plt.rcParams['font.sans-serif'] = ['Times New Roman']
plt.figure(figsize=(8, 4), dpi=500)
plt.subplot(121)
plt.imshow(img, cmap='gray')
plt.title('Original Image', fontsize=18)
plt.xticks([]), plt.yticks([])
plt.subplot(122)
plt.imshow(edges, cmap='gray')
plt.title('Edge Image', fontsize=18)
plt.xticks([]), plt.yticks([])

plt.show()

使用skimage库进行边缘检测的结果如下:

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage import feature


# 产生带有噪声的举行图案
im = np.zeros((128, 128))
im[32:-32, 32:-32] = 1
im = ndi.rotate(im, 15, mode='constant')  # 旋转一定角度
im = ndi.gaussian_filter(im, 4)
im += 0.2 * np.random.random(im.shape)

# Compute the Canny filter for two values of sigma
edges1 = feature.canny(im, sigma=1)
edges2 = feature.canny(im, sigma=3)

# display results
fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=3, figsize=(8, 4),
                                    sharex=True, sharey=True, dpi=500)

ax1.imshow(im, cmap=plt.cm.gray)
ax1.axis('off')
ax1.set_title('Noisy image', fontsize=20)

ax2.imshow(edges1, cmap=plt.cm.gray)
ax2.axis('off')
ax2.set_title(r'Canny filter, $\sigma=1$', fontsize=20)

ax3.imshow(edges2, cmap=plt.cm.gray)
ax3.axis('off')
ax3.set_title(r'Canny filter, $\sigma=3$', fontsize=20)

fig.tight_layout()

plt.show()

调整不同sigma值后的对比结果如下:

skimage库中相关函数参数说明如下:

skimage.feature.canny(image, sigma=1.0,
                      low_threshold=None, high_threshold=None,
                      mask=None, use_quantiles=False)
  • sigma:高斯滤波器的标准差,用于控制平滑程度。
  • low_threshold:Canny算法最后一步中,小于该阈值的像素直接置为0(非边缘)。
  • high_threshold:Canny算法最后一步中,大于该阈值的像素直接置为255(强边缘)。

以上就是Python利用OpenCV和skimage实现图像边缘检测的详细内容,更多关于Python图像边缘检测的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。