[图像识别]7.OpenCV的边缘检测 |
您所在的位置:网站首页 › 身边的榜样,前行的力量心得体会 › [图像识别]7.OpenCV的边缘检测 |
回顾,上节课你学到了什么?
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 ,代表这张图片.... 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) 结果 将上述#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求一阶导数基于二阶导数来边缘检测, 使用的卷积核是 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)结果 最流行的一种边缘检测算法 【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 |