1 sobel算子的基本概念
Sobel 算子是一个主要用于边缘检测的离散微分算子(discrete differentiation operator)。它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,都将会产生对应的梯度矢量或是其法矢量。
2 sobel算子的计算过程
我们假设被作用图像为I然后进行如下操作。
(1)分别在x和y两个方向求导。
①水平变化:将I与一个奇数大小的内核G,进行卷积。比如,当内核大小为3时,G2的计算结果为:
②垂直变化:将:I与一个奇数大小的内核进行卷积。比如,当内核大小为3时,计算结果为:
(2)在图像的每一点,结合以上两个结果求出近似梯度:
另外有时,也可用下面更简单的公式代替:
3 sobel函数
Sobel 函数使用扩展的Sobel算子,来计算一阶、二阶、三阶或混合图像差分。
C++:
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);
(1)第一个参数,InputArray类型的src,为输入图像,填Mat类型即可。
(2)第二个参数,OutputArray 类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
(3)第三个参数,int类型的ddepth,输出图像的深度,支持如下 src.depth()和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
(4)第四个参数,int类型dx,x方向上的差分阶数。
(5)第五个参数,int类型dy,y方向上的差分阶数。
(6)第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1、3、5或7。
(7)第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。可以在文档中查阅 getDerivKernels的相关介绍,来得到这个参数的更多信息。
(8)第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
(9)第九个参数,int 类型的 borderType,边界模式,默认值为BORDER DEFAULT。这个参数可以在官方文档中borderInterpolate 处得到更详细的信息。
一般情况下,都是用ksizexksize内核来计算导数的。然而,有一种特殊情况—当ksize为1时,往往会使用3x1或者1x3的内核。且这种情况下,并没有进行高斯平滑操作。
一些补充说明如下。
①当内核大小为3时,Sobel 内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值而已)。为解决这一问题,OpenCV 提供了 Scharr函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确,其内核是这样的:
②因为Sobel算子结合了高斯平滑和分化(differentiation),因此结果会具有更多的抗噪性。大多数情况下,我们使用sobel函数时,取【xorder=1,yorder=0,ksize=3】来计算图像X方向的导数,【xorder=0,yorder=1,ksize=3】来 计算图像y方向的导数。
计算图像X方向的导数,取【xorder=1,yorder=0,ksize=3】情况对应的 内核:
而计算图像Y方向的导数,取【xorder=0,yorder=1,ksize=3】对应的内 核:
4 示例
代码:
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//--------------------------------------------------------------------------------------------
using namespace cv;
//-----------------------------------【main( )函数】-------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//--------------------------------------------------------------------------------------------
int main( )
{
//【0】创建 grad_x 和 grad_y 矩阵
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y,dst;
//【1】载入原始图
Mat src = imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图
//【2】显示原始图
imshow("【原始图】sobel边缘检测", src);
//【3】求 X方向梯度
Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
imshow("【效果图】 X方向Sobel", abs_grad_x);
//【4】求Y方向梯度
Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
imshow("【效果图】Y方向Sobel", abs_grad_y);
//【5】合并梯度(近似)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );
imshow("【效果图】整体方向Sobel", dst);
waitKey(0);
return 0;
}
原图
效果图1
效果图2
效果图3
标签:src,sobel,Sobel,int,图像处理,内核,算子,grad,CV From: https://blog.51cto.com/u_11745691/6138636