opencv_图像梯度

目录

  1. 图像梯度介绍
  2. 图像梯度的原理
  3. OpenCV中图像梯度方法
    (1) Sobel和Scharr算子
    (2) Laplacian 算子
    (3) 自定义核函数通过fiter2D实现
  4. 相关知识补充
图像梯度介绍

图像梯度可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导
在图像上表现出来的就是提取图像的边缘(无论是横向的、纵向的、斜方向的等等)

图像梯度原理

图像梯度原理介绍

Sobel和Scharr算子

Sobel是普通一阶差分,是基于寻找梯度强度。 图像中边缘区域,像素值会发生‘跳跃’,对这些像素求导,在其一阶导数在边缘位置时为极值,这就是sobel算子使用的原理–极值处就是边缘
每一个算子分别对应这x和y这两个方向的模板,算子模板为:
在这里插入图片描述
将两个梯度为合并:
在这里插入图片描述
为简化算,用绝对值代替,最终梯度为

Sobel算子是结合了高斯平滑与微分运算的结合方法,所以它的抗噪声能力很强,

代码示例
import cv2 as cv
import numpy as np

def sobel_demo(image):
    grade_x = cv.Sobel(image, cv.CV_32F, 1, 0)  #获取水平方向的梯度,对x进行一阶求导,cv.CV_32F,防止位数不够,出现截断或者溢出
    grade_y = cv.Sobel(image, cv.CV_32F, 0, 1)  #获取y轴方向的梯度
    gradex = cv.convertScaleAbs(grade_x)  #对其取绝对值,并转换成uint8形式
    gradey = cv.convertScaleAbs(grade_y)
    cv.imshow("grade_x", gradex)
    cv.imshow("grade_y", gradey)
    grade = cv.addWeighted(gradex, 0.5, gradey, 0.5, 0) #对图片进行融合
    cv.imshow("grade", grade)

print("----------------hello python opencv---------------------")
src = cv.imread("D:/pyhton/PhotoIditifyStuday/photo/manhua.jpg") #读取原图片
cv.namedWindow("input_image", cv.WINDOW_AUTOSIZE)
cv.imshow("input_image", src)
sobel_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
在调用滤波函数时,会遇到一个问题,从黑到白的边界导数是正数,白到黑是负数,所以sobel函数求完导数后会有负值,还会有大于255的值。而原图像是uint8,即8位无符号数,所以图像位数不够,会出现截断。要用更高的数据类型,cv.CV_16S,cv._CV_32F等

在OpenCV函数中,在sobel算子的基础上还有一种Scharr算子,可以获取更强的边缘检测算子模板为:
在这里插入图片描述
scharr算子相当于sobel的加强版,不过这样其抗噪能力就会减弱

代码示例
 grade_x = cv.Scharr(image, cv.CV_32F, 1, 0)  #获取水平方向的梯度,对x进行一阶求导,cv.CV_32F防止计算后数据溢出
 grade_y = cv.Scharr(image, cv.CV_32F, 0, 1)  #获取y轴方向的梯度

在这里插入图片描述

拉普拉斯算子

拉普拉斯实现的算法是在sobel的基础上,再求导,即对图像求二阶导
在这里插入图片描述
核模板:
在这里插入图片描述

在经过处理后,不能忘记用convertScaleAbs()函数将其转回原来的uint8类型。否则将无法显示图像,而只是一幅灰色的窗口。

代码示例
def laplacian_demo(image):
    lapl = cv.Laplacian(image, cv.CV_32F)
    dst = cv.convertScaleAbs(lapl)
    cv.imshow("laplacian", dst)


print("----------------hello python opencv---------------------")
src = cv.imread("D:/pyhton/PhotoIditifyStuday/photo/manhua.jpg") #读取原图片
cv.namedWindow("input_image", cv.WINDOW_AUTOSIZE)
cv.imshow("input_image", src)
laplacian_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
自定义核函数通过fiter2D实现

def laplacian_demo(image):
    kernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    dst = cv.filter2D(image, cv.CV_32F, kernel=kernel)
    lapl = cv.convertScaleAbs(dst)
    cv.imshow("laplaciam", lapl)

def laplacian_plus(image):
    kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
    dst = cv.filter2D(image, cv.CV_32F, kernel=kernel)
    lapl = cv.convertScaleAbs(dst)
    cv.imshow("laplaciam_plus", lapl)


print("----------------hello python opencv---------------------")
src = cv.imread("D:/pyhton/PhotoIditifyStuday/photo/manhua.jpg") #读取原图片
cv.namedWindow("input_image", cv.WINDOW_AUTOSIZE)
cv.imshow("input_image", src)
laplacian_demo(src)
laplacian_plus(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

相关知识补充

(1) Sobel

Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)

src参数表示输入需要处理的图像。

ddepth参数表示输出图像深度,针对不同的输入图像,输出目标图像有不同的深度。

具体组合如下:
  src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F (一般源图像都为CV_8U,为了避免溢出,一般ddepth参数选择CV_32F)
  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时,代表输出图像与输入图像相同的深度。
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2
其后是可选的参数:
dst参数表示输出与src相同大小和相同通道数的图像。
ksize参数表示Sobel算子的大小,必须为1、3、5、7。
scale参数表示缩放导数的比例常数,默认情况下没有伸缩系数。
delta参数表示一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中。
borderType表示判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。

(2) convertScaleAbsl

convertScaleAbs(src, dst=None, alpha=None, beta=None)

OpenCV的convertScaleAbs函数将数组转为取绝对值并转换 uint8

src参数表示原数组。
dst参数表示输出数组 (深度为 8u)。
alpha参数表示比例因子。
beta参数表示原数组元素按比例缩放后添加的值

(3) addWeighted

addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None)

OpenCV的addWeighted函数是计算两个数组的加权和
rc1参数表示需要加权的第一个输入数组。

alpha参数表示第一个数组的权重。
src2参数表示第二个输入数组,它和第一个数组拥有相同的尺寸和通道数。
beta参数表示第二个数组的权重。
gamma参数表示一个加到权重总和上的标量值。
dst参数表示输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
dtype参数表示输出数组的可选深度。当两个输入数组具有相同的深度时,这个参数设置为-1(默认值)

(4) Laplacian

Laplacian(src, ddepth, dst=None, ksize=None, scale=None, delta=None, borderType=None)

ddepth参数表示输出图像深度,针对不同的输入图像,输出目标图像有不同的深度。
dst参数表示输出与src相同大小和相同通道数的图像。
ksize参数表示用于计算二阶导数滤波器的孔径大小,大小必须是正数和奇数。,可以通过修改ksize大小来修改算子,ksize默认是1,为4卷积核,3是8卷积核,可以向上加,边缘梯度检测越明显
scale参数表示计算拉普拉斯算子值的比例因子,默认情况下没有伸缩系数。
delta参数表示一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中。
borderType表示判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章