拉普拉斯算子,二阶微分线性算子,与一阶微分相比,二阶微分的边缘定位能力更强,锐化效果更好。
使用二阶微分算子的基本方法是定义一种二阶微分的离散形式,然后根据这个形式生成一个滤波模板,与图像卷积。
对于二维图像f(x,y),二阶微分最简单的定义(拉普拉斯算子): ∇2I=∂2I∂x2+∂2I∂y2
对于任意阶微分算子都是线性算子,所以二阶微分算子可以用生成模板然后卷积的方式得出结果。
我们在像素点(i,j)的3×3的邻域内,可以有如下的近似:
所以二阶微分检测边缘的方法就分两步:
1)用上面的Laplace核与图像进行卷积;
2)对卷积后的图像,取得那些卷积结果为0的点。
虽然上述使用二阶微分检测边缘的方法简单,但它的缺点是对噪声十分敏感,同时也没有能够提供边缘的方向信息。为了实现对噪声的抑制,Marr等提出了LOG的方法。
为了减少噪声对边缘的影响,首先图像要进行低通滤波,LOG采用了高斯函数作为低通滤波器。高斯函数为:
拉普拉斯是用二阶差分计算边缘的(在一阶微分图中极大值或极小值处,认为是边缘。在二阶微分图中极大值和极小值之间的过 0 点,被认为是边缘。)
拉普拉斯算子推导:
一阶差分:f ‘(x) = f(x) - f(x - 1)
二阶差分:f ‘(x) = (f(x + 1) - f(x)) - (f(x) - f(x - 1))
化简后:f ‘(x) = f(x - 1) - 2 f(x)) + f(x + 1)
提取前面的系数:[1, -2, 1]
二维的情况下,同理可得
f ‘(x, y) = -4 f(x, y) + f(x-1, y) + f(x+1, y) + f(x, y-1) + f(x, y+1)
拉普拉斯算子还可以表示成模板的形式,以便更好编程需要
图1(a)表示离散拉普拉斯算子的模板,
图1(b)表示其扩展模板,
图1(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()处得到更详细的信息。
1.高斯模糊-GaussianBlur
2.灰度转换-cvtColor
3.拉普拉斯计算二阶导数
4.取绝对值
5.输出
#include
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src, dst;
src = imread("D:/程序文件/Opencv/Opencv/lena.jpg");
if (!src.data)
{
return -1;
}
/*
* 1.高斯模糊
* 2.转换为灰度图像
* 3.laplace算子找边缘
* 4.对于边缘像素值求绝对值,以保证像素没有被舍去
* 5.附加操作,可以通过阈值处理来加强结果。
*/
char inputTitle[] = "input image";
char outputTitle[] = "output image";
namedWindow(inputTitle, CV_WINDOW_NORMAL);
imshow(inputTitle, src);
Mat gray_src, edge_image;
GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray_src, CV_BGR2GRAY);
Laplacian(gray_src, edge_image, CV_16S, 3);
convertScaleAbs(edge_image, edge_image);
threshold(edge_image, edge_image, 0, 255, THRESH_OTSU | THRESH_BINARY);
namedWindow(outputTitle, CV_WINDOW_NORMAL);
imshow(outputTitle, edge_image);
waitKey(0);
return 0;
}