1. 简介
Sobel算子利用一个横轴方向的算子和纵轴方向的算子,分别求得图像的亮度差分,再计算平方和或者绝对值之和,得到近似梯度(即最后的结果)。
横轴方向的算子为:
纵轴方向的算子为:
(注意:这里正负号在左边还是右边并无影响,因为最后计算的时候会取左右或者上下之差的绝对值)
以a13点为例,
可得:Gx = (a9 - a7) + 2 * (a14 - a12) +(a19 - a17)
一般会将其简化为:
所以:G = |Gx| + |Gy| = |(a9 - a7) + 2 * (a14 - a12) +(a19 - a17) | + |(a19 - a9) +2 * (a18 - a8) +(a17 - a7)|
3. 代码
现在有图片ten.jpg,如下图所示:
代码如下:
import cv2
img = cv2.imread('ten.jpg', 0)
img = cv2.resize(img, (300, 500))
_, img = cv2.threshold(img, 180, 250, 0)
# 只计算纵轴方向结果
sobel_y = cv2.Sobel(img, -1, 0, 1)
cv2.imshow('sobel_y', sobel_y)
# 只计算横轴方向结果
sobel_x = cv2.Sobel(img, -1, 1, 0)
cv2.imshow('sobel_x', sobel_x)
# 同时计算x,y轴方向结果
sobel_xy = cv2.Sobel(img, -1, 1, 1)
cv2.imshow('sobel_xy', sobel_xy)
# 清除窗口
cv2.waitKey()
cv2.destroyAllWindows()
输出结果如下图所示:
从上述结果中发现,直接在x,y轴上调用cv2.Sobel并不能得到满意的结果。
改进方法:分别计算x轴,y轴的近似梯度,在加权求和。
改进代码如下:
import cv2
img = cv2.imread('ten.jpg', 0)
img = cv2.resize(img, (300, 500))
_, img = cv2.threshold(img, 180, 250, 0)
x = cv2.Sobel(img, cv2.CV_64F, 1, 0)
x = cv2.convertScaleAbs(x)
y = cv2.Sobel(img, cv2.CV_64F, 0, 1)
y = cv2.convertScaleAbs(y)
z = cv2.addWeighted(x, 0.5, y, 0.5, 0)
cv2.imshow('z', z)
cv2.waitKey()
cv2.destroyAllWindows()
1. 简介
Scharr算子跟Sobel类似,只不过它的算子系数如下所示:
import cv2
img = cv2.imread('ten.jpg', 0)
img = cv2.resize(img, (300, 500))
_, img = cv2.threshold(img, 180, 250, 0)
x = cv2.Scharr(img, cv2.CV_64F, 1, 0)
x = cv2.convertScaleAbs(x)
y = cv2.Scharr(img, cv2.CV_64F, 0, 1)
y = cv2.convertScaleAbs(y)
z = cv2.addWeighted(x, 0.5, y, 0.5, 0)
cv2.imshow('Scharr', z)
cv2.waitKey()
cv2.destroyAllWindows()
输出结果如下所示:
注意:调用Scharr算子不能跟Sobel算子一样,同时在横轴和纵轴方向算出结果,必须满足条件 dx >= 0 && dy >= 0 && dx+dy == 1,例如:x = cv2.Scharr(img, cv2.CV_64F, 1, 1) 这样调用就会报错。
1. 简介
拉普拉斯算子,如下所示:
可以看出,拉普拉斯的计算其实就是取中心点跟它相邻的四个点作差,包括横轴和纵轴方向,它在左右方向上算了两次,在上下方向上也算了两次,因此它是二阶的。
2. 代码
import cv2
img = cv2.imread('ten.jpg', 0)
img = cv2.resize(img, (300, 500))
_, img = cv2.threshold(img, 180, 250, 0)
z = cv2.Laplacian(img, cv2.CV_64F)
cv2.imshow('Laplacian', z)
cv2.waitKey()
cv2.destroyAllWindows()
输出结果如下所示:
可以看到,拉普拉斯算子的调用也是比较简单的,只要一句话就能运行出结果。
1. 简介
Canny算子相比Sobel而言,要稍微复杂一点,它的计算步骤可以总结为以下4点:
1.1 去噪
一般用高斯滤波。高斯滤波的介绍可以我前面写的博文:https://blog.csdn.net/weixin_43508499/article/details/107904998
1.2 计算梯度和方向
1.3 非极大值抑制
1.4 滞后阈值
二次判断,设置最小阈值minV和最大阈值maxV:
如果计算出来的梯度小于minV,则将其抛弃,
如果计算出来的梯度大于maxV,则将其保留
如果计算出来的梯度在 minV~maxV之间,就分两种情况考虑:
———如果该点与边缘相连,则保留;
———如果该点与边缘不相连,则抛弃。
对于阈值,如果设置的越小,保留的细节更丰富。
2. 代码
import cv2
img = cv2.imread('ten.jpg', 0)
img = cv2.resize(img, (300, 500))
_, img = cv2.threshold(img, 180, 250, 0)
canny = cv2.Canny(img, 100, 200)
cv2.imshow('canny', canny)
cv2.waitKey()
cv2.destroyAllWindows()
可以看到,相比于Sobel计算的边缘,用Canny计算出来的结果边缘更细,没有那么粗大明亮。