OpenCV中的边缘检测——Sobel滤波器

一、原理 

Sobel算子是一种用于边缘检测的线性滤波器,它基于两个简单的3\times3的内核,如下图:

OpenCV中的边缘检测——Sobel滤波器_第1张图片

 如果把图像看做是一个二维函数,那么Sobel算子就是图像在垂直和水平方向上变化的速度(即梯度)。它是一个二维向量,向量的元素是横竖两个方向的函数一阶导数:

grad\left ( I \right )=\left [ \frac{\partial I}{\partial x},\frac{\partial I}{\partial y}\right ]^{T}

Sobel算子在水平和垂直方向上做像素值的差分,能够得到图像梯度的近似值,在像素周围进行运算时,能够减少噪声带来的影响。OpenCV中的Sobel函数如下:

cv::Sobel(image, // 输入
          sobel, // 输出
          image_depth, // 图像类型
          xorder,yorder, // 内核规格
          kernel_size, // 正方形内核的尺寸
          alpha, beta); // 比例和偏移量

此函数中,输出图像的像素类型是可以选择的:无符号字符型、有符号整数或浮点数。如果结果超出了像素值域的范围,就会进行饱和度运算,在生成最终图像之前,可以将结果缩放(相乘)alpha倍,并加上偏移量beta。

每个Sobel 掩码都是一个方向上的导数,因此要用两个参数来指明将要应用的内核,即x方向和y 方向导数的阶数。例如,如果xorder和yorder分别为1 和0,则得到水平方向Sobel内核;如果分别是0和1,则得到垂直方向的内核。内核的尺寸也可以大于3×3。可选的尺寸有1、3、5 和7。内核尺寸为1,表示一维Sobel 滤波器(1×3 或3×1)。

二、实验过程

 1、对图像分别做X轴和Y轴的滤波

在这个实验中,选择输出的图像类型是8位的输出图像(CV_8U)

cv::Mat sobelX;//水平方向结果
cv::Mat sobelY;//垂直方向结果
//Sobel滤波器
cv::Sobel(image, sobelX, CV_8U, 1, 0, 3, 0.4, 128);//水平方向上的滤波器
cv::Sobel(image, sobelY, CV_8U, 0, 1, 3, 0.4, 128);//垂直方向上的滤波器
cv::imshow("Sobel_X", sobelX);
cv::imshow("Sobel_Y", sobelY);

水平方向上Sobel算子结果

OpenCV中的边缘检测——Sobel滤波器_第2张图片

垂直方向上Sobel算子结果

OpenCV中的边缘检测——Sobel滤波器_第3张图片

 这两种效果看上去和浮雕特效很像。

2、组合垂直和水平方向的结果,计算Sobel的范数

因为梯度是一个二维向量,所有它有范数和方向,梯度向量的范数表示变化的振幅,计算时通常被当作是欧几里得范数(也称L2范数):

\left | grad\left ( I \right ) \right |=\sqrt{\left ( \frac{\partial I}{\partial x} \right )^{2}+\left ( \frac{\partial I}{\partial y} \right )^{2}}

但是在图像处理领域,通常把绝对值之和作为范数进行计算(成为L1范数),他的结果和L2范数结果接近,且计算速度快。

cv::Mat sobelX;//水平方向结果
cv::Mat sobelY;//垂直方向结果
cv::Mat sobel;
cv::Sobel(image, sobelX, CV_16S, 1, 0);
cv::Sobel(image, sobelY, CV_16S, 0, 1);
sobel = abs(sobelX) + abs(sobelY);//计算L1范数
cv::imshow("Sobel", sobel);

结果图:

OpenCV中的边缘检测——Sobel滤波器_第4张图片

3、将第2步的sobel图像转换为8位图像

在convertTo方法中使用可选的缩放参数可得到一幅图像,图像中白色用0表示,更黑的灰色阴影用大于0的值表示。

double sobmin, sobmax;
cv::minMaxLoc(sobel, &sobmin, &sobmax);
std::cout << "sobel value range: " << sobmin << "  " << sobmax << std::endl;
//转换为8位图像
// sobelImage = -alpha*sobel + 255
cv::Mat sobelImage;
cv::Mat sobelThresholded;
sobel.convertTo(sobelImage, CV_8U, -255. / sobmax, 255);
cv::imshow("sobelImage", sobelImage);

结果图:

OpenCV中的边缘检测——Sobel滤波器_第5张图片

三、其他梯度算子

 Prewitt算子

该算子使用下面内核来计算某个像素位置的梯度:

OpenCV中的边缘检测——Sobel滤波器_第6张图片

 Roberts算子

使用简单的2\times2的内核

OpenCV中的边缘检测——Sobel滤波器_第7张图片

Scharr算子

 该算子能够更精确地计算梯度方向

OpenCV中的边缘检测——Sobel滤波器_第8张图片

在OpenCV中使用cv::Sobel函数时,要使用Scharr内核,其参数为CV_SCHARR:

cv::Sobel(image,sobelX,CV_16S,1,0,CV_SCHARR);
cv::Scharr(image,scharrX,CV_16S,1,0,3);

所有这些定向滤波器都会计算图像函数的一阶导数。因此,在滤波器方向上像素强度变化大的区域将得到较大的值,较平坦的区域将得到较小的值。正因为如此,计算图像导数的滤波器被称为高通滤波器。

本篇文章是我学习opencv做的笔记,可能存在许多不足,欢迎大家批评指正!有问题可以随时和我交流

你可能感兴趣的:(opencv,算法,计算机视觉)