1.图像边缘检测
图像边缘检测对于分析图像中的内容、实现图像中物体的分割、定位等具有重要的作用。边缘检测大大减少了源图像的数据量,剔除了与目标不相干的信息,保留了图像重要的结构属性。常用的图像边缘检测方法分为以下两种:
- 一阶导数的边缘算子:
通过模板作为核与图像的每个像素点做卷积和运算,然后选取合适的阈值来提取图像的边缘。代表算子为sobel、scharr算子。 - 二阶导数的边缘算子:
通过求取二阶导数为0来寻找边界,代表laplacian算子。
2.Sobel算子
2.1Sobel算子原理:
sobel算子需要先将图像转为灰度图,然后通过图像平滑操作,进行过滤噪声,然后使用sobel算子。 转化为灰度图像后用图像与卷积因子进行卷积运算。分别得到x方向和y方向的梯度值。 分别求水平Gx和竖直方向的导数Gy。 再求出该点整体的导数。得到该点的导数的方法有很多,可以用平方根的方式,或者绝对值求和等。下面展示平方根的方法。 得到的G可以与设定的阈值进行比较,如果大于某一阈值,可以认为该点为边缘点。
2.2代码实现
自定义sobel边缘检测算法:
def calculate_Sobel(img, threshold):
height,width = img.shape[::-1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = sum(sum(G_x * img[i:i + 3, j:j + 3]))
h = sum(sum(G_y * img[i:i + 3, j:j + 3]))
result[i + 1, j + 1] = np.sqrt((v ** 2) + (h ** 2))
for i in range(0, width):
for j in range(0, height):
if result[i, j] < threshold:
result[i, j] = 0
return result
2.3API接口
cv.Sobel(src,depth,dx,dy,dst,ksize,scale,delta,borderType)
src:传入的图像 ddepth:图像的深度 dx dy:指求导的阶数。0表示这个方向上没有求导,取值为0、1。 ksize:指Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7,默认为3。 注意:如果ksize = -1,就演变为3*3的Scharr算子。 scale:缩放导数的比例常数,默认情况为没有伸缩系数。 borderType:图像边界的模式,默认cv2.BORDER_DEFAULT。 注:Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted()函数将其组合起来.
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
Scale_absX = cv2.convertScaleAbs(x)
Scale_absY = cv2.convertScaleAbs(y)
result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
3.Laplacian算子
3.1laplacian算子原理
对x和y的二阶求偏导相加 因此,laplacian算子的卷积核如下。还是用图像与卷积核相乘。该点的梯度值就是周围的值相加 - 中心值的四倍。
3.2代码实现
def calculate_laplacian(img):
temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
height, width = img.shape[::-1]
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
result[i + 1][j + 1] = np.abs(sum(sum(temLaplacian * img[i:i + 3, j:j + 3])))
return result
API接口:
cv.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
ddepth:输出图片的数据深度 dst:输出图像,大小和类型与 src 相同 ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项 scale:缩放比例因子,可选项,默认值为 1 delta:输出图像的偏移量,可选项,默认值为 0 borderType:边界扩充的类型,注意不支持对侧填充(BORDER_WRAP)
4.Canny算子
Canny算子在检测算法中比较优秀。该算法的步骤如下: 1.高斯平滑进行降噪 2.计算梯度强度和方向。采用的是sobel算子 3.非极大值抑制。通常灰度变化的地方都比较集中,将局部范围内的梯度方向上,灰度变化最大的保留下来,其它的不保留,这样可以剔除掉一大部分的点。将有多个像素宽的边缘变成一个单像素宽的边缘。即“胖边缘”变成“瘦边缘”。 4.双阈值筛选。通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(low),高阈值(high)。灰度变化大于high的,设置为强边缘像素,低于low的,剔除。在low和high之间的设置为弱边缘。进一步判断,如果其领域内有强边缘像素,保留,如果没有,剔除。
Api接口如下:
Canny(image, th1, th2, edges=None, apertureSize=None, L2gradient=None)
image参数表示8位输入图像。 threshold1参数表示设置的低阈值。 threshold2参数表示设置的高阈值,一般设定为低阈值的3倍 (根据Canny算法的推荐)。 edges参数表示输出边缘图像,单通道8位图像。 apertureSize参数表示Sobel算子的大小
blur = cv.GaussianBlur(image, (3, 3), 0)
edge_output = cv.Canny(img, 50, 150)
5.总结
Laplacian算子对噪声比较敏感,由于其算法可能会出现双像素边界,常用来判断边缘像素位于图像的明区或暗区,很少用于边缘检测;Sobel算子考虑了综合因素,对噪声较多的图像处理效果更好。canny算子效果比较好,对于噪声比较敏感,结合几种不同算子的优点衍生而来。
|