前面所提到的滤波都是用于降噪的,去掉噪声,而算子是用来找边界,来识别图像的边缘。
边缘是像素值发生跃迁的值,是图像的显著特点之一,在图像特征提取,对象检测,模式识别等方面都有重要的作用。
人眼如何识别图像的边缘呢?
比如有一幅画,图里面有一条线,左边很亮,右边很暗,那人眼就很容易识别这条线作为边缘,也就是像素的灰度值快速变化的地方。
sobel算子对图像求一阶导数。一阶导数越大,说明像素在该方面的变化越大,边缘信号越强。
因为图像的灰度值都是离散的数字,sobel算子采样离散差分算子计算图像像素点亮度值的近似梯度。
差分算子是一种算子,对任一实函数f(x),若记Δf(x)=f(x+1)-f(x),则称Δ为向前差分算子,简称差分算子。
图像时二维的,即沿着宽度/高度两个方向。
我们使用卷积核对图像进行处理:
水平方向:
?
中间一列相当于f(x),第3列相当于f(x+1),第1列相当于f(x-1);相当于第3列的像素点减去第1列的像素点最后得到的就是水平方向上的近似梯度。
垂直方向:
?
中间一行相当于f(x),第3行相当于f(x+1),第1行相当于f(x-1);?相当于第3行的像素点减去第1行的像素点最后得到的就是垂直方向上的近似梯度。
综合考虑这两个方向上的变化,我们可以使用以下公式反应某个像素的梯度变化情况:
有时候为了简单起见,也可以用绝对值相加替代:
import cv2
import numpy as np
img = cv2.imread("chess.png")
# 计算x轴方向的梯度,只有垂直方向的边缘
dx = cv2.Sobel(img, cv2.CV_64F, dx=1, dy=0, ksize=3)
# 计算y轴方向的梯度,只有水平方向的边缘
dy = cv2.Sobel(img, cv2.CV_64F, dx=0, dy=1, ksize=3)
new_img = cv2.add(dx, dy)
cv2.imshow("img1", img)
cv2.imshow("img2", dx)
cv2.imshow("img3", dy)
cv2.imshow("new_img", new_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意点:
sobel算子必须分开计算x轴和y轴,不然的话效果很差。