OpenCV计算机视觉实战(11)——边缘检测详解

    • 0. 前言
    • 1. Sobel 算子与方向梯度
      • 1.1 Sobel 算子简介
      • 1.2 实现过程
    • 2. Laplacian 边缘检测
      • 2.1 Laplacian 算子简介
      • 2.2 实现过程
    • 3. Canny 算法
      • 3.1 Canny 算法简介
      • 3.2 实现过程
    • 小结
    • 系列链接

0. 前言

边缘检测能够将图像中最关键的轮廓与结构清晰呈现。从一阶梯度的 Sobel 算子,到二阶导数的 Laplacian,再到集平滑、非极大值抑制与双阈值连接于一体的 Canny 算法,三者各有千秋,共同构筑了边缘检测的基石。本节将深入探索 OpenCV 中三大经典边缘检测算子:Sobel 算子、LaplacianCanny 算法,并详细介绍每种方法的实现细节与优化技巧。

1. Sobel 算子与方向梯度

1.1 Sobel 算子简介

Sobel 算子通过对图像执行一阶导数运算,计算水平方向和垂直方向的梯度,从而提取边缘,能同时滤除高频噪声与提取梯度信息。它不仅告诉我们“哪里有边缘”,更指明了“边缘朝哪个方向”——非常适合做纹理分析、特征描述、甚至流场估计的第一步。可以分别获取 Gx ( x 方向梯度)、Gy (y 方向梯度),再合成强度图或直接根据方向信息进行后续处理。

1.2 实现过程

(1) 噪声与纹理权衡:

  • 高斯平滑 (ksize ≈ 5, alpha ≈ 1.0):抑制图像中细小噪声,但会稍微模糊纹理
  • 中值滤波 (cv2.medianBlur):对椒盐噪声更有效,但对细节损伤较小
  • 根据场景选择:工业检测用高斯,中值或双边滤波;医学影像则可考虑更强的噪声抑制

(2) 梯度计算细节:

  • dx=1, dy=0:提取水平方向的亮度变化,突出垂直边
  • dx=0, dy=1:提取垂直方向的亮度变化,突出水平边
  • 卷积核大小 (ksize=3 vs 5):3×3 速度更快,5×5 更平滑

(3) 梯度合成与可视化:

  • 绝对值转换后,不同通道的梯度可做彩色叠加:
    sobel_color = cv2.merge([abs_x, abs_y, np.zeros_like(abs_x)])
    
  • 方向图: theta = arctan2(Gy, Gx) 可绘制 Pseudo-color 方向图,辅助分割
