这里介绍三种边缘检测的方法, Sobel算子(索贝尔算子), Laplacian算子(拉普拉斯算子) 和 Canny算子 的边缘检测。
一、Sobel算子
Sobel算子在一阶偏导
上检测边缘,且能在水平(x 方向)和竖直(y 方向)分别作用。直观上,Sobel寻找这样的边缘:中间灰度值特别大,两边很小,即像素值出现跳跃的现象。我们可以通过求梯度值来确定。
x 和 y 两个方向的核函数如下:
????1?2?1000+1+2+1???(Gx)
???+10?1+20?2+10?1???(Gy)
若要同时考虑两个方向,则用
|G|=(Gx)2+(Gy)2????????????√2
或者为了方便,直接用绝对值的和
|G|=|Gx|+|Gy|
核函数和图像的卷积过程,其实是梯度的一个近似,从核函数的结构上可以看出来。注意Kernel的大小需是奇数。
二、Laplacian算子
Laplacian算子偏重在二阶导数
上寻找边缘。因为前面讲到的Sobel算子,其中边缘的一阶导数的极大值时,往往伴随着二阶导数取 0 的情况。
Laplacian算子定义如下:
Laplacian(f)=?2f?x2+?2f?y2
三、代码示例
代码示例如下,展示【原图】,【Sobel算子】,【x方向】,【y方向】,和【Laplacian算子】后的效果。
import cv2
# 读入并转化成灰度图
img = cv2.imread("1.jpg", 0)
# 加特效!
sobel = cv2.Sobel(img, cv2.CV_8U, 1, 1, ksize = 5)
sobel_x = cv2.Sobel(img, cv2.CV_8U, 1, 0, ksize = 5)
sobel_y = cv2.Sobel(img, cv2.CV_8U, 0, 1, ksize = 5)
laplacian = cv2.Laplacian(img, cv2.CV_8U)
# 创建窗口
cv2.namedWindow("origin", cv2.WINDOW_NORMAL)
cv2.namedWindow("sobel x", cv2.WINDOW_NORMAL)
cv2.namedWindow("sobel y", cv2.WINDOW_NORMAL)
cv2.namedWindow("sobel", cv2.WINDOW_NORMAL)
cv2.namedWindow("laplacian", cv2.WINDOW_NORMAL)
# 显示
cv2.imshow("origin", img)
cv2.imshow("sobel x", sobel_x)
cv2.imshow("sobel y", sobel_y)
cv2.imshow("sobel", sobel)
cv2.imshow("laplacian", laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
四、Canny算子
Canny算子像Sobel算子那样,也有两个方向的核函数,不同的是,Canny会组合成四个方向的导数,每个方向达到局部最大值才能是边缘的候选点。
Canny算法有两个阈值,设小的阈值为 t1, 大的阈值为 t2,
若小于小的阈值,即 t<t1,直接抛弃;
若大于大的阈值,即 t>t2,则直接判定为边缘像素;
若是处于中间,t1<t<t2,则必须和确定的边缘像素(大于最大阈值)相连才能进一步判断为边缘像素。
代码示例,创建一个滑动条,可以动态改变两个阈值
import cv2
threshold_one = 100
threshold_two = 200
# 下阈值改变
def refresh_x(x):
global threshold_one
threshold_one = x
refresh()
# 上阈值改变
def refresh_y(y):
global threshold_two
threshold_two = y
refresh()
# 刷新Canny检测
def refresh():
global threshold_one
global ghreshold_two
print ‘x = %d, y = %d‘ %(threshold_one, threshold_two)
canny = cv2.Canny(blur, threshold_one, threshold_two)
cv2.imshow("canny", canny)
# 读入并转成灰度图
img = cv2.imread("1.jpg", 0)
# 高斯模糊,减少噪点
blur = cv2.GaussianBlur(img, (5, 5), 0)
# 检测边缘
canny = cv2.Canny(blur, 100, 200)
# 创建窗口
cv2.namedWindow("origin", cv2.WINDOW_NORMAL)
cv2.namedWindow("canny", cv2.WINDOW_NORMAL)
# 创建进度条
cv2.createTrackbar("threhold one: ", "canny", 0, 255, refresh_x)
cv2.createTrackbar("threhold two: ", "canny", 0, 255, refresh_y)
# 显示
cv2.imshow("origin", img)
cv2.imshow("canny", canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
限于篇幅,图片效果就不放出来了。
版权声明:本文为博主原创文章,未经博主允许不得转载。