OpenCV学习笔记之九——边缘检测(Canny算子,Sobel算子,Laplace算子,Scharr滤波)

首先感谢@浅墨_毛星云本篇博文是小武通过学习@浅墨_毛星云的博客以及书籍《opencv3.0编程入门》整理的笔记及疑问心得,小武水平有限,欢迎交流。

@浅墨_毛星云博文:https://blog.csdn.net/poem_qianmo/article/category/1923021


一、Canny算子

详情介绍:https://zh.wikipedia.org/wiki/Canny%E7%AE%97%E5%AD%90

基本原理:https://blog.csdn.net/likezhaobin/article/details/6892176


函数详情:

C++: void Canny(InputArray image,OutputArray edges,
                double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false ) 

参数解释:

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。
  • 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和类型。
  • 第三个参数,double类型的threshold1,第一个滞后性阈值。
  • 第四个参数,double类型的threshold2,第二个滞后性阈值。
  • 第五个参数,int类型的apertureSize,表示应用Sobel算子的孔径大小,其有默认值3。
  • 第六个参数,bool类型的L2gradient,一个计算图像梯度幅值的标识,有默认值false。

需要注意的是,这个函数阈值1和阈值2两者的小者用于边缘连接,而大者用来控制强边缘的初始段,推荐的高低阈值比在2:1到3:1之间。


二、Sobel算子

详情介绍:https://zh.wikipedia.org/wiki/索貝爾算子

基本原理:http://www.cnblogs.com/lancidie/archive/2011/07/17/2108885.html


函数详情:

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 );  

参数解释:

  • 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,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
  • 第四个参数,int类型dx,x 方向上的差分阶数。
  • 第五个参数,int类型dy,y方向上的差分阶数。
  • 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
  • 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
  • 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。


三、Laplace算子

详情介绍:https://zh.wikipedia.org/wiki/%E6%8B%89%E6%99%AE%E6%8B%89%E6%96%AF%E7%AE%97%E5%AD%90

基本原理:http://www.cnblogs.com/xfzhang/archive/2011/01/19/1939020.html

函数详解:

C++: void Laplacian(InputArray src,OutputArray dst, 
int ddepth,
 int ksize=1, 
double scale=1, 
double delta=0, intborderType=BORDER_DEFAULT );  

参数解释:

  • 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像。
  • 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和通道数。
  • 第三个参数,int类型的ddept,目标图像的深度。
  • 第四个参数,int类型的ksize,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,且有默认值1。
  • 第五个参数,double类型的scale,计算拉普拉斯值的时候可选的比例因子,有默认值1。
  • 第六个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第七个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate()处得到更详细的信息。

Laplacian( )函数其实主要是利用sobel算子的运算。它通过加上sobel算子运算出的图像x方向和y方向上的导数,来得到我们载入图像的拉普拉斯变换结果。


四、scharr滤波器

scharr一般我就直接称它为滤波器,而不是算子。

函数详情:https://docs.opencv.org/2.4/modules/ocl/doc/image_filtering.html?highlight=scharr#ocl-scharr

C++: void Scharr(  
InputArray src, //源图  
 OutputArray dst, //目标图  
 int ddepth,//图像深度  
 int dx,// x方向上的差分阶数  
 int dy,//y方向上的差分阶数  
 double scale=1,//缩放因子  
 double delta=0,// delta值  
 intborderType=BORDER_DEFAULT )// 边界模式  

参数详解:

  • 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,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
  • 第四个参数,int类型dx,x方向上的差分阶数。
  • 第五个参数,int类型dy,y方向上的差分阶数。
  • 第六个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
  • 第七个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第八个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。


综合代码实现:

 跟踪条:     0——Canny算子 

                   1——Sobel算子

                   2——Laplace算子

                   3——Scharr滤波

//添加头文件
#include<opencv2/core/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>

using namespace std;
using namespace cv;

//参数预定义
int Way_num=0;
int struct_size=1;

Mat  Img_in , Img_out,Img_gray;
Mat Img_out_x , Img_out_y;
//函数声明
void callback_Way_num(int ,void*);
void callback_struct_size(int ,void*);
void process();

//主函数
int main ()
{
	 Img_in=imread("home.jpg");
	 cvtColor(Img_in,Img_gray,CV_BGR2GRAY);
	 imshow("【原图】",Img_gray);


	 //添加跟踪条
	 namedWindow("【效果图】");
	 createTrackbar("Canny/Sobel/Laplace/scharr","【效果图】",&Way_num, 3 , callback_Way_num);
	 callback_Way_num(Way_num,0);
	
	 //添加跟踪条
	  createTrackbar("参数值","【效果图】",&struct_size, 45 , callback_struct_size);
	  callback_struct_size(struct_size,0);
	
	 waitKey(0);
	 return 0;

}

//进行自定义的各功能操作
void process()
{

//Way_num=0,Canny算子
if (Way_num==0)
Canny(Img_gray,Img_out,struct_size , struct_size*5 , 3);

//Way_num=1,Sobel算子
else if(Way_num==1)
{
//计算x方向梯度
Sobel(Img_in , Img_out_x,CV_16U, 1 , 0 , struct_size*2+1 , 1 , 1 , BORDER_DEFAULT);
convertScaleAbs(Img_out_x,Img_out_x);
//计算y方向的梯度
Sobel(Img_in , Img_out_y,CV_16U, 0 , 1 , struct_size*2+1 , 1 , 1 , BORDER_DEFAULT);
convertScaleAbs(Img_out_y,Img_out_y);
//合并
addWeighted( Img_out_x,0.5, Img_out_y , 0.5,0, Img_out);
}

 //Way_num=2,Laplace算子
else if(Way_num==2)
{	
	Laplacian(Img_gray,Img_out, CV_16U , struct_size*2+1, 1 , 0  , BORDER_DEFAULT);
	 convertScaleAbs(Img_out ,Img_out); 
}

//Way_num=3,scharr滤波
else if(Way_num==3)
{
	//计算x方向梯度
Scharr(Img_in , Img_out_x,CV_16U, 1 , 0 , 1 , 0 , BORDER_DEFAULT);
convertScaleAbs(Img_out_x,Img_out_x);
//计算y方向的梯度
Scharr(Img_in , Img_out_y,CV_16U, 0 , 1 , 1 , 0 ,  BORDER_DEFAULT);
convertScaleAbs(Img_out_y,Img_out_y);
//合并
addWeighted( Img_out_x , 0.5 , Img_out_y , 0.5 , 0 , Img_out);
}

//显示
imshow("【效果图】",Img_out);
}





//更能切换开关的回调函数 
void callback_Way_num(int ,void*)
{
	process();
}

//改变各个功能操作内核时的回调函数
void callback_struct_size(int ,void*)
{
	process();
}


效果:

                    

                    

                    

                   

                   

                  

猜你喜欢

转载自blog.csdn.net/weixin_40647819/article/details/80029858