OpenCV+python------【图像梯度】

前言

梯度简单理解就是求导,OpenCV提供了三种梯度滤波器,或称为高通滤波器:Sobel,Scharr,Laplacian。

Sobel,Scharr 是求一阶或二阶导数。
Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。
Laplacian 是求二阶导数。

Sobel算子

Sobel算子是高斯平滑和微分操作的结合体,它的抗噪声能力很好,可以提供比较精确的边缘方向信息,但是边缘的定位精度不高。
我们可以设定求导的方向为 x \color{red}{x } x y \color{red}{y } y,设定卷积核的大小。
在这里插入图片描述
我们使用上述3*3模板对原图像进行卷积操作(对应位置相乘然后求和)得到Gx、Gy
假设A为如下像素值矩阵:
[ P 1 P 2 P 3 P 4 P 5 P 6 P 7 P 8 P 9 ] \begin{bmatrix} P1 & P2 & P3\\ P4 & P5 & P6 \\P7 & P8 &P9 \end{bmatrix} P1P4P7P2P5P8P3P6P9

P 5 x \color{red}{P5x} P5x = ( P 3 − P 1 ) + ( 2 P 6 − 2 P 4 ) + ( P 9 − P 7 ) \color{blue}{(P3 - P1) + (2P6 - 2P4) + (P9 - P7)} (P3P1)+(2P62P4)+(P9P7)
P 5 y \color{red}{P5y} P5y = ( P 7 − P 1 ) + ( 2 P 8 − 2 P 2 ) + ( P 9 − P 3 ) \color{blue}{(P7 - P1) + (2P8 - 2P2) + (P9 - P3) } (P7P1)+(2P82P2)+(P9P3)

把得到的结果替换掉中间的像素值,按照这样的方法对图像进行遍历,提取到水平和垂直方向的边界。

Sobel函数

dst = cv2.Sobel(src, ddepth, dx, dy,ksize)

  • s r c , d s t : \color{orange}{src,dst:} src,dst 输入图像和输出图像,图像尺寸一致。
  • i n t \color{orange}{int} int d d e p t h : \color{orange}{ddepth:} ddepth输出图像的深度,针对不同的输入图像,输出目标图像有不同的深度,具体组合如下:
    若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
    若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
    若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
    若src.depth() = CV_64F, 取ddepth = -1/CV_64F
    注:ddepth =-1时,代表输出图像与输入图像相同的深度。
  • i n t \color{orange}{int} int d x : \color{orange}{dx:} dxint类型dx,x 方向上的差分阶数,1或0
    i n t \color{orange}{int} int d y : \color{orange}{dy:} dyint类型dy,y 方向上的差分阶数,1或0
    dx=1,dy=0,表示计算X方向的导数,检测出的是垂直方向上的边缘;
    dx=0,dy=1,表示计算Y方向的导数,检测出的是水平方向上的边缘。
  • i n t \color{orange}{int} int k s i z e : \color{orange}{ksize:} ksize为进行边缘检测时的模板大小为(ksize ∗ * ksize),取值为1、3、5和7,其中默认值为3。
    特殊情况:ksize=1时,采用的模板为3 ∗ * 1或1 ∗ * 3

Scharr

当ksize=3时,Sobel内核可能产生比较明显的误差,此时,可以使用 Scharr 函数,该函数仅作用于大小为3的内核(所以Scharr函数里不能自己设定卷积核大小)。它具有跟Sobel一样的速度,但结果更精确。
它的核模板为:
在这里插入图片描述
其运算法则也是跟上一个一样。

Scharr函数
dst = cv2.Scharr(src, ddepth, dx, dy)
参数含义与Sobel里面的一样,不做解释。

说明:
Sobel和Scharr是先算一个水平梯度,再算一个垂直梯度,将两个结果按照0.5的权重进行图像融合来得到完整的边界。

sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0) 
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)

Laplacian

Laplacian算子与前面的两种算子不同,它本身是一个二阶的,在水平方向运算两次,在垂直方向运行两次,两个结果相叠加替换中心点的像素值。
使用的核模板为:
在这里插入图片描述
把前面的那个像素值拿下来,假设A为如下像素值矩阵:
[ P 1 P 2 P 3 P 4 P 5 P 6 P 7 P 8 P 9 ] \begin{bmatrix} P1 & P2 & P3\\ P4 & P5 & P6 \\P7 & P8 &P9 \end{bmatrix} P1P4P7P2P5P8P3P6P9

P 5 \color{red}{P5} P5 = ( P 2 + P 4 + P 6 + P 8 ) − 4 P 5 \color{blue}{(P2 + P4 + P6 + P8)- 4P5} (P2+P4+P6+P84P5

三种算子对比结果可视化:
在这里插入图片描述
Scharr算子所获取的信息更多。

完整代码

import cv2
import numpy as np

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

img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
cv_show('img', img)

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
# 取绝对值,并将梯度图像转换成256色位图,转换为unit8类型
sobelx = cv2.convertScaleAbs(sobelx)
#cv_show('sobelx', sobelx)

# 白到黑是整数,黑到白就是负数了, 所有的负数都会截断成0,所以要取绝对值

sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)
#cv_show('sobely', sobely)


sobelxy1 = cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize=3)
sobelxy1 = cv2.convertScaleAbs(sobelxy1)
# 直接计算
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)  # 结果更好
#cv_show('sobelxy', sobelxy)

# 不同方向信息对比
# res1 = np.hstack((img, sobelx, sobely, sobelxy, sobelxy1))
# cv_show('res1', res1)

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

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

# 结果对比
res = np.hstack((img, sobelxy, scharrx, laplacian))
cv_show('res', res)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值