当前位置: 首页 > news >正文

计算机视觉(十一):边缘检测Canny

Canny 边缘检测的原理

Canny 算法由 John F. Canny 在 1986 年提出,其设计理念是寻找一个最优的边缘检测器,其核心思想可以概括为以下三个准则:

  1. 低错误率:尽可能多地检测出真实的边缘,同时减少错误地检测到非边缘的情况。
  2. 高定位精度:检测到的边缘点应该尽可能准确地靠近真实边缘的中心位置。
  3. 单边缘响应:对于一个真实的边缘,算法只应给出一个响应,避免检测到多个重叠的边缘。

为了实现这三个准则,Canny 算法分五步执行:

第一步:高斯模糊(Gaussian Blurring)

在进行任何边缘检测之前,首先要对图像进行平滑处理,以去除噪声。Canny 算法使用高斯滤波器来平滑图像。高斯滤波是一种加权平均,它使用一个高斯函数来定义权重,中心点的权重最大,离中心越远的像素权重越小。这一步的目的是确保后续的梯度计算不会被图像中的随机噪声所干扰。

第二步:计算梯度幅值和方向(Gradient Magnitude and Direction)

平滑后的图像会进行梯度计算。梯度可以理解为像素值在水平和垂直方向上的变化率。梯度幅值表示该点像素变化的剧烈程度,即“边缘的强度”,而梯度方向则表示变化的方向。

Canny 算法通常使用 Sobel 算子来计算图像在 x 和 y 方向的梯度 (G_x 和 G_y)。

  • 梯度幅值 (Magnitude):G =

    在这里插入图片描述

  • 梯度方向 (Direction)

    在这里插入图片描述

梯度幅值越大,表示该点的边缘越强。

第三步:非极大值抑制(Non-maximum Suppression)

这一步是 Canny 算法的关键。在计算出梯度幅值后,我们得到的是许多“粗糙”的边缘,其中一个真实的边缘可能对应了多个像素点。非极大值抑制的目标是将这些粗糙的边缘“细化”为单一的像素宽

算法会遍历所有像素点,并检查该点的梯度幅值是否在其梯度方向上的邻域内达到最大。如果不是,就将该点视为非边缘点并将其幅值设为零。例如,如果一个点的梯度方向是水平的,算法会比较它与左边和右边邻点的梯度幅值,如果它不是最大的,则它不是真正的边缘点。通过这个过程,我们能够消除许多由于梯度值高但并非边缘中心而产生的假边缘。

第四步:双阈值处理(Double Thresholding)

非极大值抑制后,图像中仍然存在许多边缘,有些是真实的,有些可能是噪声。Canny 算法使用两个阈值(高阈值 high_threshold 和低阈值 low_threshold)来区分它们。

  • 强边缘(Strong Edges):梯度幅值大于 high_threshold 的像素点被立即标记为边缘。
  • 弱边缘(Weak Edges):梯度幅值介于 low_thresholdhigh_threshold 之间的像素点被标记为潜在的边缘。
  • 非边缘(Non-edges):梯度幅值小于 low_threshold 的像素点被直接丢弃。

这个步骤有效地将所有边缘分成了三类,为下一步的边缘连接做准备。

第五步:边缘连接(Hysteresis Thresholding)

这一步的目标是将弱边缘点连接到强边缘上。算法会遍历所有的弱边缘点,如果某个弱边缘点与任何一个强边缘点是相邻的,那么它也会被视为一个真实的边缘。这种方法可以有效地保留那些因噪声等原因导致梯度值稍低的真实边缘,同时丢弃那些孤立的、可能是噪声引起的弱边缘点。

最终,所有被标记为强边缘或通过连接保留的弱边缘,就构成了最终的边缘图像。

OpenCV 中的 Canny 边缘检测

核心函数

edges = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

参数详解:

1. image

  • 类型: numpy.ndarray
  • 说明: 这是输入图像。Canny 算法通常在单通道的灰度图像上效果最好。如果你传入彩色图像,函数内部会先将其转换为灰度图。为了获得更好的控制和性能,建议在调用 Canny() 之前手动将图像转换为灰度。

2. threshold1 (低阈值)

  • 类型: intfloat
  • 说明: 这是 Canny 算法中双阈值处理低阈值。任何梯度幅值小于这个值的像素点都会被立即丢弃,不被认为是边缘。

3. threshold2 (高阈值)

  • 类型: intfloat
  • 说明: 这是 Canny 算法中双阈值处理高阈值。任何梯度幅值大于这个值的像素点都会被立即标记为强边缘

threshold1threshold2 之间的关系是 Canny 算法的关键:

  • 梯度幅值大于 threshold2 的点是强边缘。
  • 梯度幅值在 threshold1threshold2 之间的点是弱边缘。
  • 梯度幅值小于 threshold1 的点被丢弃。

弱边缘点只有在与强边缘点相连时才会被保留。这个机制(滞后阈值)使得 Canny 算法能够保留真实的边缘,同时有效地过滤掉噪声。

