百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

OpenCV 图像边缘检测:sobel、scharr、laplacian、canny

toyiye 2024-07-11 00:25 18 浏览 0 评论

各位同学好,今天和大家分享一下图像边缘检测的几个算子,主要内容有:

(1)sobel算子:cv2.Sobel();(2)scharr算子:cv2.Scharr();(3)laplacian算子:cv2.Laplacian();(4)canny算子:cv2.Canny()


正文

在开始前,我们先导入需要的库文件和图片,再定义一个图像显示函数,方便绘图。

import numpy as np
import cv2
# 获取图片所在文件夹
filepath = 'C:\\Users\\admin\\.spyder-py3\\test\\opencv\\img'
# 获取文件夹中的某一张图片
img = cv2.imread(filepath+'\\mh1.jpg',cv2.IMREAD_GRAYSCALE)
# 定义绘图函数
def cv_show(name,img):
    # 传入自定义图像名,即图像变量
    cv2.imshow(name,img) 
    # 图片不会自动消失
    cv2.waitKey(0)
    # 手动关闭窗口
    cv2.destroyWindow()

1. Sobel算子

假设在一幅图像中,一块区域内如果全为黑或全为白,都是同一种颜色此时灰度的变化率为0;当一块区域内既有白又有黑,那么在黑白交界处的灰度变化就不为0,这些梯度不为0的区域也就是我们需要找的边缘。

Sobel算子的特点:根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,但边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。

sobel算子计算方法:使用两个3*3的卷积核分别和原始图像运算,卷积核中的每一个值和图像做内积,得到的值代替卷积核滑窗所框住的图像的中间值。分别得到横向 G(x) 和纵向 G(y) 的梯度值,如果梯度值大于某一个阈值,则认为该点为边缘点。


sobel算子函数:

dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • src:输入图像
  • ddepth:图像深度,通常指定-1,表示输入深度和输出深度相同
  • dx和dy:代表水平和竖直方向。当dx=1,dy=0,表示对x方向求梯度,y方向不求。
  • ksize:是sobel算子的大小,指定核的大小,默认为3,卷积核为上图所示。

图像深度是指存储每个像素值所用的位数,如:CV_16S(16位有符号数),CV_16U(16位无符号数),CV_32F(32位浮点数),CV_64F(64位浮点数)

我们先对水平方向计算梯度

# 输入图像,计算结果能带负数;dx=1,dy=0,表明计算水平的;卷积核3*3
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
# 绘图
cv_show('sobelx',sobelx)

由于opencv自带的sobel算子在进行卷积运算时没有求绝对值,每个像素值是在0-255之间,计算时所有结果小于零的值都会变成0。截断操作,即计算结果大于255则输出为255,小于0则输出为0,其余不变。因此我们需要对小于0的像素值取绝对值,将这些值在图像上显示出来。

取绝对值函数为:

cv2.convertScaleAbs(src)

输入图像src,计算绝对值,然后将结果转换为uint8类型

# 取绝对值
sobelx = cv2.convertScaleAbs(sobelx)
cv_show('abs',sobelx)

第一张是原图,第二张是sobel函数计算结果,第三张是取绝对值之后



我们完成了x方向的梯度计算,接下来对y方向计算梯度,方法和上面一样,不再赘述。

# 对x轴求完之后,再对y轴求。只计算竖直方向梯度,不计算水平方向dx=0
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
cv_show('abs',sobely)

由于Sobel算子是在x和y两个方向上分别计算梯度的,最后还需要计算整个图像的梯度。

公式为:


图像叠加或图像混合加权函数为:

cv2.addWeighted(src1, alpha, src2, beta, gamma)

其中alpha是第一幅图片的权重;beta是第二个的权重,;gamma是加到最后结果上的偏置,一般为0

# 偏置项一般为0,比例分配自定义
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
cv_show('sobelxy',sobelxy)

第一张是对x轴求梯度,第二张是对y轴求梯度,第三张是叠加后的

2. Scharr算子

scharr与sobel算子思想一样,只是卷积核的系数不同,scharr算子提取边界也更加灵敏,能提取到更细小的边界,但越是灵敏就越是可能误判。下图左边是scharr算子计算水平梯度时的卷积核,右边是计算垂直梯度时的卷积核


scharr算子函数:

cv2.Scharr(src, ddepth, dx, dy, ksize)

src表示输入的图片。ddepth表示图片的深度,通常使用-1,这里使用cv2.CV_64F允许结果是负值。具体深度值同Sobel算法。dx表示计算x轴方向梯度,dy表示计算y轴方向梯度。ksize为卷积核大小默认为3


#(1)图像梯度Scharr算子
# 对x方向求梯度,保留计算后的负号
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
# 对图像像素求绝对值
scharrx = cv2.convertScaleAbs(scharrx)
# 对y方向求梯度
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharry = cv2.convertScaleAbs(scharry)
# 将两幅图像按比例叠加
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
cv_show('scharr',scharrxy)

下图第一张是原图,第二张是scharr算法处理后的


3. Laplacian算子

Laplacian算子是一个二阶的算子,它的运算规则是在水平方向运算两次,垂直方向运算两次,两个结果相叠加替换中心点(锚点)的像素值,对噪音比较敏感,直接使用时效果不太好。其卷积核为:

