opencv-python常用函数解析及参数介绍(七)——边缘检测

news2024/11/15 3:15:19

边缘检测

  • 前言
  • 1.基本概念
    • 1) 滤波
    • 2) 计算梯度
    • 3) 非极大值抑制
    • 4) 双阈值检测
  • 2.opencv中的边缘检测
    • 效果展示
    • 分析对比
  • 3.结尾

前言

在之前的文章中我们介绍了使用膨胀和腐蚀、计算图像梯度的方式来获取图像的轮廓,本篇文章将介绍另外一种可以获取图像轮廓的方法——边缘检测

1.基本概念

首先我们来看一下边缘检测的基本过程

1) 滤波

使用高斯滤波器,以平滑图像,滤除噪声
在这里插入图片描述
H即为高斯分布的卷积核,初看上去似乎这个矩阵似乎很莫名其妙,但其实他的特征很明显,中间的数值要比周围的大,因为高斯滤波使用的卷积核是满足高斯分布,即正态分布的(是的,高斯分布就是正态分布)

关于高斯滤波的细节请参考之前的文章:opencv-python常用函数解析及参数介绍(三)——图像滤波

2) 计算梯度

计算图像中每个像素点的梯度强度和方向。

我们以3x3的sobel算子为例计算梯度
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在之前的文章中我们知道,sobel的梯度因为算子可以分成Sx和Sy,所以梯度也可以分为两个梯度,一个是Gx,更加侧重左右的偏差,即侧重竖直方向的边缘,而Gy更加侧重上下的偏差,即侧重水平方向的边缘,那么我们得到了x方向的梯度Gx,y方向的梯度Gy,那么总梯度应该为

G x 2 + G y 2 \sqrt{Gx^2+Gy^2} Gx2+Gy2
这里我们只求得了梯度的大小,那么如何计算梯度的方向呢

我们已经知道了x方向的梯度大小为Gx,y方向的梯度大小为Gy
假设梯度方向与 x 轴方向的夹角为 θ 则 t a n θ = G y G x 即 : θ = a r c t a n ( G y G x ) 假设梯度方向与x轴方向的夹角为 \theta \\则tan\theta = \frac{Gy}{Gx} \\ 即:\theta = arctan(\frac{Gy}{Gx}) 假设梯度方向与x轴方向的夹角为θtanθ=GxGy:θ=arctan(GxGy)

关于图像梯度的计算的详细细节可以参照上一篇博客:opencv-python常用函数解析及参数介绍(六)——图像梯度

3) 非极大值抑制

顾名思义就是抑制不是极大值的值,应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
在本问题中可以理解为只选用最大的梯度。

4) 双阈值检测

应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。

其细节上表现为,设置两个阈值,一个阈值决定下限,另一个阈值决定上限,超过阈值上限的梯度可以理所应当的被认为是边缘,低于下限的梯度被认为不是边缘,而对应在上下限直接的范围梯度,应该看与他相连的梯度是不是已经被认为是边缘,如果已经被认为是边缘了,那么与边缘相连的也一定是边缘。

2.opencv中的边缘检测

上述的过程似乎有些复杂,幸好,在opencv中我们可以使用cv2.Canny进行边缘检测,我们只需设置双阈值检测中需要的上下限就好

效果展示

我们假设有一张名为kl.png的图片
在这里插入图片描述
为了展示方便,我们依然先编写一个展示函数

def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

对这张图片进行边缘检测的效果如下

img=cv2.imread("kl.png",cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,80,150)
cv_show(v1,'res')

在这里插入图片描述

分析对比

与上篇文章中直接使用梯度当做边缘的效果相比似乎是更好的,那么这是为什么呢?其主要的区别就是从双阈值检测,因为我们进行了双阈值检测,在这个过程中当某一个点上的梯度小于设置的下限时就会被丢弃,即立即判断这个点不是边缘,所以相比之下,结果看起来会更干净(因为直接使用梯度作为边缘时一些较小梯度的点仍然会被保留)

当我们把下限设置成0时,即不对梯度的下限做限制,我们可以清晰的看到有些本不属于边缘的位置被当成了边缘

img=cv2.imread("kl.png",cv2.IMREAD_GRAYSCALE)
v1=cv2.Canny(img,0,150)
cv_show(v1,'res')

下面我们来对上下限进行修改,然后做一下对比

img=cv2.imread("kl.png",cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,0,150)
v2=cv2.Canny(img,50,150)
v3=cv2.Canny(img,50,200)

res = np.hstack((v1,v2,v3))
cv_show(cv2.resize(res, (1500, 500)),'res')

在这里插入图片描述

从这个对比中我们可以得到一个结论,上限相同时,降低下限,会导致被直接判断成非边界的点减少,从而得到更多的边缘,下限相同时,升高上限,会使得直接被判断成边界的点减少,同时也会影响到与被判断成边界的点相连的点,产生更少的边缘

3.结尾

关于边缘检测所需的内容,如果感兴趣可以参照之前的一个博客边缘检测生成(伪)手绘线稿风格的视频简易版教程自己生成一个边缘检测的(伪)线稿视频,关于图像的处理所用的全都是本专栏介绍过的知识

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再说原型链

关于原型链,已经被无数次的提起,每次回顾都有新的理解,今天我们再来说说原型链。 我们知道,每一个javascript对象(除了null)在被创建的时候都会与另一个对象关联起来,这个对象就是我们所说的原型…

【C++进阶】二叉搜索树

文章目录二叉搜索树概念二叉搜索树操作二叉搜索树的实现每个节点的结构插入查找删除二叉搜索树的所有代码(包括测试)版本一版本二test.cpp二叉搜索树概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空&a…

Linux环境下gdb程序调试

