OpenCV中的边缘检测

边缘检测是图像处理和计算机视觉中的关键技术之一,旨在识别图像中像素强度发生显著变化的区域,这些区域通常对应于物体的边界或轮廓。边缘检测在机器视觉中具有重要的需求背景,主要体现在以下几个方面:

  1. 图像分割:边缘检测可以帮助将图像分割成不同的区域,便于后续的图像分析和处理。
  2. 物体识别:通过检测物体的边缘,可以提取物体的特征,为物体识别提供基础。
  3. 图像增强:边缘检测可以增强图像中的重要特征,提高图像的清晰度和质量。
  4. 三维重建:在三维重建中,边缘检测可以帮助确定物体的形状和结构。

1.1.2. 应用场景

边缘检测在机器视觉中有着广泛的应用场景,包括但不限于以下几个方面:

  1. 工业检测:用于检测产品表面的缺陷,如裂纹、划痕、凹陷等。
  2. 自动驾驶:用于检测道路、交通标志、车辆和行人等物体的轮廓,辅助自动驾驶系统进行决策。
  3. 医学图像分析:用于识别医学图像中的器官、病变和组织边界,辅助医生进行诊断。
  4. 安防监控:用于检测视频中的异常行为或物体,提高监控系统的智能化水平。
  5. 机器人视觉:用于识别环境中的物体和障碍物,帮助机器人进行导航和避障。

1.2. OpenCV中的实现方法

OpenCV提供了多种边缘检测方法,常用的包括:

  1. Canny 边缘检测
  2. Sobel 算子
  3. Laplacian 算子

1.2.1. Canny 边缘检测

原理及内部流程: Canny 边缘检测是一种多阶段的边缘检测算法,主要包括以下步骤:

  1. 噪声抑制:使用高斯滤波器对图像进行平滑处理,以减少噪声的影响。
  2. 计算梯度:使用Sobel算子计算图像的梯度幅值和方向。
  3. 非极大值抑制:沿着梯度方向,保留局部梯度最大的像素点,抑制其他像素点,有效的去除多余的边缘效应,精确图像的边缘。
  4. 双阈值检测:设置高阈值和低阈值,高于高阈值的像素被认为是强边缘,介于高阈值和低阈值之间的像素被认为是弱边缘。
  5. 边缘连接:通过强边缘像素和与之相邻的弱边缘像素进行连接,形成完整的边缘线。

参数确定及影响

  • 高斯滤波器的参数:通常根据图像的噪声水平选择合适的高斯滤波器参数,如标准差和核大小。
  • 阈值:高阈值和低阈值的选择对边缘检测结果有重要影响。高阈值用于检测强边缘,低阈值用于检测弱边缘。阈值的选择需要根据图像的特点和应用场景进行调整。

1.2.2. Sobel 算子

原理及内部流程: Sobel 算子是一种基于一阶导数的边缘检测算子,通过计算图像在水平和垂直方向的梯度来检测边缘。Sobel 算子使用两个3×3的卷积核,分别计算水平和垂直方向的梯度,然后通过这两个梯度来估计边缘。

参数确定及影响

  • 卷积核大小:通常为3×3,但可以根据需要选择其他大小。
  • 阈值:通过设置阈值来确定边缘像素,阈值的选择需要根据图像的特点和应用场景进行调整。

1.2.3. Laplacian 算子

原理及内部流程: Laplacian 算子是一种基于二阶导数的边缘检测算子,通过对图像进行二阶微分操作来检测边缘。Laplacian 算子可以提供边缘的强度和方向信息。

参数确定及影响

  • 卷积核大小:通常为3×3,但可以根据需要选择其他大小。
  • 阈值:通过设置阈值来确定边缘像素,阈值的选择需要根据图像的特点和应用场景进行调整。、

1.2.4. 在openCV中如何使用

Sobel 算子与Laplacian 算子:这个在之前的高通滤波中已经说明过。

Canny 算子:

