OpenCV-Python-图像梯度与边缘检测
Posted 墨麟非攻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV-Python-图像梯度与边缘检测相关的知识,希望对你有一定的参考价值。
图像梯度
我们知道一阶导数可以用来求极值。把图片想象成连续函数,因为边缘部分的像素值与旁边的像素明显有区别,所以对图片局部求极值,就可以得到整幅图片的边缘信息。不过图片是二维的离散函数,导数就变成了差分,这个查分就变成了图像梯度。
1. 垂直边缘提取
滤波是应用卷积来实现的,卷积的关键就是卷积核。我们来考察下面这个卷积核:
这个核是用来提取图片中的垂直边缘的,怎么做到的呢?看下图:
当前列左右两侧的元素进行差分,由于边缘的值明显小于(或大于)周边像素,所以边缘的差分结果会明显不同,这样就提取出垂直边缘。同理,把上面的那个矩阵转置一下,就是提取水平边缘。这种差分操作就成为图像的梯度计算:
import cv2 import numpy as np img = cv2.imread(\'sudoku.jpg\', 0) # 自己进行垂直边缘提取 kernel = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=np.float32) dst_v = cv2.filter2D(img, -1, kernel) # 自己进行水平边缘提取 dst_h = cv2.filter2D(img, -1, kernel.T) # 横向并排对比显示 cv2.imshow(\'edge\', np.hstack((img, dst_v, dst_h))) cv2.waitKey(0)
2. Sobel算子
上面这种差分方法就叫Sobel算子,它先在垂直方向上计算梯度 Gx = k1 x src,再在水平方向计算梯度Gy = k2 x src,最后求出总梯度:
我们可以把前面的代码用Sobel算子更简单的实现:
sobelx = cv2.Sobel(img, -1, 1, 0, ksize=3) # 只计算x方向 sobely = cv2.Sobel(img, -1, 0, 1, ksize=3) # 只计算y方向 # 横向并排对比显示 cv2.imshow(\'edge\', np.hstack((img, sobelx, sobely))) cv2.waitKey(0)
还有其他算子,比如只利用领域间的原始差值来检测边缘的Prewitt算子
还有比Sobel更好用的Scharr算子
这些算法都是一阶边缘检测的代表。
3. Laplacian算子
高数中用一阶导数求极值,在这些极值的地方,二阶导数为0,所以也可以求二阶导计算梯度:
一维的一阶和二阶差分公式分别为:
提取前面的系数,那么一维的Laplacian的滤波核是:
对于二维函数f(x,y),两个方向的二阶差分分别是:
合在一起:
同样提取前面的系数,那么二维的Laplacian滤波核就是:
这就是 Laplacian 算子的图像卷积模板,有些资料在此基础上考虑斜对角情况,将卷积核扩展为:
laplacian = cv2.Laplacian(img, -1) # 横向并排对比显示 cv2.imshow(\'edge\', np.hstack((img, laplacian))) cv2.waitKey(0)
Laplacian算子是二阶边缘检测的典型代表。
参考地址:http://ex2tron.wang/opencv-python-extra-image-gradients/
以上是关于OpenCV-Python-图像梯度与边缘检测的主要内容,如果未能解决你的问题,请参考以下文章
3. OpenCV-Python——图像梯度算法边缘检测图像金字塔与轮廓检测直方图与傅里叶变换
opencv-python图像处理 ----图像梯度Sobel算子