图像变换(2):基于OpenCV的边缘检测
三,sobel算子;
1. sobel算子的基本概念
2. sobel算子的计算过程
3.使用Sobel算子:Sobel()函数
4.示例程序:Sobel算子的使用
三,sobel算子
1. sobel算子的基本概念
Sobel 算子是一个主要用于边缘检测的离散微分算子( discrete differentiationoperator)。它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,都将会产生对应的梯度矢量或是其法矢量。
2. sobel算子的计算过程
我们假设被作用图像为Ⅰ然后进行如下操作。
(1)分别在x和y两个方向求导。
①水平变化:将Ⅰ与一个奇数大小的内核G进行卷积。比如,当内核大小为3时,Gx的计算结果为:
②垂直变化:将:I与一个奇数大小的内核进行卷积。比如,当内核大小为3时,计算结果为:
(2)在图像的每一点,结合以上两个结果求出近似梯度:
3.使用Sobel算子:Sobel()函数
Sobel 函数使用扩展的Sobel算子,来计算一阶、二阶、三阶或混合图像差分。
(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处得到更详细的信息。
一般情况下,都是用ksize x ksize内核来计算导数的。然而,有一种特殊情况——当ksize为1时,往往会使用3x1或者1x 3的内核。且这种情况下,并没有进行高斯平滑操作。
一些补充说明如下。
①当内核大小为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】情况对应的内核:
4.示例程序:Sobel算子的使用
代码:
#include<opencv2/opencv.hpp>
#include <opencv2/core/utils/logger.hpp>
#include<iostream>
using namespace std;
using namespace cv;//包含cv命名空间
int main()
{
cv::utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//控制台不在输出日志文件
//创建grad_x和grad_y矩阵
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y,dst;
//载入原始图
Mat src = imread("E:/pictures/2.jpg");
//显示原始图
imshow("【原始图】sobel边缘检测",src);
//求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);
//求y方向梯度
Sobel(src, grad_y, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
imshow("【效果图】y方向sobel", abs_grad_y);
//合并梯度(近似)
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
imshow("【效果图】整体方向Sobel", dst);
waitKey(0);
return 0;
}
运行结果: