注意:梯度计算总是由右边减去左边
目录
一、边缘检测原理
边缘检测是图像处理和计算机视觉当中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点,用于确定图片中物体的边界(边缘)或者区域,边缘检测可以大幅减小数据量并且剔除不相关问题
边缘检测前,我们一般要先进行滤波对图像进行平滑处理。这是为了去除图片中的噪声。在边缘检测中,需要对像素亮度进行数值求导,结果会产生带有噪声的边缘。换而言之,图像中的相邻像素的亮度(特别是在边缘附近)波动比较大的噪音会被我们当成边界,但并不是我们寻找的主要边缘结构。
有许多方法用于边缘检测,他们的绝大部分可以划分为两类:基于搜索和基于零穿越。
对图一的图片进行边缘检测 图二就是基于搜索 图三是基于领穿越
(1)基于搜索∶通过寻找图像一阶导数中的最大值来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值。
(2)基于零穿越:通过寻找图像二阶导数零穿越来寻找边界。
二、Sobel算子(基于搜索)
本质是梯度运算
Sobel算子要同时计算图像x方向和y方向的卷积结果
结合x方向和y方向求出:
可以简化为:
具体卷积步骤:
对于一张5 * 6的图像,用Sobel算子卷积核来进行卷积:
深度学习中对于原图像中无法计算的边界像素点的计算:将原图像用0像素点扩展成一张7 * 8的图像:
具体例子:对于 (2, 1) 的像素点x轴的梯度计算:255 * -1 + 155 * 0 + 215 * 1 + 65 * -2 + 255 * 0 + 255 * 2 + 255 * -1 + 155 * 0 + 215 * 1 所得结果即
G
x
G_{x}
Gx
Sobel特点:对效率要求较高 但是不太关注细纹理
Opencv API:
gray_x_or_y = cv.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
输入:
1.src:传入的图像;
2.ddepth:图像的深度;
3.dx 和 dy: 分别代表所用的 Sobel 算子的 x 和 y 方向的偏导数。
4.dst:函数的输出结果存储在 dst 中
5.ksize:指Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7,默认为3。注意:如果ksize = -1,就演变为3*3的Scharr算子。
6.scale:缩放导数的比例常数,默认情况为没有伸缩系数。
7.borderType:图像边界的模式,默认cv2.BORDER_DEFAULT。
输出:
Sobel_x, Sobel_y: 图像在x轴或y轴所得梯度计算结果
注意:
(1)由于梯度计算总是由右边减去左边 所以可能所得结果中存在负数以及大于255的数,而原图像为uint8数据类型(8位无符号数),Sobel建立的图像位数不够,所以要进行数据类型转换,处理完数据后再使用cv2.convertScaleAbs()函数将其转回原来的uint8格式,不然图像无法显示(cv2.convertScaleAbs()用于将图像数组进行线性变换并将结果转换为无符号8位整数类型。它通常用于图像对比度和亮度的调整。)
(2)Sobel算子求出来的是一个方向的梯度 最后还要用cv2.addWeighted()函数对所得x方向和y方向的结果相组合
gray_absX = cv2.convertScaleAbs(gray_x) #格式转换
gray_absY = cv2.convertScaleAbs(gray_y)
result_sobel = cv2.addWeighted(gray_absX, alpha, gray_absX, beta, C) #图像融合
代码:
gray_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize = 3)
gray_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize = 3)
gray_absX = cv2.convertScaleAbs(gray_x)
gray_absY = cv2.convertScaleAbs(gray_y)
result_sobel = cv2.addWeighted(gray_absX, 0.5, gray_absX, 0.5, 0)
三、Laplacian算子(基于零穿越)
使用拉普拉斯算子边缘处理可以对图像进行锐化处理,突出图像亮度快速变化的区域,提高图像的视觉效果。但是对噪声敏感,适合用于无噪声图像,使用该算子进行边缘处理前先使用高斯滤波平滑掉噪声
拉普拉斯卷积核:
Opencv API:
cv2.Laplacian(src, ddepth, dst, ksize, scale, delta, borderType)
输入:
src:输入的图像
ddepth:图像深度。-1表示采用与原图像相同的深度,目标图像的深度必须大于等于原图像的深度。
ksize:算子的大小,即卷积核的大小,必须为1,3,5,7,默认为3。
scale:缩放导数的比例常数,默认情况为没有伸缩系数。
borderType:图像边界的模式,默认cv2.BORDER_DEFAULT。
代码:
gray_la = cv2.Laplacian(gray, cv2.CV_64F)
result_laplacian = cv2.convertScaleAbs(gray_la)
四、Canny边缘检测算法
Canny边缘检测是当今最流行的也是目前公认最优的边缘检测算法。
该算法共分为四部分:
1. 消除噪声;
2. 计算图像的亮度梯度值;
3. 减除虚假边缘;
4. 双阈值筛选边界;
1.消除噪声
使用高斯滤波器可以去除大部分噪声,或者尽量减少不必要的图像细节产生不必要的边缘。 图像平滑处理
2. 计算图像的亮度梯度值
对高斯滤波平滑后的图像使用Sobel算子计算水平和竖直方向的一阶导数,从而求出边界的梯度和方向
梯度方向被分为四类:竖直、水平以及两对角线方向
3.减除虚假边缘(非极大值抑制NMS)
通过比较每个像素与周围像素在水平和垂直两个方向上的梯度值来实现剔除虚假边缘。如果一个像素对应的梯度在局部是最大的,也就是比他的上下左右像素梯度都大,它就保留下来。否则将就该像素置为0.
4. 双阈值筛选边界
通过双阈值筛选真正的边界 高于maxVal的边界称为边界 梯度值位于(minVal, maxVal)的边界称为若边界 进一步筛选 若与边界连通则处理为边界 否则舍弃
Opencv API:
dst = cv2.Canny(image, threshold1, threshold2)
输入:
image:输入的灰度图
threshold1:minVal,较小的阈值将间断的边缘连接起来。
threshold2:maxVal,较大的阈值检测图像中明显的边缘。
输出:
边缘处理后所得图像
代码:
result_candy = cv2.Canny(gray, 0, 160)