edges = cv2.Canny(image, threshold1, threshold2, apertureSize=3, L2gradient=False)
  1. image
    • 作用:输入图像,必须是单通道灰度图像
    • 确认方法:如果输入图像是彩色图像,需要先将其转换为灰度图像:Python复制
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  1. threshold1
    • 作用:低阈值,用于滞后阈值处理。
    • 作用机制:用于检测弱边缘。如果梯度幅值低于此阈值,则认为该像素不是边缘。
    • 确认方法
      • 根据经验,可以设置为 50 左右。
      • 通过实验调整,观察边缘检测的效果。通常需要结合高阈值一起调整。
      • 调的较低会保留更多的弱边缘,对于边缘较弱的,可以适当降低低阈值
  1. threshold2
    • 作用:高阈值,用于滞后阈值处理。
    • 作用机制:用于检测强边缘。如果梯度幅值高于此阈值,则认为该像素是强边缘。
    • 确认方法
      • 根据经验,可以设置为 150 左右。
      • 高阈值与低阈值的比值通常在 2:1 到 3:1 之间。例如,低阈值为 50,高阈值为 150 或 100。
      • 对于边缘较复杂的图像,可以适当增加高阈值。
  1. apertureSize
    • 作用:Sobel 算子的卷积核大小,影响梯度计算的精度。
    • 默认值:3
    • 确认方法
      • 如果需要更平滑的边缘,可以尝试更大的值(如 5 或 7)。
      • 值越大,计算复杂度越高,但边缘检测结果可能更平滑。
  1. L2gradient
    • 作用:决定梯度幅值的计算方式。
      • 如果为 True,则使用 L2 范数计算梯度幅值(M=Gx2+Gy2)。
      • 如果为 False,则使用 L1 范数计算梯度幅值(M=∣Gx∣+∣Gy∣)。
    • 默认值False
    • 确认方法
      • 如果对精度要求较高,可以设置为 True
      • 如果对性能要求较高,可以使用默认值 False
# Canny 边缘检测
edges = cv2.Canny(gray_image, 100, 200)

我们可以找一张图片,先高斯滤波,然后Canny检测,再边缘检测,感受一下各参数的改变的Canny边缘检测的影响:

新建文件:UiTest.py 在其中构建下列类

import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Sliderclass EdgeDetectionDemo:def __init__(self, image_path):self.image = cv2.imread(image_path)if self.image is None:raise ValueError(f"Failed to load image at path: {image_path}")self.image_gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)# 初始化默认参数self.blur_size = 5self.canny_low = 100self.canny_high = 200self.min_w = 100self.min_h = 100# 创建图像窗口self.fig, (self.ax1, self.ax2, self.ax3) = plt.subplots(1, 3, figsize=(18, 6))self.fig.subplots_adjust(bottom=0.25)  # 调整底部空间以放置滑块# 显示原始图像self.ax1.imshow(cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB))self.ax1.set_title("Original Image")self.ax1.axis('off')# 显示边缘检测和轮廓检测结果self.update_processing()# 创建滑块self.create_sliders()plt.show()def update_processing(self):# 高斯模糊(确保核大小为奇数)blur_size = self.blur_size if self.blur_size % 2 == 1 else self.blur_size + 1blurred = cv2.GaussianBlur(self.image_gray, (blur_size, blur_size), 0)# Canny边缘检测edges = cv2.Canny(blurred, self.canny_low, self.canny_high)# 查找轮廓contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 绘制边缘检测结果self.ax2.clear()self.ax2.imshow(edges, cmap='gray')self.ax2.set_title(f"Canny Edges (Low={self.canny_low}, High={self.canny_high})")self.ax2.axis('off')# 绘制轮廓检测结果contour_img = self.image.copy()valid_contours = []for cnt in contours:x, y, w, h = cv2.boundingRect(cnt)if w > self.min_w and h > self.min_h:cv2.rectangle(contour_img, (x, y), (x+w, y+h), (0, 255, 0), 2)valid_contours.append(cnt)self.ax3.clear()self.ax3.imshow(cv2.cvtColor(contour_img, cv2.COLOR_BGR2RGB))self.ax3.set_title(f"Contours (Min Size: {self.min_w}x{self.min_h})")self.ax3.axis('off')self.fig.canvas.draw_idle()  # 重新绘制图像def create_sliders(self):# 创建滑块ax_blur_size = self.fig.add_axes([0.25, 0.15, 0.65, 0.03])ax_canny_low = self.fig.add_axes([0.25, 0.12, 0.65, 0.03])ax_canny_high = self.fig.add_axes([0.25, 0.09, 0.65, 0.03])ax_min_w = self.fig.add_axes([0.25, 0.06, 0.65, 0.03])ax_min_h = self.fig.add_axes([0.25, 0.03, 0.65, 0.03])self.slider_blur_size = Slider(ax_blur_size, 'Blur Size', 1, 15, valinit=self.blur_size, valstep=2)self.slider_canny_low = Slider(ax_canny_low, 'Canny Low', 0, 300, valinit=self.canny_low, valstep=10)self.slider_canny_high = Slider(ax_canny_high, 'Canny High', 50, 500, valinit=self.canny_high, valstep=10)self.slider_min_w = Slider(ax_min_w, 'Min Width', 50, 500, valinit=self.min_w, valstep=10)self.slider_min_h = Slider(ax_min_h, 'Min Height', 50, 500, valinit=self.min_h, valstep=10)# 绑定滑块事件self.slider_blur_size.on_changed(self.update_slider)self.slider_canny_low.on_changed(self.update_slider)self.slider_canny_high.on_changed(self.update_slider)self.slider_min_w.on_changed(self.update_slider)self.slider_min_h.on_changed(self.update_slider)def update_slider(self, val):self.blur_size = int(self.slider_blur_size.val)self.canny_low = int(self.slider_canny_low.val)self.canny_high = int(self.slider_canny_high.val)self.min_w = int(self.slider_min_w.val)self.min_h = int(self.slider_min_h.val)self.update_processing()

