目录
图像梯度
计算的是图像变化的速度,对于图像的边缘部分,灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息
Sobel算子
原理
Sobel算子是一种离散的微分算子,结合了高斯平滑和微分求导运算,利用局部差分寻找边缘,计算所得的是一个梯度的近似值,例子如下
滤波器通常是由一幅图像根据像素点(x,y)邻近的区域计算得到另外一幅图像的新算法。因此,滤波器是由邻域及预定义的操作构成,滤波器规定滤波时所采用的形状以及该区域像素值的组成规律。滤波器也被称为“掩膜”、“核”、“模板”、“窗口”、“算子”等。一般信号邻域将其称为“滤波器”,数学领域称为“核”
计算水平方向偏导数的近似值
P5=(P3-P1)+2*(P6-P4)+(P9-P7)
下-上,其中P2和P8距离像素P5比较近,所以值为2,其余权重值为1
sobel算子函数
dst=cv2.Sobel(src,ddepth,dx,dy[,ksize[,scale[,deltal[,borderType]]]])
- dx表示x方向的求导阶数,常为0或1,最大值为2.如果为0,表示在该方向上没有求导
- dy表示y方向的求导阶数,同上,但是dy和dx不能同时为0
- scalar表示计算导数时所采用的缩放因子,默认值为1,没有缩放
- delta表示加在目标图像dst上的值,默认为0.
- ddepth表示输出图像的深度,可以设置为-1,让处理结果与原始图像保持一致,但直接设置为-1,计算时得到的结果可能是错的。实际操作中计算梯度可能会出现负值,如果处理的是8位图类型,则在ddepth的参数为-1,意味着指定运算结果也是8位图类型,那么负数会自动截断为0,发生信息丢失。为了避免信息丢失,在计算时要使用更高的数据类型cv2.CV_64F再通过取绝对值将其映射到cv2.CV_8U(8位图),所以通常将该参数设置为cv2.CV_64F
计算x方向边缘(梯度):dx=1/2,dy=0
# 计算x方向边缘梯度
img=cv2.imread("C:\photo\pie.png")
r=cv2.Sobel(img,cv2.CV_64F,1,0)
cv2.imshow("original",img)
cv2.imshow("filter2D",r)
cv2.waitKey()
cv2.destroyAllWindows()
计算y方向边缘(梯度):dx=0,dy=1
# 计算y方向边缘梯度
img=cv2.imread("C:\photo\pie.png")
r=cv2.Sobel(img,cv2.CV_64F,0,2)
cv2.imshow("original",img)
cv2.imshow("filter2D",r)
cv2.waitKey()
cv2.destroyAllWindows()
参与dx与dy的值均为1:dx=1,dy=1
#计算dx与dy方向边缘梯度
img=cv2.imread("C:\photo\pie.png")
dy=cv2.Sobel(img,cv2.CV_64F,0,1)
dx=cv2.Sobel(img,cv2.CV_64F,1,0)
dst=cv2.addWeighted(dx,0.2,dy,0.6,0)
cv2.imshow("original",img)
cv2.imshow("filter2D",dst)
cv2.waitKey()
cv2.destroyAllWindows()
直接使用cv2.Sobel(img,cv2.CV_64F,1,1)的效果很差
使用绝对值函数处理
对于A线条,右-左=-1,对于B线条:右-左=1;直接计算,因为负值会进行0截断,所以只显示B线条,计算绝对值,上述值均在8位图表示范围之内,因此可以进行显示
取绝对值函数cv2.converScaleAbs(src,[,alpha[,beta]])
- alpha代表调节系数,可选,默认为0.
- beta代表调节亮度值,该值为默认值,默认为0
将原始图像转换为256位图可以表示为:dst=saturate(src+alpha+beta)src+alpha+beta如果超过255,则取值255
#使用绝对值函数处理
img=cv2.imread("C:\photo\pie.png",cv2.IMREAD_GRAYSCALE)
r=cv2.Sobel(img,cv2.CV_64F,1,0)
r=cv2.convertScaleAbs(r)
cv2.imshow("original",img)
cv2.imshow("filter2D",r)
cv2.waitKey()
cv2.destroyAllWindows()
Scharr算子
原理
Opencv提供scharr算子,具有和sobel一样的速度,且精度更高,可以将scharr算子看做是对sobel算子的改进,其核通常为:
函数语法
dst=cv2.Scharr(src,ddepth,dx,dy[,ksize[,scale[,deltal[,borderType]]]])
在cv2.Sobel()中,如果ksize=-1,会使用scharr滤波器,即等价于Scharr算子
- ddepth的值应该设定为cv2.CV_64F
运算完应取绝对值,才能保证得到正确的结果。
计算x方向边缘(梯度):dx=1,dy=0
# 计算x方向边缘
img=cv2.imread("C:\photo\pie.png")
r=cv2.Scharr(img,cv2.CV_64F,1,0)
r=cv2.convertScaleAbs(r)
cv2.imshow("original",img)
cv2.imshow("result",r)
cv2.waitKey()
cv2.destroyAllWindows()
计算x方向边缘(梯度):dy=1,dx=0
计算y方向边缘
img=cv2.imread("C:\photo\pie.png")
r=cv2.Scharr(img,cv2.CV_64F,0,1)
r=cv2.convertScaleAbs(r)
cv2.imshow("original",img)
cv2.imshow("result",r)
cv2.waitKey()
cv2.destroyAllWindows()
计算x方向与y方向的边缘叠加
#计算dx与dy方向边缘梯度
img=cv2.imread("C:\photo\pie.png")
dy=cv2.Scharr(img,cv2.CV_64F,0,1)
dx=cv2.Scharr(img,cv2.CV_64F,1,0)
dx=cv2.convertScaleAbs(dx)
dy=cv2.convertScaleAbs(dy)
dst=cv2.addWeighted(dx,0.5,dy,0.5,0)
cv2.imshow("original",img)
cv2.imshow("result",dst)
cv2.waitKey()
cv2.destroyAllWindows()
Tip:dx和dy不能同时为1,同时为1的时候会报错
sobel和scharr算子的比较
Sobel算子的缺点是:当核结构较小时,精确度不高,而scharr算子具有恒高的精度
sobel和scharr算子的比较
img=cv2.imread("C:\photo\lena.jpg")
scharry=cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx=cv2.Scharr(img,cv2.CV_64F,1,0)
scharry=cv2.convertScaleAbs(scharry)
scharrx=cv2.convertScaleAbs(scharrx)
scharrxy=cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
Sobelx=cv2.Sobel(img,cv2.CV_64F,1,0)
Sobelx=cv2.convertScaleAbs(Sobelx)
Sobely=cv2.Sobel(img,cv2.CV_64F,0,1)
Sobely=cv2.convertScaleAbs(Sobely)
Sobelxy=cv2.addWeighted(Sobelx,0.5,Sobely,0.5,0)
cv2.imshow("original",img)
cv2.imshow("Sobelxy",Sobelxy)
cv2.imshow("scharrxy",scharrxy)
cv2.waitKey()
cv2.destroyAllWindows()
Laplacian算子
拉普拉斯算子是一种二阶导数算子,其具有旋转不变形,可以满足不同方向的图像边缘锐化(边缘检测)的要求,通常情况下,其算子的系数之和要等于0。如下:
拉普拉斯算子类似二阶sobel导数,需要计算两个方向的梯度值,中间值与周围像素点的值相差较小,得到的计算结果较小,边缘不明显;相差较大,得到的计算结果较大,边缘较明显。
函数实现
Dst=cv2.Laplacian(src,ddepth[,ksize[,scale[,delta[,borderType]]]])
#laplacian算子
img=cv2.imread("C:\photo\lena.jpg")
r=cv2.Laplacian(img,cv2.CV_64F)
r=cv2.convertScaleAbs(r)
cv2.imshow("original",img)
cv2.imshow("result",r)
cv2.waitKey()
cv2.destroyAllWindows()