上一篇我们学习了边缘检测相关的Sobel算了,经过学习之后,我们应该可以对Sobel算子进行熟悉的运用,那么今天,我们一起来学习一下边缘检测相关的Laplacian(拉普拉斯)算子以及scharr滤波器。
一、理论
Laplacian 算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度grad()的散度div(),因此如果f是二阶可微的实函数,则f的拉普拉斯算子定义为:
(1) f的拉普拉斯算子也是笛卡儿坐标系xi中的所有非混合二阶偏导数求和;
(2) 作为一个二阶微分算子,拉普拉斯算子把C函数映射到C函数,对于k ≥ 2。表达式(1)(或(2))定义了一个算子Δ :C(R) → C(R),或更一般地,定义了一个算子Δ : C(Ω) → C(Ω),对于任何开集Ω。
根据图像处理的原理我们知道,二阶导数可以用来进行检测边缘 。 因为图像是 “二维”,我们需要在两个方向进行求导,使用Laplacian算子将会使求导过程变得简单。
由于 Laplacian使用了图像梯度,它内部的代码其实是调用了 Sobel 算子的。
tips:让一幅图像减去它的Laplacian可以增强对比度。
离散函数导数
离散函数的导数退化成了差分,一维一阶差分公式和二阶差分公式分别为
Laplace算子的差分形式
分别对Laplace算子x,y两个方向的二阶导数进行差分就得到了离散函数的Laplace算子
在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为,
所以Laplace算子的差分形式为,
函数的拉普拉斯算子也是该函数的Hessian 矩阵的迹,可以证明,它具有各向同性,即与坐标轴方向无关,坐标轴旋转后梯度结果不变。如果邻域系统是4 邻域,Laplacian 算子的模板为:
如果邻域系统是8 邻域,Laplacian 算子的模板为:
Laplacian 算子对噪声比较敏感,所以图像一般先经过平滑处理,因为平滑处理也是用模板进行的,所以,通常的分割算法都是把Laplacian 算子和平滑算子结合起来生成一个新的模板。
二、OpenCV中Laplacian()函数详解
1、函数原型
void Laplacian(InputArray src,
OutputArray dst,
int ddepth,
int ksize = 1,
double scale = 1,
double delta = 0,
intborderType =
BORDER_DEFAULT);
2、函数功能
Laplacian函数可以计算出图像经过拉普拉斯变换后的结果。
3、参数详解
- 第一个参数,InputArray类型的image,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位图像;
- 第二个参数,OutputArray类型的edges,输出的边缘图,需要和源图片有一样的尺寸和通道数;
- 第三个参数,int类型的ddept,目标图像的深度;
- 第四个参数,int类型的ksize,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,且有默认值1;
当ksize>1时,
当ksize = 1,拉普拉斯算子默认采用下面的卷积核
- 第五个参数,double类型的scale,计算拉普拉斯值的时候可选的比例因子,有默认值1;
- 第六个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0;
- 第七个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。
4、实例:实现对摄像头的图像进行Laplacian边缘检测
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
static void help()
{
cout <<
"This program demonstrates
Laplace point/edge detection
using OpenCV function Laplacian()"
"It captures from the camera of
your choice: 0, 1, ... default 0"
"Call:"
"./laplace -c=
-p=
decoded/captured next>" << endl;
}
// 三种滤波
enum { GAUSSIAN, BLUR, MEDIAN };
int sigma = 3;
// 默认滤波为高斯滤波
int smoothType = GAUSSIAN;
const char* keys =
{
"{ c | 0 | }{ p | | }"
};
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc,
argv, keys );
help();
VideoCapture cap; // 摄像机接口
// 获取摄像机参数
string camera = ("c");
if (() == 1 && isdigit(camera[0]))
(("c"));
else
(samples::findFileOrKeep(camera));
// 判断相机是否打开
if (!())
{
cerr << "Can't open camera/video stream: "
<< camera << endl;
return 1;
}
// 打开相机后,输出相机的相关信息
cout << "Video " << ("c") <<
": width=" << (CAP_PROP_FRAME_WIDTH) <<