import cv2
import numpy as np# 1. 读取并灰度化
img = cv2.imread('10.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 可选降噪
blur = cv2.GaussianBlur(gray, (5, 5), 1.4)# 2. 计算 Sobel 梯度
# 参数 ksize=3 指定 Sobel 卷积核大小
grad_x = cv2.Sobel(blur, cv2.CV_16S, dx=1, dy=0, ksize=3)
grad_y = cv2.Sobel(blur, cv2.CV_16S, dx=0, dy=1, ksize=3)# 3. 转换为绝对值并归一化
abs_x = cv2.convertScaleAbs(grad_x)
abs_y = cv2.convertScaleAbs(grad_y)
sobel_combined = cv2.addWeighted(abs_x, 0.5, abs_y, 0.5, 0)# 4. 显示结果
cv2.imshow('Original', img)
cv2.imshow('Sobel X', abs_x)
cv2.imshow('Sobel Y', abs_y)
cv2.imshow('Sobel Combined', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()

sobel算子

关键函数解析:

  • cv2.Sobel(src, ddepth, dx, dy, ksize)

    • src:输入图像(建议先降噪)
    • ddepth:输出图像深度,CV_16S 可避免溢出后再转换
    • dx, dy:分别指定求导的方向
    • ksizeSobel 卷积核大小(常用 35)
  • cv2.convertScaleAbs(src):将带符号图像转换为无符号 8 位图像,并计算绝对值,便于后续可视化

  • cv2.addWeighted(src1, alpha, src2, beta, gamma):对两幅图像按权重线性叠加,dst = src1*alpha + src2*beta + gamma,常用于合成 xy 梯度

2. Laplacian 边缘检测

2.1 Laplacian 算子简介

Laplacian 算子基于二阶导数,对亮度突变更为敏感,通过对图像应用 Laplacian 卷积核,能够在一次操作中同时获得所有方向的边缘,并且通过零交叉 (zero-crossing) 定位精确的边界。但由于二阶导数对噪声非常敏感,通常需要先进行平滑再做检测。

2.2 实现过程

(1) 高阶平滑:

  • LoG (Laplacian of Gaussian):先高斯再 Laplacian,可直接调用 cv2.GaussianBlur + cv2.Laplacian
  • 也可用 cv2.filter2D 自定义 LoG 卷积核,一步到位

(2) 零交叉检测:

  • lap 图中,像素值符号变化(正→负)即为边缘
  • 可通过扫描 3×3 邻域,判断中心像素与邻居异号来定位“零交叉点”

(3) 阈值筛选与细化:

  • 首次检测后,用 cv2.threshold 去除微弱响应
  • 再做形态学细化 (cv2.ximgproc.thinning) 得到单像素宽度边缘
import cv2
import numpy as np# 1. 读取与 LoG 平滑
img = cv2.imread('10.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur_log = cv2.GaussianBlur(gray, (7, 7), sigmaX=2)
lap = cv2.Laplacian(blur_log, cv2.CV_16S, ksize=3)
lap_abs = cv2.convertScaleAbs(lap)# 2. 零交叉检测(简易实现)
zero_cross = np.zeros_like(lap, dtype=np.uint8)
for y in range(1, lap.shape[0]-1):for x in range(1, lap.shape[1]-1):patch = lap[y-1:y+2, x-1:x+2]if np.min(patch) < 0 < np.max(patch):zero_cross[y, x] = 255# 3. 细化边缘
thinned = cv2.ximgproc.thinning(zero_cross)# 4. 显示
cv2.imshow('Laplacian', lap_abs)
cv2.imshow('Zero Crossing', zero_cross)
cv2.imshow('Thinned Edges', thinned)
cv2.waitKey(0)
cv2.destroyAllWindows()

laplacian

关键函数解析:

  • cv2.Laplacian(src, ddepth, ksize):计算二阶导数,ksize 越大,对噪声抑制越好但细节越模糊
  • 零交叉:检测符号变化来定位精确边缘点,是 LoG 方法的经典后处理
  • cv2.ximgproc.thinning(src):细化算法,将二值边缘收敛为单像素宽度

3. Canny 算法

3.1 Canny 算法简介

Canny 算法集平滑、梯度、非极大值抑制与双阈值连接于一体,是产业、科研常用的边缘检测算法。合理调参与后处理,能在保持细节的同时,极大抑制噪声与伪边缘。

3.2 实现过程

(1) 高斯平滑:

  • 使用 cv2.GaussianBlur,核大小与 sigma 需配合调整:
  • 较大核与 sigma:去噪更多,但细节丢失
  • 较小核与 sigma:保留细节,但噪声多

(2) 非极大值抑制 (Non-Maximum Suppression, NMS) 剖析:

  • Canny 内部已实现,但了解其原理有助于后续定制:
    • 根据梯度方向,将像素与梯度方向上的两个邻居比较
    • 保留局部最大值,抑制非极大响应
  • 可自定义 NMS,加入方向高精度分桶 ( 8 个方向),进一步细化

(3) 双阈值与边缘连接:

  • threshold1 (低阈值) 与 threshold2 (高阈值)
  • 一般建议 threshold2 ≈ 2~3 × threshold1

(4) (可选)自适应阈值:

  • 可先计算图像梯度的全局统计量,再动态设置低高阈值
  • 或根据图像直方图 Otsu 自动选阈,再衍生双阈值
import cv2# 1. 读取并灰度化
img = cv2.imread('input.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 2. Gaussian 平滑
blur = cv2.GaussianBlur(gray, (5, 5), 1.4)# 3. Canny 边缘检测
low_thresh = 50
high_thresh = 150
edges = cv2.Canny(blur, low_thresh, high_thresh, apertureSize=3, L2gradient=True)# 4. 显示结果
cv2.imshow('Original', img)
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

关键函数解析:

  • cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradient)
    • threshold1:较低阈值,用于连接边缘
    • threshold2:较高阈值,定义强边缘
    • apertureSizeSobel 卷积核大小,常用 3
    • L2gradient=True:使用更精确的欧氏梯度 ( ( d x 2 + d y 2 ) \sqrt {(dx²+dy²)} (dx2+dy2) ) 替代 L1 范数

小结

在本节中,我们系统介绍了三大经典边缘检测算子,包括 Sobel 算子:一阶导数平衡了噪声抑制与边缘提取,结合方向信息可用于纹理分析与车道检测;Laplacian 算子:二阶导数对微小亮度突变尤为敏感,配合零交叉和细化技术,可精确捕捉任意方向的细节边缘;Canny 算法:集成多阶段处理与双阈值策略,通过多尺度融合与自适应阈值优化,达到抗噪与细节兼顾的卓越效果。

系列链接

OpenCV计算机视觉实战(1)——计算机视觉简介
OpenCV计算机视觉实战(2)——环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)——计算机图像处理基础
OpenCV计算机视觉实战(4)——计算机视觉核心技术全解析
OpenCV计算机视觉实战(5)——图像基础操作全解析
OpenCV计算机视觉实战(6)——经典计算机视觉算法
OpenCV计算机视觉实战(7)——色彩空间详解
OpenCV计算机视觉实战(8)——图像滤波详解
OpenCV计算机视觉实战(9)——阈值化技术详解
OpenCV计算机视觉实战(10)——形态学操作详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86118.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86118.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/86118.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

哈尔滨idc服务器租用-青蛙云

在数字化浪潮汹涌的当下&#xff0c;企业对于服务器的需求愈发强烈。哈尔滨作为东北地区重要的经济文化中心&#xff0c;其 IDC 服务器租用市场也呈现出蓬勃发展的态势。众多企业在寻求 IDC 服务器租用时&#xff0c;青蛙云凭借自身显著优势脱颖而出&#xff0c;成为众多用户的…

Zephyr 系统深入解析:SoC 支持包结构与中断调度器调优实践

本文将全面深入讲解 Zephyr RTOS 的 SoC 支持包设计架构&#xff08;SoC Series / SoC Variant&#xff09;、中断系统实现、调度器原理、时间片与优先级调优技巧&#xff0c;以及如何在实际项目中构建自定义 SoC 支持包、实现高效的调度器策略和系统性能优化。全文超过 5000 字…

FPGA基础 -- Verilog 结构建模之模块参数值

Verilog 中模块参数值&#xff08;parameter&#xff09;的使用&#xff0c;这是结构建模和模块可配置设计的核心机制&#xff0c;广泛应用于 总线宽度配置、流水线级数、功能开关、模块复用 等场景。 一、什么是模块参数值&#xff08;parameter&#xff09; parameter 是 Ver…

Skrill是什么?中国用户能用吗?安全吗?完整指南

什么是Skrill&#xff1f; Skrill 前身为 Moneybookers&#xff0c;成立于 2001 年&#xff0c;总部位于英国伦敦&#xff0c;目前隶属于 Paysafe 集团。作为一个多功能电子支付平台&#xff0c;Skrill 支持全球 100 多个国家和地区、40 多种货币&#xff0c;被广泛用于&#…

java+vue+SpringBoo校园部门资料管理系统(程序+数据库+报告+部署教程+答辩指导)

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿ppt部署教程代码讲解代码时间修改工具 技术实现 开发语言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot数据库&#xff1a;mysql 开发工具 JDK版本&#xff1a;JDK1.…

Java中的Map实现类详解

Java中的Map实现类详解 Java集合框架提供了多种Map接口的实现&#xff0c;每种实现都有其特定的使用场景和特点。以下是主要的Map实现类及其特性分析&#xff1a; 1. 通用Map实现 HashMap 特点&#xff1a;基于哈希表的实现&#xff0c;允许null键和null值线程安全&#xf…

Pytorch Lightning 进阶 1 - 梯度检查点(Gradient Checkpointing)

梯度检查点&#xff08;Gradient Checkpointing&#xff09;是一种在深度学习训练中优化显存使用的技术&#xff0c;尤其适用于处理大型模型&#xff08;如Transformer架构&#xff09;时显存不足的情况。下面用简单的例子解释其工作原理和优缺点&#xff1a; 核心原理 深度学…

SpreadJS 迷你图:数据趋势可视化的利器

引言 在数据处理和分析领域&#xff0c;直观地展示数据趋势对于理解数据和做出决策至关重要。迷你图作为一种简洁而有效的数据可视化方式&#xff0c;在显示数据趋势方面发挥着重要作用&#xff0c;尤其在与他人共享数据时&#xff0c;能够快速传达关键信息。SpreadJS 作为一款…

GESP2024年12月认证C++一级( 第三部分编程题(1)温度转换)

参考程序1&#xff1a; #include <cstdio> using namespace std;int main() {double K;scanf("%lf", &K);double C K - 273.15; //转换为摄氏温度 double F 32 C * 1.8; //转换为华氏温度 if (F > 212) //条件判断 print…

从零开始手写redis(18)缓存淘汰算法 FIFO 优化

项目简介 大家好&#xff0c;我是老马。 Cache 用于实现一个可拓展的高性能本地缓存。 有人的地方&#xff0c;就有江湖。有高性能的地方&#xff0c;就有 cache。 v1.0.0 版本 以前的 FIFO 实现比较简单&#xff0c;但是 queue 循环一遍删除的话&#xff0c;性能实在是太…

用Zynq实现脉冲多普勒雷达信号处理:架构、算法与实现详解

用Zynq实现脉冲多普勒雷达信号处理:架构、算法与实现详解 脉冲多普勒(PD)雷达是现代雷达系统的核心技术之一,广泛应用于机载火控、气象监测、交通监控等领域。其核心优势在于能在强杂波背景下检测运动目标,并精确测量其径向速度。本文将深入探讨如何利用Xilinx Zynq SoC(…

OpenCV CUDA模块设备层-----线程块级别的一个内存填充工具函数blockFill()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在同一个线程块&#xff08;thread block&#xff09;内&#xff0c;将 [beg, end) 范围内的数据并行地填充为指定值 value。 它使用了 CUDA 线程…

SAP-ABAP:如何查询 SAP 事务码(T-Code)被包含在哪些权限角色或权限对象中

要查询 SAP 事务码&#xff08;T-Code&#xff09;被包含在哪些权限角色或权限对象中&#xff0c;可使用以下专业方法&#xff1a; &#x1f50d; 1. 通过权限浏览器 (SUIM) - 最推荐 事务码&#xff1a;SUIM (权限信息系统) 操作步骤&#xff1a; 执行 SUIM → 选择 “角色…

MySQL 多列 IN 查询详解:语法、性能与实战技巧

在 MySQL 中&#xff0c;多列 IN 查询是一种强大的筛选工具&#xff0c;它允许通过多字段组合快速过滤数据。相较于传统的 OR 连接多个条件&#xff0c;这种语法更简洁高效&#xff0c;尤其适合批量匹配复合键或联合字段的场景。本文将深入解析其用法&#xff0c;并探讨性能优化…

自由学习记录(63)

编码全称&#xff1a;AV1&#xff08;Alliance for Open Media Video 1&#xff09;。 算力消耗大&#xff1a;目前&#xff08;截至 2025 年中&#xff09;软件解码 AV1 的 CPU 开销非常高&#xff0c;如果没有专门的硬件解码单元&#xff0c;播放高清视频时会很吃 CPU&#…

日本生活:日语语言学校-日语作文-沟通无国界(4)-题目:喜欢读书

日本生活&#xff1a;日语语言学校-日语作文-沟通无国界&#xff08;4&#xff09;-题目&#xff1a;喜欢读书 1-前言2-作文原稿3-作文日语和译本&#xff08;1&#xff09;日文原文&#xff08;2&#xff09;对应中文&#xff08;3&#xff09;对应英文 4-老师评语5-自我感想&…

C++优化程序的Tips

转自个人博客 1. 避免创建过多中间变量 过多的中间变量不利于代码的可读性&#xff0c;还会增加内存的使用&#xff0c;而且可能导致额外的计算开销。 将用于同一种情况的变量统一管理&#xff0c;可以使用一种通用的变量来代替多个变量。 2. 函数中习惯使用引用传参而不是返…

C#Blazor应用-跨平台WEB开发VB.NET

在 C# 中实现 Blazor 应用需要结合 Razor 语法和 C# 代码&#xff0c;Blazor 允许使用 C# 同时开发前端和后端逻辑。以下是一个完整的 C# Blazor 实现示例&#xff0c;包含项目创建、基础组件和数据交互等内容&#xff1a; 一、创建 Blazor 项目 使用 Visual Studio 新建项目 …

前端的安全隐患之API恶意调用

永远不要相信前端传来的数据&#xff0c;对于资深开发者而言&#xff0c;这几乎是一种本能&#xff0c;无需过多解释。然而&#xff0c;初入职场的开发新手可能会感到困惑&#xff1a;为何要对前端传来的数据持有如此不信任的态度&#xff1f;难道人与人之间连基本的信任都不存…

基于 Spark 实现 COS 海量数据处理

上周在组内分享了一下这个主题&#xff0c; 我觉得还是摘出一部分当文章输出出来 分享主要包括三个方面&#xff1a; 1. 项目背景 2.Spark 原理 3. Spark 实战 项目背景 主要是将海量日志进行多维度处理&#xff1b; 项目难点 1、数据量大&#xff08;压缩包数量 6TB,60 亿条数…