在另外一个文件(learnCV.py)中引用该类

from ImageManipulation import cvTest
from UiTest import EdgeDetectionDemo
def main():# cvTest.TestGrayImage()# cvTest.TestChannelSplite()demo = EdgeDetectionDemo("Cars.jpg")if(__name__=="__main__"):main()
  1. 滤波核大小对弱边缘有影响,滤波核越大,弱边缘越少

 

 

高阈值越高,弱边缘越少

 


极限检测:

上下限和滤波都是0:

 

先逐渐把低阈值拉满:

 

再把高阈值拉满:

 

弱边缘是在持续减少的。

大家可以个人自己多尝试尝试

 

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

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

相关文章

vscode的一些实用操作

1. 焦点切换(比如主要用到使用快捷键在编辑区和终端区进行切换操作) 2. 跳转行号 使用ctrl g,然后输入指定的文件内容,即可跳转到相应位置。 使用ctrl p,然后输入指定的行号,回车即可跳转到相应行号位置。

Redis(高阶篇)02章——BigKey

一、面试题 阿里广告平台,海量数据里查询某一个固定前缀的key小红书,你如何生产上限制 keys* /flushdb/flushall等危险命令以防止阻塞或误删数据?美团,memory usage命令你用过吗?BigKey问题,多大算big&…

《Zookeeper 分布式过程协同技术详解》读书笔记-2

目录 zk的一些内部原理和应用请求,事务和标识读写操作事务标识(zxid) 群首选举Zab协议(ZooKeeper Atomic Broadcast protocol)文件系统和监听通知机制分布式配置中心, 简单Demojava code 集群管理code 分布式锁 zk的一…

53倍性能提升!TiDB 全局索引如何优化分区表查询?

作者: Defined2014 原文来源: https://tidb.net/blog/7077577f 什么是 TiDB 全局索引 在 TiDB 中,全局索引是一种定义在分区表上的索引类型,它允许索引分区与表分区之间建立一对多的映射关系,即一个索引分区可以对…

unity学习39:连续动作之间的切换,用按键控制角色的移动

目录 1 不同状态之间的切换模式 1.1 在1个连续状态和一个连续状态之间的transition,使用trigger 1.2 在2个连续状态之间的转换,使用bool值切换转换 2 至少现在有2种角色的移动控制方式 2.1 用CharacterController 控制角色的移动 2.2 用animator…

【Python 打造高效文件分类工具】