目录gdb介绍进入gdb调试环境指令学习l(list)指令b(break)指令info b指令d指令r(run)指令n(next)指令s(step)指令c(continue)指令bt(breaktrace)指令finish指令p(print)指令display指令undisplay指令until指令disable命令enable命令这篇文章将会介绍gdb以及一些常用的gdb调试指令…

3.移动端百分比布局练习-京东首页

访问地址 https://youthddup.gitee.io/myproject/ 1、项目目录结构 2、注意 (1)设置视口标签以及引入初始化样式 (2)二倍精灵图缩放 先把精灵图等比缩放原来的一半 然后再测精灵图位置 代码里background-size置为原来的一半 &a…

typescript 数组操作

使用变量来存储值会带来以下限制: 变量本质上是标量。换言之,一个变量声明变量声明一次只能包含一个。这意味着在程序中存储n个值需要n个变量声明。因此,当需要存储更大的值集合时,使用变量是不可行的。 程序中的变量以随机顺序分…

当下一场数字化的浪潮,正在各行各业深刻上演着

一场数字化的浪潮,正在各行各业深刻上演着。在零售领域,亦不例外。以往,提及零售,我们更多地想到的是,各式各样的电商平台,我们看到的是,各式各样的电商模式;现在,提及零…

测试用例设计-淘宝购物车

测试人员和开发人员产生争执了怎么办? ① 先检查自身,是否BUG描述不清楚 ② 站在用户的角度考虑问题 ③ BUG定级要有理有据 ④ 提高自身的技术能力和业务水平,最好同时提出解决方案。 ⑤ 开发人员不接受时,不要争吵,可…

YOLOv5更换骨干网络之 PP-LCNet

论文地址:https://arxiv.org/abs/2109.15099 代码地址:https://github.com/ngnquan/PP-LCNet 我们提出了一种基于MKLDNN加速策略的轻量级CPU网络,名为PP LCNet,它提高了轻量级模型在多个任务上的性能。本文列出了在延迟几乎不变的…

YOLOv5更换骨干网络之 EfficientNet-B0

论文地址:https://arxiv.org/abs/1905.11946 代码地址:https://githeb.com/TensorFlow/tpu/tree/master/Models/Offical/Efficientnet 卷积神经网络(ConvNet)通常是在固定的资源预算下开发的,如果有更多的资源可用,则…

如何从macOS ventura降级到 macOS Monterey?这两大方法可以帮到你

苹果发布了macOS 13 Ventura的正式版系统,增加了许多实用性的功能,大家纷纷下载更新最新版本的系统。但根据许多已安装ventura的用户反馈,这个版本的MacOS系统还不够成熟,应该有不少bug还没有修复过来,从而求助小编分享…

c#入门-泛型约束

泛型约束 使用泛型时会假设泛型占位符是任何类型。 但因为它被假设是任何类型,所以使用起来有很大的限制。只有所有类型都有的功能,他才能用。 为了满足所有的可能类型,可用的操作非常少。 为此我们可以为泛型占位符添加约束。虽然会让能兼…

大型项目迭代流程

一、回顾目标 总目标: 年底上线完成100% 结果: 年底上线并开量验证过成功,完成率100% 阶段目标A: 10月底项目全流程开发完成,并提测出票前流程 结果:10月21日项目开发完成100%,10月25日前…

基于残差神经网络的交通标志识别算法研究与应用实现

问题: 从图像中识别交通标志对于自动驾驶至关重要。要想实现自动驾驶,车辆必须了解并遵守所有交通规则。当前,特斯拉、谷歌、梅赛德斯-奔驰、丰田、福特、奥迪等许多大公司都在研究自动驾驶。因此,为了实现这项技术的准确性&…

pandas的series创建和pandans的dataFrame创建

一:series和读取外部数据 1.1pandas的series的了解 1.1.1 为什么要学习pandas numpy能够帮我们处理处理数值型数据,但是这还不够。很多时候,我们的数据除了数值之外,还有字符串,还有时间序列等 比如:我们通…

显式利用用户画像的多兴趣建模

显式利用用户画像的多兴趣建模 目前在多兴趣建模中,用户侧的特征包括用户基础画像特征(年龄、性别、地域等)、用户在当前场景的静态兴趣画像特征(短期兴趣画像、长期兴趣画像)、交互的历史正向行为序列特征&#xff0…

【Javassist】快速入门系列13 使用Javassist获取注解

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 05 当有指定方法调用时替换方法调用的内容 06 当有构造方法调用时替换方法调用的内容 07 当检测到字段被访问时使用语…

MySQL性能优化三 一条SQL在MySQL中执行的过程

一 MySQL的内部组件结构 大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。 1.1 service层 主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学…

Easy-Captcha验证码 生成以及校验(简单易懂)

目录说明pom引入详解参数类使用easy-captcha 中提供了下面几种类源码说明Captcha使用验证图解源码测试GitHub说明 Java图形验证码&#xff0c;支持gif、中文、算术等类型&#xff0c;可用于Java Web、JavaSE等项目 pom引入 <dependency><groupId>com.github.whvc…

【C++】 bitset(位图)的使用

目录 一、bitset的基本介绍 1. 位图的概念 2. 位图的应用 二、biset的基本使用 1. bitset的成员函数 2. 基本使用介绍 1. 定义方式 2. 成员函数的使用 一、bitset的基本介绍 1. 位图的概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数…

win系统一台电脑安装两个不同版本的mysql教程

1.mysql下载zip包&#xff08;地址&#xff09;MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ 2.解压在你的电脑上&#xff08;不要再C盘和带中文的路径&#xff09; data和my.ini是没有的。 3.创建my.ini文件 创建记事本改变后缀名就可以 …