Opencv之图像梯度(边缘)

一、图像梯度

梯度简单来说就是求导。OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器: Sobel,Scharr 和 Laplacian。其中Sobel,Scharr 是求一阶导数。Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化,而 Laplacian 是求二阶导数。

1、Sobel算子

原理:
在这里插入图片描述前一个Sobel矩阵与原始图像A进行卷积操作后得到的是右边的像素值减去左边的像素值;后一个Sobel矩阵与原始图像A进行卷积操作后得到的是下边的像素值减去上边的像素值。
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • ddepth:图像的深度
  • dx和dy分别表示水平和竖直方向
  • ksize是Sobel算子的大小
    拿一张圆形图片举例:
    首先导入图片
img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow("img",img)
cv2.waitKey()
cv2.destroyAllWindows()

def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

在这里插入图片描述

# x方向取边缘
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
# 白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
sobelx = cv2.convertScaleAbs(sobelx)  # 也可以用 sobelx = np.absolute(gradX)
cv_show(sobelx,'sobelx')
# y方向取边缘
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely) 
cv_show(sobely,'sobely')

但是用sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)时效果并不好。
所以一般先分别计算x方向和y方向的边缘再求和。

sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  # 0表示偏置项,一般不加
cv_show(sobelxy,'sobelxy')

结果分别为:
在这里插入图片描述

2、Scharr算子

原理:
在这里插入图片描述其实就是将Sobel算子的数增大了,这样对边缘的检测更敏感。
同样用上面的图片举例:

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)   
scharry = cv2.convertScaleAbs(scharry)  
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

得到结果为:
在这里插入图片描述

3、laplacian算子

原理:
在这里插入图片描述
由G矩阵的形式可知,拉普拉斯算子只关心离中心点最近的几个边缘点。
用上面的图片举例:

laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)   

显示结果为:
在这里插入图片描述
从上面的所有结果来看,拉普拉斯算子的效果最好,另外两种算子的结果差不多,下面,用另一张比较复杂的图片做个测试,看看三种算子的效果。
原始图片:
在这里插入图片描述

#不同算子的差异
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)   
sobely = cv2.convertScaleAbs(sobely)  
sobelxy =  cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)   
scharry = cv2.convertScaleAbs(scharry)  
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)   

res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show(res,'res')

得到结果:
在这里插入图片描述

二、Canny边缘检测

原理:

  • 1、使用高斯滤波器,以平滑图像,滤除噪声。
    高斯滤波器
    在这里插入图片描述
  • 2、计算图像中每个像素点的梯度强度和方向。
    梯度和方向
    在这里插入图片描述
  • 3、应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
    非极大值抑制
    在这里插入图片描述在这里插入图片描述
  • 4、应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。

双阈值检测
在这里插入图片描述

  • 5、通过抑制孤立的弱边缘最终完成边缘检测。

用代码实现非常简单,导入图片:
在这里插入图片描述

img=cv2.imread("car.png",cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,120,250)  # 取值越大,对边缘的要求越严格
v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2))
cv_show(res,'res')

最终得到(左图的边缘明显要比右图的少,这是因为阈值过高,导致很多边缘被舍弃):
在这里插入图片描述

发布了36 篇原创文章 · 获赞 1 · 访问量 544

猜你喜欢

转载自blog.csdn.net/qq_36758914/article/details/104006560