目录
- 图像梯度介绍
- 图像梯度的原理
- OpenCV中图像梯度方法
(1) Sobel和Scharr算子
(2) Laplacian 算子
(3) 自定义核函数通过fiter2D实现 - 相关知识补充
图像梯度介绍
图像梯度可以把图像看成二维离散函数,图像梯度其实就是这个二维离散函数的求导
在图像上表现出来的就是提取图像的边缘(无论是横向的、纵向的、斜方向的等等)
图像梯度原理
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。