[图像识别]7.OpenCV的边缘检测

您所在的位置:网站首页 身边的榜样,前行的力量心得体会 [图像识别]7.OpenCV的边缘检测

[图像识别]7.OpenCV的边缘检测

2022-11-12 20:13| 来源: 网络整理| 查看: 265

回顾,上节课你学到了什么?

plt.figure(num,figsize,dpi,bgcolor.edgecolor,frameon)

plt.title(string)

plt.xlabel()

plt.ylabel()

plt.xlim((star,end))

plt.ylim((star,end))

plt.plot(图变量,format_string)

plt.plot(x,y,format_string)

plt.grid()

plt.show()

fig,axes=plt.subplots(nrows,ncols,sharex,sharey,subplot_kw,**fig_kw) axes[r1,c1].imshow(img)

axes[r1,c1]=plt.set_title(string)

plt.savefig(图片路径)

cv.bitwise_and(img1,img2,mask=掩膜矩阵)        按位与

cv.bitwise_or(img1,img2,,mask=掩膜矩阵)        按位或

cv.bitwise_not(img1,img2,,mask=掩膜矩阵)        按位非

cv.bitwise_nor(img1,img2,,mask=掩膜矩阵)        按位异或

cv.calcHIst([img],[channels],mask,[histSize],ranges,hist,accumulate)

res=cv.equalizeHist(img)

clahe=cv.createCLAHE(clipLimit,tileGridSize)

Img=clahe.apply(img)

目录

1.原理

2.Sobel检测算子

 3.Shcarr算子

 4.Laplacian算子(拉普拉斯)

5.Canny边缘检测

总结,这节课你学到了什么?

1.原理

识别数字图像中亮度突变的点,边缘检测大幅度减少了数据量,保留了图像重要的结构属性

边缘检测方法主要有两种:

【1】基于搜索:

通过寻找图像一阶导数中的最大值来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值,代表算法是Sobel算子和Scharr算子。

 

【2】基于零穿越

通过寻找图像二阶导数零穿越来寻找边界,二阶导数为0代表的一阶导数的斜率方向变化点,也就是原函数斜率最大点。代表算法是Laplacian算子。

图像处理中的差分求导计算和相应的卷积核(filter)_子燕若水的博客-CSDN博客1)一元函数的一阶导数稍微的调整一下,得到离散信号的导数怎么计算呢? 很简单,右边的是这个操作的filter或者卷积核,把这个卷积核扩展到二维如下,用这个卷积核,对图片执行一遍卷积操作,就得出图片沿着这个方向(x轴)的导数了!如下上面的f(x,y) =I ,代表这张图片....https://blog.csdn.net/u010087338/article/details/108938426如何根据导函数与原函数关系式计算卷积核,建议阅读。

 

2.Sobel检测算子

特点:简单效率高,不如canny检测准确,对细纹理不太关心

原理:

 

假设要处理的图像为I,在两个方向求导:

水平变化:将图像I与奇数大小的模版进行卷积,结果为Gx。比如,当模板大小为3时,Gx为:

垂直变化:将图像I与奇数大小的模版进行卷积,结果为Gy。比如,当模板大小为3时,Gy为:

 结合以上俩个方向:

G就可以代表二维的斜率或变化率,极大值点就是突变点边缘

