目录
4、x方向上的边缘,包括负数信息,进行取绝对值的操作,右端的负值信息就可以显示出来了,使用cv2.convertScaleAbs()方法
2、 转换数据类型保存图像的负数信息,同时,y方向上的边缘,包括负数信息,进行取绝对值的操作,右端的负值信息就可以显示出来了,使用cv2.convertScaleAbs()方法
3、非极大值抑制NMS(Non-Maximal Suppression)
边缘检测
边缘检测:是图形图像处理、计算机视觉和机器视觉中的一个基本工具,通常用于特征提取和特征检测,旨在检测一张数字图像中有明显变化的边缘或者不连续的区域。
一、sobel算子边缘检测
(1)原理
Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑(离像素点越远的值越小)和微分求导运算(像素变化率, 从左到右或右到左)。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
Sobel算子包含2组3×3的矩阵,分别为横向和纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。
1、X轴方向的边缘检测
Gx这个卷积核会从图像的左上角,从左到右从上到下移动,每移动到一个新的位置都会按卷积核计算。在纵向方向上进行加权计算。
当卷积框出现在”1“这个位置时,卷积框左侧为黑色,数值为接近0的数;卷积框右侧为白色,数值为接近255的数,卷积计算之后的值大于255正值。
当卷积框出现在”2“位置时,卷积框左右对称计算之后数值接近0,显示为黑色。
当卷积框出现在”3“位置时,卷积框左侧为白色,数值为接近255的数;卷积框右侧为黑色,数值为接近0的数,卷积计算之后的值为小于255负值。
由于负数在opencv的图像中显示不出来,所以会出现圆的左半部分会显示,右半部分显示不出来。
2、Y轴方向的边缘检测
Gy这个卷积核会从图像的左上角,从左到右从上到下移动,每移动到一个新的位置都会按卷积核计算。在横向方向上进行加权计算。
当卷积框出现在”1“这个位置时,卷积框上侧为黑色,数值为接近0的数;卷积框下侧为白色,数值为接近255的数,卷积计算之后的值大于255正值。
当卷积框出现在”2“位置时,卷积框左右对称计算之后数值接近0,显示为黑色。
当卷积框出现在”3“位置时,卷积框上侧为白色,数值为接近255的数;卷积框下侧为黑色,数值为接近0的数,卷积计算之后的值为小于255负值。
由于负数在opencv的图像中显示不出来,所以会出现圆的上半部分会显示,下半部分显示不出来。
(2)sobel算子参数
cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
参数:
src:输入图像
ddepth: 输出图像的深度(可以理解为数据类型),-1表示与原图像相同的深度
dx,dy:当组合为dx=1,dy=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常效果不佳)
ksize:(可选参数)Sobel算子的大小,必须是1,3,5或者7,默认为3
(3)X轴方向边缘检测代码演示
目标:检测白色圆的边缘,得到一个完整的圆环。
1、显示圆的图像
yuan = cv2.imread('yuan.png')
cv2.imshow('yuan',yuan)
cv2.waitKey(0)
2、x方向上的边缘检测,即使用Gx卷积核
x方向上的边缘,包括负数信息(右端),但显示不出来,因为范围是(0~255)
yuan_x = cv2.Sobel(yuan,-1,dx=1,dy=0)
cv2.imshow('yuan_x',yuan_x)
cv2.waitKey(0)
3、 转换数据类型保存图像的负数信息
opencv读取图像默认是uint8类型,-1表示与原图像相同的深度即相同的数据类型也就是uint8类,型,使用cv2.CV_64F这个数据类型也就是float64位,将边缘检测的中遇到的负数保存下来,但是在图像中还没体现出来。
yuan_x_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=1,dy=0)#默认uint8改为float64,可保存负数
cv2.imshow('yuan_x_64',yuan_x_64)
cv2.waitKey(0)
4、x方向上的边缘,包括负数信息,进行取绝对值的操作,右端的负值信息就可以显示出来了,使用cv2.convertScaleAbs()方法
yuan_x_full = cv2.convertScaleAbs(yuan_x_64)#转换为绝对值,负数转换为正数
cv2.imshow('yuan_x_full',yuan_x_full)
cv2.waitKey(0)
(4)Y轴方向边缘检测代码演示
1、y方向上的边缘检测,即使用Gy卷积核
yuan_y = cv2.Sobel(yuan,-1,dx=0,dy=1)
cv2.imshow('yuan_y',yuan_y)
cv2.waitKey(0)
y方向上的边缘,包括负数信息(下端),但显示不出来,因为范围是(0~255)
2、 转换数据类型保存图像的负数信息,同时,y方向上的边缘,包括负数信息,进行取绝对值的操作,右端的负值信息就可以显示出来了,使用cv2.convertScaleAbs()方法
yuan_y_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
yuan_y_full = cv2.convertScaleAbs(yuan_y_64)#转换为绝对值,负数转换为正数
cv2.imshow('yuan_y_full',yuan_y_full)
cv2.waitKey(0)
(5)同时对x,y方向做边缘检测(不建议使用)
yuan_xy = cv2.Sobel(yuan,-1,dx=1,dy=1)
cv2.imshow('yuan_xy',yuan_xy)
cv2.waitKey(100000)
(6)使用图像加权运算组合x和y方向的2个边缘。
从上面的图像看出只做X轴的边缘检测左右两边是可以得到完整的圆弧,只做Y轴的边缘检测上下两侧可以得到完整的圆弧,因此我们考虑将两者加权在一起就可以得到完整的圆弧。
yuan_xy_full = cv2.addWeighted(yuan_x_full,1,yuan_y_full,1,0)
cv2.imshow('yuan_xy_full',yuan_xy_full)
cv2.waitKey(0)
(7)读取人物图像观看sobel算子效果
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)#不用灰度试试效果
zl_x_64 = cv2.Sobel(zl,cv2.CV_64F,dx=1,dy=0)#默认int8改为float64,可保存负数
zl_x_full = cv2.convertScaleAbs(zl_x_64)#转换为绝对值,负数转换为正数
zl_y_64 = cv2.Sobel(zl,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
zl_y_full = cv2.convertScaleAbs(zl_y_64)#转换为绝对值,负数转换为正数
zl_xy_sobel_full = cv2.addWeighted(zl_x_full,1,zl_y_full,1,0)
cv2.imshow('zl_xy_sobel_full',zl_xy_sobel_full)
cv2.waitKey(0)
二、Scharr 算子
(1)原理
Scharr 算子是 Soble 算子在 ksize=3 时的优化,与 Soble 的速度相同,且精度更高。Scharr 算子与 Sobel 算子的不同点是在平滑部分,其中心元素占的权重更重,相当于使用较小标准差的高斯函数,也就是更瘦高的模板。
(2)参数及代码
cv.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])
src:输入图像
ddepth:输出图片的数据深度,由输入图像的深度进行选择
dx:x 轴方向导数的阶数
dy:y 轴方向导数的阶数
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
zl_x_64 = cv2.Scharr(zl,cv2.CV_64F,dx=1,dy=0)#默认int8改为float64,可保存负数
zl_x_full = cv2.convertScaleAbs(zl_x_64)#转换为绝对值,负数转换为正数
zl_y_64 = cv2.Scharr(zl,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
zl_y_full = cv2.convertScaleAbs(zl_y_64)#转换为绝对值,负数转换为正数
zl_xy_Scharr_full = cv2.addWeighted(zl_x_full,1,zl_y_full,1,0)
cv2.imshow('zl_xy_Scharr_full',zl_xy_Scharr_full)
cv2.waitKey(0)
三、拉普拉斯算子
(1)原理
不再以x和y的方向计算,而是以圆方向计算变化率。因此不需要Gx+Gy。
2、参数及代码
cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
参数说明:
src:输入图像,可以是灰度图像,也可以是多通道的彩色图像
ddepth:输出图片的数据深度:
ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项
scale:缩放比例因子,可选项,默认值为 1
delta:输出图像的偏移量,可选项,默认值为 0
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
zl_lap = cv2.Laplacian(zl,cv2.CV_64F)
zl_lap_full = cv2.convertScaleAbs(zl_lap)#转换为绝对值,负数转换为正数
cv2.imshow('zl_lap_full',zl_lap_full)
cv2.waitKey(0)
四、canny边缘检测
(1)Canny边缘检测的优点
低错误率。因为一般的边缘检测算子可能存在检测到伪边缘的情况,因此Canny算法检测到的边缘尽可能地是真实的边缘。
较好地定位边缘点。由检测器标记的边缘点与真实边缘点中心尽可能地接近。
单一的边缘响应。图像中的边缘只标记出一次。
(2)canny边缘检测分为4个部分
1、图像降噪
图像去噪是进行边缘检测的第一步,通过去噪可以去除图像中的一些噪点,从而使边缘检测时免受噪点干扰。高斯滤波。
2、梯度计算
要进行边缘检测,就需要得到图像梯度信息,根据图像的梯度幅值和梯度方向来确定边缘,一般均采用sobel算子对图像进行梯度幅值与梯度方向计算。
根据得到的这两幅梯度图(和)找到边界的梯度和方向。
3、非极大值抑制NMS(Non-Maximal Suppression)
一阶微分在灰度值斜坡过渡时不为零且存在较粗的边缘,较粗的边缘会增大边缘检测的误差,因此需要细化边缘,一种较为常用的方法是非极大值抑制.
非极大值抑制:即在梯度图像中寻找梯度方向上的最大值作为边缘,不是梯度方向上的最大值则抑制为0。因为梯度方向是灰度变化最大的方向。比较梯度图像中每一点的灰度值与梯度方向上至少两个梯度图像像素点灰度值的大小,根据上述大小关系来确定是否保留该点的灰度值。
4、双阈值边界跟踪
双阈值处理就是根据实际情况需要设置一个灰度高阈值和一个灰度低阈值对NMS后的图像进行过滤,使得得到的边缘尽可能是真实的边缘。
双阈值的基本处理步骤为:
fH 和 fL 分别表示 大阈值和小阈值, 由用户设定
若像素点所在的边缘存在强边缘像素,则保留,否则置0
(3)参数解释及代码
cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
image 为输入图像。
threshold1 表示处理过程中的第一个阈值。fL
threshold2 表示处理过程中的第二个阈值。fH
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('zl',zl)
cv2.waitKey(0)
zl_canny = cv2.Canny(zl,100,150)#低,高
cv2.imshow('zl_canny',zl_canny)
cv2.waitKey(0)
总结:canny边缘检测的能力较强,使用简单,其他的边缘检测都是基于sobel算子的原理,都需要做处理。