而sobel算子和scharr算子一般先算一个水平梯度,再算一个垂直方向梯度,然后把两个结果按照0.5的权重进行图像融合以得到完整的边界。

Laplacian算子函数:

dst = cv2.Laplacian(src, ddepth, ksize)

src为输入图像,ddepth为图像深度,同sobel函数,ksize为卷积核大小默认为1

#(2)图像梯度laplacian算子
# 求二阶导,对于噪音点比较敏感,直接用效果不太好
# 通过中间点和周围的比较来求,不需要x和y轴
laplacian = cv2.Laplacian(img, cv2.CV_64F,ksize=3)
laplacian = cv2.convertScaleAbs(laplacian)
cv_show('laplacian',laplacian)


4. canny算子

canny算子边缘检测步骤:

(1)高斯滤波器,平滑图像,消除噪声

(2)计算图像中每个像素点的梯度强度和方向。把小的梯度抑制,保留大的,体现最明显的边缘

(3)应用非极大值抑制,消除边缘检测带来的杂散响应

(4)应用双阈值检测来确定真实和潜在的边缘。对所有可能的边界再过滤,只保留最真实的边界

(5)通过抑制孤立的弱边缘最终完成边缘检测

4.1 高斯滤波器

使用高斯滤波,对图像去噪。卷积核在图像上滑动,将核的锚点放在该特定位置的像素上,同时,核内的其他值与该像素邻域的各像素重合;卷积核内的权重值服从高斯分布,离中心点越近的点权值越大。将卷积核内的值进行归一化处理。将卷积核内各值与相应像素值做内积,将乘积相加后求平均,将所得结果放到与锚点对应的像素上。如下图,H代表归一化后的高斯核,A代表高斯核框住的图像的像素值数据,e代表使用e值替换原图像上被高斯核框住的最中间的值。

4.2 梯度和方向

使用sobel算子计算梯度和方向。Sx和Sy分别代表x方向和y方向上的卷积核,先计算x方向的梯度Gx和y方向的梯度Gy,再计算合成梯度G。然后计算梯度方向θ。

4.3 非极大值抑制

(1)方法1:线性插值法。

梯度方向和边界方向是垂直关系。比较当前点的梯度值和它梯度方向上的2个点的梯度值。

已知c点梯度方向,如下图蓝色线所示,判断c点是否是极大值点,和dtmp1dtmp2的梯度值相比较。在图像上g1、g2、g3、g4都是可以计算的,那就通过线段比例去计算dtmp1和dtmp2。M(dtmp1)=w*M(g2)+(1-w)*M(g1),权重参数w等于dtmp1到g2的距离除以g1到g2的距离。

得到dtmp1和dtmp2的梯度值之后与c的梯度值相比较。如果c是极大值点,把像素c点保留,否则把c点抑制。

(2)方法2:

将线性插值简化成8个方向,由于梯度方向和边界方向是垂直关系,因此很容易就可以找出边界方向。在简化方向时,看梯度方向上的点距离这八个方向哪一个最近,就归为那个方向。如上图中的dtmp1就归为朝上方向。

对比当前点和梯度方向的两个点的梯度大小,如果A的梯度比B和C都要大,那么A就保存下来,由于梯度方向和边界垂直,这样就能找出A的边界。

4.4 双阈值检测

如果计算出的A点的梯度值大于maxval,那就将A点处理为边界。如果梯度值小于minval的,即不是边界,就将该点舍弃。如果梯度值在maxval和minval之间,如c点,连有边界那也将c视为边界,如B点没有连接边界,对B点舍弃。

4.5 代码实现

cv2.Canny(img, minval, maxval, apertureSize, L2gradient)

img为输入图像;minval为最小阈值;maxval为最大阈值。

可选参数:

apertureSize为sobel算子卷积核大小;

L2gradient是一个布尔值,如果为真,则使用更精确的L2范数进行计算(两个方向的导数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)。

# 获取图像
img = cv2.imread(filepath+'\\mh1.jpg',cv2.IMREAD_GRAYSCALE)
# 使用canny算子,指定最大和最小阈值
# minval阈值指定的小,对边缘的要求没那么高,能检测出尽可能多的边界
# maxval阈值指定的大,对边界的要求很高
# 对比不同与之参数
v1 = cv2.Canny(img,50,100) #阈值小
v2 = cv2.Canny(img,150,200) #阈值大,边界越少
# 绘图
res = np.hstack((v1,v2))
cv_show('res',res)

第一张为原图,第二张图为阈值较小的结果,第三张图为阈值较大的结果。


最后有惊喜(别错过哦)

跻身大厂是每一个程序员的梦想,也希望有机会可以大放异彩,成绩斐然。不过,不积跬步无以至千里,理想和现实的距离是需要努力来不断缩短的。

所以这里我准备了一些礼包,希望能够帮助到各位小伙伴。

★礼包1

如果对学习没有自制力或者没有一起学习交流的动力,欢迎私信或者评论区留言,我会拉你进学习交流群,我们一起交流学习,报团打卡,群内更有众多福利等你来解锁哟,赶快加入我们吧!

★礼包2

?Python全套电子书,200本总共6个G电子书资料,囊括Python各大领域。

?Python练手项目,包括爬虫、数据分析、机器学习、人工智能、小游戏开发。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码