OpenCV学习笔记(十二):边缘检测:Canny(),Sobel(),Laplace(),Scharr滤波器
1)滤波:边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。常见的滤波方法主要有高斯滤波,即采用离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和。
2)增强:增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。在具体编程实现时,可通过计算梯度幅值来确定。
3)检测:经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是我们要找的边缘点,所以应该采用某种方法来对这些点进行取舍。实际工程中,常用的方法是通过阈值化方法来检测。
1、Canny()算子:
Canny边缘检测算子是一个多级边缘检测算法
1
2
3
4
5
6
7
8
9C++: void Canny(InputArray image, //输入图像,即源图像 OutputArray edges, // 输出的边缘图 double threshold1, // 第一个滞后性阈值 double threshold2, // 第二个滞后性阈值 // 这个函数阈值1和阈值2两者的小者用于边缘连接,而大者用来控制强边缘的初始段,推荐的高低阈值比在2:1到3:1之间。 int apertureSize=3, // 表示应用Sobel算子的孔径大小 bool L2gradient=false // 一个计算图像梯度幅值的标识 )
2、Sobel()算子:
Sobel 算子是一个主要用作边缘检测的离散微分算子 (discrete differentiation operator)。它Sobel算子结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,将会产生对应的梯度矢量或是其法矢量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16void Sobel ( InputArray src, // 输入图 OutputArray dst, // 输出图 int 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 int dx, // x 方向上的差分阶数 int dy, // y 方向上的差分阶数 int ksize=3, // 表示Sobel核的大小;必须取1,3,5或7 double scale=1, // 计算导数值时可选的缩放因子 double delta=0, // 表示在结果存入目标图之前可选的delta值 int borderType=BORDER_DEFAULT // 边界模式 );
3、Laplace()算子:
Laplacian 算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度grad()的散度div()。Laplacian( )函数其实主要是利用sobel算子的运算。它通过加上sobel算子运算出的图像x方向和y方向上的导数,来得到我们载入图像的拉普拉斯变换结果。
1
2
3
4
5
6
7
8
9void Laplacian(InputArray src, // 源图像 OutputArray dst, // 输出的边缘图 int ddepth, // 输出图像的深度 int ksize=1, // 用于计算二阶导数的滤波器的孔径尺寸 double scale=1, // 计算拉普拉斯值的时候可选的比例因子 double delta=0, // 表示在结果存入目标图之前可选的delta值 intborderType=BORDER_DEFAULT // 边界模式 );
4、scharr滤波器:
scharr一般我就直接称它为滤波器,而不是算子,主要是配合Sobel算子的运算而存在的。
scharr算子与Sobel的不同点是在平滑部分,这里所用的平滑算子是1/16∗[3,10,3],相比于1/4∗[1,2,1],中心元素占的权重更重,这可能是相对于图像这种随机性较强的信号,邻域相关性不大,所以邻域平滑应该使用相对较小的标准差的高斯函数,也就是更瘦高的模板。
1
2
3
4
5
6
7
8
9
10
11
12void Scharr( InputArray src, // 源图 OutputArray dst, // 目标图 int ddepth, // 图像深度 int dx, // x方向上的差分阶数 int dy, //y方向上的差分阶数 double scale=1, //缩放因子 double delta=0, // delta值 intborderType=BORDER_DEFAULT // 边界模式 )
4、代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include <opencv2/opencv.hpp> using namespace cv; using namespace std; //原图,原图的灰度版,目标图 Mat g_srcImage, g_srcGrayImage,g_dstImage; //Canny边缘检测相关变量 Mat g_cannyDetectedEdges; int g_cannyLowThreshold=1;//TrackBar位置参数 //Sobel边缘检测相关变量 Mat g_sobelGradient_X, g_sobelGradient_Y; Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y; int g_sobelKernelSize=1;//TrackBar位置参数 //Scharr滤波器相关变量 Mat g_scharrGradient_X, g_scharrGradient_Y; Mat g_scharrAbsGradient_X, g_scharrAbsGradient_Y; int main() { //载入原图 g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/7.1 edge detection 边缘检测/5.jpg"); if( !g_srcImage.data ) { printf("Oh,no,读取srcImage错误~! n"); return false; } //显示原始图 namedWindow("【原始图】"); imshow("【原始图】", g_srcImage); // 1、创建与src同类型和大小的矩阵(dst) g_dstImage.create( g_srcImage.size(), g_srcImage.type() ); // 2、将原图像转换为灰度图像 cvtColor( g_srcImage, g_srcGrayImage, COLOR_BGR2GRAY ); // 3、创建trackbar namedWindow( "【效果图】Canny边缘检测", WINDOW_AUTOSIZE ); namedWindow( "【效果图】Sobel边缘检测", WINDOW_AUTOSIZE ); createTrackbar( "参数值:", "【效果图】Canny边缘检测", &g_cannyLowThreshold, 120, on_Canny); createTrackbar( "参数值:", "【效果图】Sobel边缘检测", &g_sobelKernelSize, 3, on_Sobel); // 4、调用回调函数 on_Canny(0, 0); on_Sobel(0, 0); // 5、调用封装了Scharr边缘检测代码的函数 Scharr( ); //轮询获取按键信息,若按下Q,程序退出 while((char(waitKey(1)) != 'q')) {} }
1)Canny边缘检测窗口滚动条的回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21void on_Canny(int, void*) { // 先使用 3x3内核来降噪 blur( g_srcGrayImage, g_cannyDetectedEdges, Size(3,3) ); // 运行我们的Canny算子 // threshold1:滞后性阈值1(较小值用于边缘连接,较大值控制强边缘的初始段) // threshold2:滞后性阈值2 // apertureSize sobel算子的孔径大小 Canny( g_cannyDetectedEdges, g_cannyDetectedEdges, g_cannyLowThreshold, g_cannyLowThreshold*3, 3 ); //先将g_dstImage内的所有元素设置为0 g_dstImage = Scalar::all(0); //使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcImage拷到目标图g_dstImage中 g_srcImage.copyTo( g_dstImage, g_cannyDetectedEdges); //显示效果图 imshow( "【效果图】Canny边缘检测", g_dstImage ); }
2)Sobel边缘检测窗口滚动条的回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32void on_Sobel(int, void*) { //Sobel算子是一阶导数的边缘检测算子,在算法实现过程中,通过3×3模板作为核与图像中的每个像素点做卷积和运算,然后选取合适的阈值以提取边缘。 //Sobel算子算法的优点是计算简单,速度快。但是由于只采用了2个方向的模板,只能检测水平和垂直方向的边缘, //因此这种算法对于纹理较为复杂的图像,其边缘检测效果就不是很理想。该算法认为: //凡灰度新值大于或等于阈值的像素点时都是边缘点。 //这种判断欠合理,会造成边缘点的误判,因为许多噪声点的灰度值也很大。 // ddepth:输出图像的深度 // dx,dy: x y方向上的差分阶数 // scale :计算导数时的缩放因子 // 求 X方向梯度 Sobel( g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT ); // 对于输入数组的每个元素,convertScaleAbs函数依次执行三个操作:缩放、取绝对值、转换为无符号8位类型 : // dst(I)=saturate_cast<uchar>(|src(I)∗alpha+beta|) convertScaleAbs( g_sobelGradient_X, g_sobelAbsGradient_X ); // Mat grad_xROI(grad_x,Rect(0,0,20,20)); // cout<<"M="<<endl<<grad_xROI<<endl; // imshow("【效果图】 X方向Sobel1", grad_x); // 求Y方向梯度 Sobel( g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT ); convertScaleAbs( g_sobelGradient_Y, g_sobelAbsGradient_Y ); // 合并梯度 addWeighted( g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage ); //显示效果图 imshow("【效果图】Sobel边缘检测", g_dstImage); }
3)Scharr边缘检测相关代码的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21void Scharr( ) { // scharr算子与Sobel的不同点是在平滑部分,这里所用的平滑算子是1/16∗[3,10,3], // 相比于1/4∗[1,2,1],中心元素占的权重更重,这可能是相对于图像这种随机性较强的信号, // 邻域相关性不大,所以邻域平滑应该使用相对较小的标准差的高斯函数,也就是更瘦高的模板。 // 求 X方向梯度 Scharr( g_srcImage, g_scharrGradient_X, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT ); convertScaleAbs( g_scharrGradient_X, g_scharrAbsGradient_X );//计算绝对值,并将结果转换成8位 // 求Y方向梯度 Scharr( g_srcImage, g_scharrGradient_Y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT ); convertScaleAbs( g_scharrGradient_Y, g_scharrAbsGradient_Y );//计算绝对值,并将结果转换成8位 // 合并梯度 addWeighted( g_scharrAbsGradient_X, 0.5, g_scharrAbsGradient_Y, 0.5, 0, g_dstImage ); //显示效果图 imshow("【效果图】Scharr滤波器", g_dstImage); }
结果:
最后
以上就是愉快砖头最近收集整理的关于OpenCV学习笔记(十二):边缘检测:Canny(),Sobel(),Laplace(),Scharr滤波器的全部内容,更多相关OpenCV学习笔记(十二):边缘检测:Canny()内容请搜索靠谱客的其他文章。
发表评论 取消回复