用Python和OpenCV实现图像梯度检测与Sobel滤波操作
图像梯度
图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像的梯度计算是图像的边缘信息。
其实梯度就是导数,但是图像梯度一般通过计算像素值的差来得到梯度的近似值,也可以说是近似导数。该导数可以用微积分来表示。
在微积分中,一维函数的一阶微分的基本定义是这样的:
而图像是一个二维函数f(x,y),其微分当然就是偏微分。因此有:
因为图像是一个离散的二维函数,ϵ不能无限小,我们的图像是按照像素来离散的,最小的ϵ就是1像素。因此,上面的图像微分又变成了如下的形式(ϵ=1):
这分别是图像在(x, y)点处x方向和y方向上的梯度,从上面的表达式可以看出来,图像的梯度相当于2个相邻像素之间的差值。
那么,这个梯度(或者说灰度值的变化率)如何增强图像的清晰度呢?
我们先考虑下x方向,选取某个像素,假设其像素值是100,沿x方向的相邻像素分别是90,90,90,则根据上面的计算其x方向梯度分别是10,0,0。这里只取变化率的绝对值,表明变化的大小即可。
我们看到,100和90之间亮度相差10,并不是很明显,与一大群90的连续灰度值在一起,轮廓必然是模糊的。我们注意到,如果相邻像素灰度值有变化,那么梯度就有值,如果相邻像素灰度值没有变化,那么梯度就为0。如果我们把梯度值与对应的像素相加,那么灰度值没有变化的,像素值不变,而有梯度值的,灰度值变大了。
我们看到,相加后的新图像,原图像像素点100与90亮度只相差10,现在是110与90,亮度相差20了,对比度显然增强了,尤其是图像中物体的轮廓和边缘,与背景大大加强了区别,这就是用梯度来增强图像的原理。
上面只是说了x方向,y方向是一样的。那么能否将x方向和y方向的梯度结合起来呢?当然是可以的。x方向和y方向上的梯度可以用如下式子表示在一起:
这里又是平方,又是开方的,计算量比较大,于是一般用绝对值来近似平方和平方根的操作,来降低计算量:
原理了解后,我们来了解一些OpenCV提供了哪些梯度滤波器?
在OpenCV中,它给我们提供了三种不同的梯度滤波器,或者说高通滤波器:Sobel,Scharr 和Laplacian。什么叫高通呢?其实就是和图像模糊相反。图像模糊是让低频通过,阻挡高频,这样就可以去除噪点,让锐利的边缘变平滑。高通滤波器就是让高频通过,阻挡低频,可以让边缘更加明显,增强图像。
Sobel滤波器
Sobel滤波器是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
具体的原理如下:
将Sobel滤波器与原始图像进行卷积计算,可以计算水平方向上的像素值变化情况。例如,当Sobel滤波器的大小为3*3时,水平方向偏导数的计算方式如下:
如果需要计算P5水平方向偏导数(梯度),则公式如下:
P5x=(P3-P1)+2*(P6-P4)+(P9-P7)
如果需要计算P5垂直方向偏导数(梯度),则公式如下:
P5y=(P7-P1)+2*(P8-P2)+(P9-P3)
在OpenCV中,它给我们提供cv2.Sobel()函数实现Sobel滤波器,其函数定义如下:
def Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None):
src:原始图像
ddepth:输出图像的深度,详细取值如下表:
输入图像深度 | 输出图像深度 |
---|---|
cv2.CV_8U | -1/cv2.CV_16S/cv2.CV_32F/cv2/CV_64F |
cv2.CV_16U/cv2.CV_16S | -1/cv2.CV_32F/cv2.CV_64F |
cv2.CV_32F | -1/cv2.CV_32F/cv2.CV_64F |
cv2.CV_64F | -1/cv2.CV_64F |
dx:代表X方向的求导阶数
dy:代表Y方向的求导阶数
ksize:Sobel核的大小,该值为-1时,则会使用Sobel滤波器进行运算
scale:计算导数值所采用的缩放因子,默认值为1,时没有缩放的
delta:加载目标图像上的值,该值可选,默认为0
borderType:边界样式,前面博文有详细介绍,这里不在赘述。
需要注意的是,如果将ddepth参数设置为-1,让处理结果与原图像保持一致,可以会得到错误的结果。实际上,这么做会导致梯度值可能出现负数。如果处理的是8位图像,意味着指定运算的结果也是8位图类型,那么所有的负数会自动截断为0,发生信息丢失。为了避免信息丢失,在计算时先使用更高的数据类型cv2.CV_64F,再通过取绝对值将其映射为cv2.CV_8U类型。所以,我们使用Sobel滤波器常常会将ddepth设置为cv2.CV_64F。
计算X方向梯度语法格式为:
cv2.Sobel(src,ddepth,1,0)
计算Y方向梯度语法格式为:
cv2.Sobel(src,ddepth,0,1)
计算XY方向梯度语法格式为:
cv2.Sobel(src,ddepth,1,1)
计算XY叠加梯度语法格式为:
dx=cv2.Sobel(src,ddepth,1,0) dy=cv2.Sobel(src,ddepth,0,1) dst=cv2.addWeighted(src1,alpha,src2,beta,gamma)
因为可能会出现负数,我们还需要使用另一个函数取绝对值,该函数为:cv2.convertScaleAbs(),其完整定义如下:
def convertScaleAbs(src, dst=None, alpha=None, beta=None):
alpha:调节系数,可选值,默认为1
beta:调节亮度值,默认为0
下面,我们来使用Sobel滤波器,获取图像水平方向的边缘信息,代码如下:
import cv2 img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED) sobel_x=cv2.Sobel(img,cv2.CV_64F,1,0) result=cv2.convertScaleAbs(sobel_x) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果如下所示:
接着,我们来使用Sobel滤波器,获取图像垂直方向的边缘信息,代码如下:
import cv2 img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED) sobel_y=cv2.Sobel(img,cv2.CV_64F,0,1)#更改这一行就行 result=cv2.convertScaleAbs(sobel_y) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果如下:
接着,我们来计算XY方向梯度,代码如下:
import cv2 img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED) sobel_xy=cv2.Sobel(img,cv2.CV_64F,1,1)#都设置为1 result=cv2.convertScaleAbs(sobel_xy) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果如下:
最后,我们来计算其水平垂直两个方向的叠加边缘信息,代码如下:
import cv2 img = cv2.imread("4.jpg", cv2.IMREAD_UNCHANGED) sobel_x=cv2.Sobel(img,cv2.CV_64F,1,0) sobel_y=cv2.Sobel(img,cv2.CV_64F,0,1) abx_x=cv2.convertScaleAbs(sobel_x) abx_y=cv2.convertScaleAbs(sobel_y) result=cv2.addWeighted(sobel_x,0.5,sobel_y,0.5,0) cv2.imshow("img", img) cv2.imshow("result", result) cv2.waitKey() cv2.destroyAllWindows()
运行之后,效果如下:
到此这篇关于OpenCV-Python实现图像梯度与Sobel滤波器的文章就介绍到这了,更多相关OpenCV 图像梯度与Sobel滤波器内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
上一篇: OpenCV 图像梯度的实现方法
下一篇: 深入理解OpenCV中的图像梯度计算方法
推荐阅读
-
[姿势估计] 实践记录:使用 Dlib 和 mediapipe 进行人脸姿势估计 - 本文重点介绍方法 2):方法 1:基于深度学习的方法:。 基于深度学习的方法:基于深度学习的方法利用深度学习模型,如卷积神经网络(CNN)或递归神经网络(RNN),直接从人脸图像中学习姿势估计。这些方法能够学习更复杂的特征表征,并在大规模数据集上取得优异的性能。方法二:基于二维校准信息估计三维姿态信息(计算机视觉 PnP 问题)。 特征点定位:人脸姿态估计的第一步是通过特征点定位来检测和定位人脸的关键点,如眼睛、鼻子和嘴巴。这些关键点提供了人脸的局部结构信息,可用于后续的姿势估计。 旋转表示:常见的旋转表示方法包括欧拉角和旋转矩阵。欧拉角通过三个旋转角度(通常是俯仰、偏航和滚动)描述头部的旋转姿态。旋转矩阵是一个 3x3 矩阵,表示头部从一个坐标系到另一个坐标系的变换。 三维模型重建:根据特征点的定位结果,三维人脸模型可用于姿势估计。通过将人脸的二维图像映射到三维模型上,可以估算出人脸的旋转和平移信息。这就需要建立人脸的三维模型,然后通过优化方法将模型与特征点对齐,从而获得姿势估计结果。 特征点定位 特征点定位是用于检测人脸关键部位的五官基础部分,还有其他更多的特征点表示方法,大家可以参考我上一篇文章中介绍的特征点检测方案实践:人脸校正二次定位操作来解决人脸校正的问题,客户在检测关键点的代码上略有修改,坐标转换部分客户见上图 def get_face_info(image). img_copy = image.copy image.flags.writeable = False image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = face_detection.process(image) # 在图像上绘制人脸检测注释。 image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) box_info, facial = None, None if results.detections: for detection in results. for detection in results.detections: mp_drawing.Drawing.detection = 无 mp_drawing.draw_detection(image, detection) 面部 = detection.location_data.relative_keypoints 返回面部 在上述代码中,返回的数据是五官(6 个关键点的坐标),这是用 mediapipe 库实现的,下面我们可以尝试用另一个库:dlib 来实现。 使用 dlib 使用 Dlib 库在 Python 中实现人脸关键点检测的步骤如下: 确保已安装 Dlib 库,可使用以下命令: pip install dlib 导入必要的库: 加载 Dlib 的人脸检测器和关键点检测器模型: 读取图像并将其灰度化: 使用人脸检测器检测图像中的人脸: 对检测到的人脸进行遍历,并使用关键点检测器检测人脸关键点: 显示绘制了关键点的图像: 以下代码将参数 landmarks_part 添加到要返回的关键点坐标中。
-
用Python实现OpenCV的基本图像过滤操作:平均滤波、中值滤波、高斯滤波、高斯双边滤波及高通滤波指南
-
用Python和OpenCV实现Sobel边缘检测算法
-
玩转 Python 图像处理用OpenCV(12):罗伯茨、普瑞魏特、Sobel与拉普拉斯边缘检测算法详解
-
玩转Python OpenCV:理解图像梯度,Sobel、Scharr与Laplacian滤波器的作用
-
用Python和OpenCV实现图像梯度检测与Sobel滤波操作
-
用Python实现罗伯特、 Sobel 和拉普拉斯算子进行图像边缘详细解析与操作指南
-
玩转Python OpenCV:理解图像梯度,Sobel、Scharr与Laplacian滤波器的作用
-
用Python实现边缘检测:Robert滤波器、Sobel算法和Canny方法的实践操作
-
玩转Python OpenCV:理解图像梯度,Sobel、Scharr与Laplacian滤波器的作用