OpenCV--033_2: 图像梯度--Sobel算子
索贝尔算子(Sobel operator)
主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。
Sobel算子是一种常用的边缘检测算子,是一阶的梯度算法;Sobel算子是结合了高斯平滑与微分运算的结合方法,所以它的抗噪声能力很强。用户可以设定求导方向,水平或者垂直(通过参数yorder和xorder)。也可以指定卷积核大小,通过参数ksize。如果ksize=-1,那么一个3*3的scharr滤波器会被使用,该滤波器会得到比Sobel滤波器更好的效果。
对噪声具有倾斜作用,提供精确的边缘信息,边缘定位精度不够高;当对精度要求不是很高时,是一种多种常用的边缘检测方法。
常见的应用和物理意义是边缘检测。
Sobel卷积因子为:
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:
具体计算如下:
其中f(a,b), 表示图像(a,b)点的灰度值;
结果: [f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)]
结果:[f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]
- 图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
通常,为了提高效率 使用不开平方的近似值:
如果梯度G大于某一阀值 则认为该点(x,y)为边缘点。
梯度方向:
Sobel提取边缘步骤:
-
高斯模糊平滑降噪
-
转灰度空间
-
求X和Y方向的梯度(求导)
Sobel(src,xsrc,CV_16S,1,0,3); Sobel(src,ysrc,CV_16S,0,1,3);
-
像素取绝对值
convertScaleAbs(A,B);//计算图像A的像素绝对值,输出到图像B -
相加X和Y,得到综合梯度,称为振幅图像。
addWeighted(A,0.5,B,0.5,0,AB);//混合权重相加,效果较差
OpenCV中的API
1. Sobel
- 函数说明
使用扩展的Sobel运算符计算第一,第二,第三或混合图像导数。 - 函数声明
void Sobel( InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT );
- 函数参数
src 输入图像。 dst 输出与src相同大小和相同通道数的图像。 ddepth 输出图像深度 dx 表示x方向上的差分阶数,1或0 。 dy 表示y 方向上的差分阶数,1或0 。 ksize 表示Sobel算子的大小;它必须是1、3、5或7。注意:只可以是小于7 的奇数。 scale 表示缩放导数的比例常数,默认情况下没有伸缩系数。 delta 表示一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中。 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时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数。
- src.depth() = CV_8U,
2. convertScaleAbs
-
函数说明
缩放,计算绝对值,然后将结果转换为8位。在输入数组的每个元素上,函数convertScaleAbs依次执行三个操作:缩放,获取绝对值,转换为无符号的8位类型:
如果是多通道阵列,该函数将独立处理每个通道。当输出不是8位时,可以通过调用Mat :: convertTo方法(或使用矩阵表达式),然后通过计算结果的绝对值来模拟该操作。 -
函数声明
void convertScaleAbs( InputArray src, OutputArray dst, double alpha = 1, double beta = 0 );
-
函数参数
src 输入数组 dst 输出数组 alpha 可选比例因子。 beta 可选增量添加到缩放值。
3. addWeighted
-
函数说明
计算两个数组的加权和。函数addWeighted计算两个数组的加权和,如下所示:
I是数组元素的多维索引。在多通道阵列的情况下,每个通道都是独立处理的。该函数可以替换为矩阵表达式:注意
当输出数组的深度为CV_32S时,不应用Saturation。在溢出的情况下,您甚至可能会得到错误符号的结果。 -
函数声明
void addWeighted( InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1 )
-
函数参数
src1 第一个输入数组 alpha 第一个数组元素的权重 src2 第二个输入数组 beta 第二个数组元素的权重 gamma 参数表示一个加到权重总和上的标量值 dst 输出数组,其大小和通道数与输入数组相同 dtype 输出数组的可选深度;当两个输入数组的深度相同时,dtype可以设置为-1,等效于src1.depth() -
应用举例
Mat src=imread("D:/test/src.jpg",0); Mat dst_x, dst_y,dst; GaussianBlur(src, dst_x, Size(3,3), 0,0); imshow("src", src); Sobel(src, dst_x, CV_16S,1, 0, 3); Sobel(src, dst_y, CV_16S,0, 1, 3); convertScaleAbs(dst_x , dst_x); convertScaleAbs(dst_y , dst_y); addWeighted(dst_x, 0.5, dst_y, 0.5,0, dst); imshow("src", src); imshow("dst_x", dst_x); imshow("dst_y", dst_y); imshow("dst", dst);
x梯度:
y梯度:
仔细观察三张图不难发现,X方向梯度在Y方向上边缘较为清晰,而Y方向梯度在X方向上边缘较为清晰,合并后的图像则综合了两张图的特征。
推荐阅读
-
OpenCV图像处理教程C++(十五)边缘检测算法--sobel算子、拉普拉斯算子、Canny算子
-
python—opencv图像膨胀|图像腐蚀|图像边缘检测sobel算子/拉普拉斯算子/canny算子
-
Opencv图像处理——边缘处理Sobel、拉普拉斯算子
-
opencv使用sobel算子提取图像的边缘信息
-
MATLAB-梯度Roberts算子、拉普拉斯算子、Sobel算子、Prewitt算子对图像进行锐化
-
Matlab采用梯度算子、拉普拉斯算子、Sobel算子及Prewitt算子对图像进行锐化
-
Python 图像处理 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子边缘检测技术
-
荐 opencv学习笔记15: 梯度运算之sobel算子及其函数使用
-
OpenCV--033_2: 图像梯度--Sobel算子
-
荐 opencv学习笔记15: 梯度运算之sobel算子及其函数使用