【Python】 打造高效文件分类工具 一、代码整体结构二、关键代码解析(一)初始化部分(二)界面创建部分(三)核心功能部分(四)其他辅助功能部分 三、运行与使用四、示图五、作者有话说 …

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议(Internet Protocol,IP)的数据报格式,由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分,包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…

Leetcode 424-替换后的最长重复字符

给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后,返回 包含相同字母的最长子字符串的长度。 题解 可以先做LCR 167/Leetcode 03再做本题 滑动窗口&…

28 在可以控制 postgres 服务器, 不知道任何用户名的情况下怎 进入 postgres 服务器

前言 最近有这样的一个需求, 有一个 postgres 服务器 但是 不知道 他的任何的用户名密码, 但是我想要查询这台 postgres 服务器 然后 基于这个需求, 我们看一下 怎么来处理 pg_hba.conf 认证方式修改为 trust 首先将 postgres 服务器的认证方式修改为 trust 这时候 …

LM Studio笔记

一、什么是 LM Studio? LM Studio 是一款功能强大、易于使用的桌面应用程序,用于在本地机器上实验和评估大型语言模型(LLMs)。它允许用户轻松地比较不同的模型,并支持使用 NVIDIA/AMD GPU 加速计算。 功能集&#xff1…

内网下,Ubuntu (24.10) 离线安装docker最新版教程

一般在数据比较敏感的情况下,是无法使用网络的,而对于Ubuntu系统来说,怎么离线安装docker呢? 下面我给大家来讲一下: 采用二进制安装: 1.下载docker离线包 官网下载: Index of linux/static…

框架ThinkPHP(小迪网络安全笔记~

免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!! 附:完整笔记目录~ ps:本人小白,笔记均在个人理解基础上整理,…

sql数据执行失败,三个命令依次执行

set global innodb_strict_mode off set global.sql_mode ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION; set sql_mode ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION;

【网络安全】零基础入门网络安全劝退指北

作为从16年接触网络安全的小白,谈谈零基础如何入门网络安全,有不对的地方,请多多指教。 这些年最后悔的事情莫过于没有把自己学习的东西积累下来形成一个知识体系。 如何入门 简单了解网络安全 网络安全就是指的确保网络系统中的数据不被别…

【Linux】网络基础

目录 一、协议分层 (一)计算机网络 (二)协议分层 (三)OSI模型 (四)TCP/IP协议 二、网络传输过程 三、IP地址和MAC地址 (一)IP地址 (二&a…

ms-swift3 序列分类训练

目录 引言 一、数据集准备 二、训练/推理代码 2.1 训练 2.2 推理 三、性能验证 引言 swift 3.x支持了序列分类Command Line Parameters — swift 3.2.0.dev0 documentation 想尝试一下用多模态(图像)的序列分类与普通的图像分类任务有啥区别 一、…

STC 51单片机63——关于STC8H的ADC通道切换问题

使用STC8H时,发现在ADC中断中只能使用一个通道,即使切换了通道,那么数据要不为0,要不就是原先通道的电压。查阅手册,内容并不多,没有发现专门提到的问题。只能去试试,最后发现在ADC中断中&#…

大数据处理如何入门

大数据处理的入门可以从以下几个方面入手: 1. 基础知识学习 在深入大数据领域之前,建议先掌握一些基础知识,包括数据类型、存储与处理的基本概念,以及常用的数据处理工具。例如,Python或Java编程语言在大数据领域应用…

Logistic Regression 逻辑回归中的sigmoid函数是什么?

Sigmoid函数是一种在数学、计算机科学,尤其是在机器学习和深度学习领域广泛应用的函数,以下是关于它的详细介绍: 定义与公式 Sigmoid函数的数学表达式为: S ( x ) = 1 1 + e − x S(x)=\frac{1}{1 + e^{-x}} S(x)=1+e−x1​,其中 x x x 可以是一个实数、向量或矩阵。当 …

什么是Spring Boot?

Spring Boot 是基于 Spring 框架的扩展工具,旨在简化 Spring 应用的初始搭建和开发流程。它通过约定优于配置和自动装配机制,减少了传统 Spring 开发中的繁琐配置,使开发者能快速构建独立运行、生产级别的应用。 Spring Boot 的核心特性 自动…