注意:当内核大小为3时,以上Sobel内核可能产生比较明显的误差,为解决这一 问题,我们使用Scharr函数,但该函数仅作用于大小为3的内核。该函数结果更加精确,其计算方法为:

 Sobel_x_or_y=cv.Sobel(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

ddepth:图像深度

dx,dy:求导阶数,0表示没求导

ksize:卷积核大小,int类型,必须为奇数,默认3

scale:缩放导数比例常数

borderType:边界模式

Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,所Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv.CV_ 16S。

常用

 Sobel_x_or_y=cv.Sobel(img,cv.CV_ 16S,dx,dy,ksize)

处理完图像后,再使用cv2.convertScaleAbs0函数将其转回原来的uint8格式,否则图像无法显示。 Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted( )函数将其组合起来

#格式转换将16位有符号的数据类型转换为uint8的scale缩放

Scale_abs=cv.convertScaleAbs(x)

#俩个方向合成

result=cv.addWeighted(img1,p1,img2,p2,k)

举例

#6.1

import cv2 as cv import numpy as np import matplotlib.pyplot as plt #解决中文显示问题,直接复制不用在意 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False #1.读取灰度图 pic1 = cv.imread("7.jpeg",0) #2.计算Sobel算子 x=cv.Sobel(pic1,cv.CV_16S,1,0,3)#对x求一阶导数 y=cv.Sobel(pic1,cv.CV_16S,0,1,3)#对y求一阶导数 #3.格式转换 Scale_absx=cv.convertScaleAbs(x) Scale_absy=cv.convertScaleAbs(y) #4.xy俩个方向合并 res=cv.addWeighted(Scale_absx,0.5,Scale_absy,0.5,0) #绘制图像 fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10)) axes[0,0].set_title("原图") axes[0,0].imshow(pic1,plt.cm.gray) axes[0,1].set_title("x方向突变图") axes[0,1].imshow(Scale_absx,plt.cm.gray) axes[1,0].set_title("y方向突变图") axes[1,0].imshow(Scale_absy,plt.cm.gray) axes[1,1].set_title("Sobel") axes[1,1].imshow(res,plt.cm.gray) plt.show() cv.waitKey(0)

 结果

 3.Shcarr算子

将上述#6.1代码中第2步修改算子的ksize=-1就是SCharr算子

x=cv.Sobel(pic1,cv.CV_16S,1,0,ksize=-1)#对x求一阶导数 y=cv.Sobel(pic1,cv.CV_16S,0,1,ksize=-1)#对y求一阶导数

 4.Laplacian算子(拉普拉斯)

基于二阶导数来边缘检测,

使用的卷积核是

 laplacian=cv.Laplacian(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

ddepth:图像深度,-1表示原图像深度,目标图像深度必须大于原图深度

dx,dy:求导阶数,0表示没求导

ksize:卷积核大小,int类型,必须为奇数

scale:缩放导数比例常数

borderType:边界模式

 由于 laplacian就是基于二维导数,所以不用求x,y方向,只需要求一次

#6.2

import cv2 as cv import numpy as np import matplotlib.pyplot as plt #解决中文显示问题 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False #1.读取灰度图 pic1 = cv.imread("7.jpeg",0) #2.计算laplacian算子 laplacian=cv.Laplacian(pic1,cv.CV_16S)#对对图像求二阶导数 #3.格式转换 Scale_abs=cv.convertScaleAbs(laplacian) #绘制图像 fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,10)) axes[0].set_title("原图") axes[0].imshow(pic1,plt.cm.gray) axes[1].set_title("laplacian") axes[1].imshow(Scale_abs,plt.cm.gray) plt.show() cv.waitKey(0)

结果

5.Canny边缘检测

最流行的一种边缘检测算法

【1】噪声去除   

由于边缘很容易受到噪声的影响,先通过5x5的高斯滤波器去除噪声

【2】计算图像梯度

用Sobel一阶算子得到x,y方向的梯度,根据这俩梯度得到边界的梯度与方向

 如果像素是边缘,则梯度方向总是与边界方向垂直。梯度方向被归为四类:水平,垂直和俩个对角线方向

【3】非极大抑制

整体扫描,去除非边界点,查看这个点是不是周围同一梯度方向最大的,若为极大值则保留,否则去除(抑制)。最终结果细边二进制图像

【4】滞后阈值

设定俩个阈值minVal和maxVal,高于maxVal认定为边界,低于minVal认为不是边界,俩者之间看有没有跟边界相连,如果相连则认定为边界。所以设定这俩个阈值非常关键

canny=cv.Canny(img,threshold1,threshold2)

threshold1:minVal,低阈值

threshold2:maxVal,高阈值

 举例

#6.3

import cv2 as cv import numpy as np import matplotlib.pyplot as plt #解决中文显示问题 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False #1.读取灰度图 pic1 = cv.imread("7.jpeg",0) #2.Canny边缘检测 canny=cv.Canny(pic1,100,200) #绘制图像 fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,10)) axes[0].set_title("原图") axes[0].imshow(pic1,plt.cm.gray) axes[1].set_title("Canny") axes[1].imshow(canny,plt.cm.gray) plt.show() cv.waitKey(0)

结果

总结,这节课你学到了什么?

 Sobel_x_or_y=cv.Sobel(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

常用 Sobel_x_or_y=cv.Sobel(img,cv.CV_ 16S,dx,dy,ksize)

格式转换Scale_abs=cv.convertScaleAbs(x)

result=cv.addWeighted(img1,p1,img2,p2,k)

laplacian=cv.Laplacian(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

canny=cv.Canny(img,threshold1,threshold2)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3