如何选择这两个阈值?

  • 一个常见的经验法则是将 high_threshold 设置为 low_threshold 的 2 到 3 倍。例如,(50, 150)(100, 200)
  • 如果阈值设置得太高,你可能会错过一些真实的微弱边缘。
  • 如果阈值设置得太低,你可能会得到太多由噪声引起的边缘。
  • 对于不同的图像,这两个值的最佳选择会有所不同,通常需要通过实验来确定。

可选参数详解

4. apertureSize

  • 类型: int
  • 说明: 这是 Sobel 算子的孔径大小。它用于计算图像梯度。这个值必须是奇数,并且在 [3, 5, 7] 之间。默认值为 3
  • apertureSize 越大,Sobel 算子的核就越大,它所计算的梯度会更平滑,对噪声的抵抗能力也更强,但可能会牺牲一些边缘的细节。

5. L2gradient

  • 类型: bool
  • 说明: 这是一个布尔标志,用于指定计算梯度幅值的方式。
  • 如果设置为 True,梯度幅值使用更精确的 L2 范数(欧几里得距离)计算: G=sqrtG_x2+G_y2
  • 如果设置为 False(默认值),梯度幅值使用更快的 L1 范数计算: G=∣G_x∣+∣G_y∣
  • L2 范数计算更准确,但计算速度稍慢。通常情况下,L1 范数已经足够好,所以默认是 False

示例

import cv2
import numpy as np# 1. 加载图像
image = cv2.imread('Lenna.png')if image is None:print("错误:无法读取图像。")exit()# 2. 将图像转换为灰度图(Canny通常在灰度图上操作)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 3. 执行Canny边缘检测
# Canny函数需要三个参数:灰度图像,低阈值,高阈值
# 这里的 50 和 150 是常用的经验值,可以根据图像特性调整
edges = cv2.Canny(gray_image, 50, 150)# 4. 显示结果
cv2.imshow('Original Image', image)
cv2.imshow('Canny Edges', edges)cv2.waitKey(0)
cv2.destroyAllWindows()

执行效果:
在这里插入图片描述


文章转载自:

http://xXnzMjK8.kLLtg.cn
http://p3v7ouVs.kLLtg.cn
http://TlJ4kwGE.kLLtg.cn
http://D4jL2Itz.kLLtg.cn
http://UOczFW6M.kLLtg.cn
http://yQ1qM4MA.kLLtg.cn
http://d1PVjaDa.kLLtg.cn
http://5LqfO9r1.kLLtg.cn
http://T6kKiRhe.kLLtg.cn
http://xzHttvMz.kLLtg.cn
http://H2fSGdzy.kLLtg.cn
http://xoz4dTIh.kLLtg.cn
http://nwaVOMXx.kLLtg.cn
http://YB2LT0i3.kLLtg.cn
http://Hblc2J2E.kLLtg.cn
http://Og5rRM0b.kLLtg.cn
http://qgbrzPhq.kLLtg.cn
http://onofoxZl.kLLtg.cn
http://AGKGJB12.kLLtg.cn
http://vxWzJBqf.kLLtg.cn
http://NfWwQ6Q7.kLLtg.cn
http://uEaGeKz8.kLLtg.cn
http://wEW3xlsC.kLLtg.cn
http://OvwFlxTu.kLLtg.cn
http://pDhtXBGg.kLLtg.cn
http://wt6yYZZM.kLLtg.cn
http://o80YB8ow.kLLtg.cn
http://fjhDwv0x.kLLtg.cn
http://vTCgOMwe.kLLtg.cn
http://yGQJXbSb.kLLtg.cn
http://www.dtcms.com/a/372480.html

相关文章:

  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘wheel’问题
  • 监控系统 | 脚本案例
  • TI-92 Plus计算器:高等数学之函数特性判断
  • IDEA 配置tomcat服务器
  • HTTP中Payload的含义解析
  • docker-compose build命令及参数
  • 接入第三方升级协议OTA教程
  • IO模型多路转接
  • Python-基础语法
  • FastApi框架
  • 单片机的bin、exe、elf、hex文件差异
  • 基于ResNet50的智能垃圾分类系统
  • 大模型推理参数讲解
  • Linux 性能调优之 OOM Killer 的认知与观测
  • Linux->日志的实现
  • 西门子 S7-200 SMART PLC :3 台电机顺启逆停控制(上篇)
  • SAP系统两种部署方式:公有云VS私有云 企业如何选择?
  • 用博图FB类比c#中sdk的api
  • 8.渗透-.虚拟机安装
  • Redis基础(含常用命令等以快速入门)
  • 做T投资学:从入门到精通
  • 特征平台学习总结
  • 每天五分钟深度学习:前向算损失,反向算梯度,梯度下降更新参数
  • 淘宝商品详情高级版(item_get_pro)调用详解
  • python进程,线程与协程
  • [特殊字符] 基于Qwen Coder的上下文工程编程框架,为AI辅助开发提供标准化流程
  • 升级PyCharm后,解释器配置正确、模块安装正确,但脚本就是找不到
  • 实现自己的AI视频监控系统-第四章-基于langchain的AI大模型与智能体应用1
  • 155. 最小栈
  • 【开题答辩全过程】以 基于微信小程序校园综合服务平台的设计与实现为例,包含答辩的问题和答案