数字图像处理——拉普拉斯算子
在图像增强中,平滑是为了消除图像中噪声的干扰,或者降低对比度,与之相反,有时为了强调图像的边缘和细节,需要对图像进行锐化,提高对比度。拉普拉斯锐化图像是根据图像某个像素的周围像素到此像素的突变程度有关,也就是说它的依据是图像像素的变化程度。我们知道,一个函数的一阶微分描述了函数图像是朝哪里变化的,即增长或者降低;而二阶微分描述的则是图像变化的速度,急剧增长下降还是平缓的增长下降。那么据此我们可以猜
数字图像处理——拉普拉斯算子
微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;
前言
在图像增强中,平滑是为了消除图像中噪声的干扰,或者降低对比度,与之相反,有时为了强调图像的边缘和细节,需要对图像进行锐化,提高对比度。
拉普拉斯锐化图像是根据图像某个像素的周围像素到此像素的突变程度有关,也就是说它的依据是图像像素的变化程度。我们知道,一个函数的一阶微分描述了函数图像是朝哪里变化的,即增长或者降低;而二阶微分描述的则是图像变化的速度,急剧增长下降还是平缓的增长下降。那么据此我们可以猜测出依据二阶微分能够找到图像的色素的过渡程度,例如白色到黑色的过渡就是比较急剧的。
或者用官方点的话说:当邻域中心像素灰度低于它所在的领域内其它像素的平均灰度时,此中心像素的灰度应被进一步降低,当邻域中心像素灰度高于它所在的邻域内其它像素的平均灰度时,此中心像素的灰度应被进一步提高,以此实现图像的锐化处理。
应用:运用拉普拉斯可以增强图像的细节,找到图像的边缘。但是有时候会把噪音也给增强了,那么可以在锐化前对图像进行平滑处理。
目录
二阶微分
与微积分中微分的定义略有不同,数字图像中处理的均是离散的值,因此对于一维函数的一阶微分的基本定义是根据差值来定义的:
∂
f
∂
x
=
f
(
x
)
−
f
(
x
−
1
)
\frac{\partial f}{\partial x}=f(x)-f(x-1)
∂x∂f=f(x)−f(x−1)
类似的,二阶微分定义为:
∂
2
f
∂
x
2
=
2
f
(
x
)
−
f
(
x
−
1
)
−
f
(
x
+
1
)
\frac{\partial^2 f}{\partial x^2}=2f(x)-f(x-1)-f(x+1)
∂x2∂2f=2f(x)−f(x−1)−f(x+1)
将上面的一维函数扩展到二维则有:
∂
f
∂
x
=
f
(
x
,
y
)
−
f
(
x
−
1
,
y
)
∂
f
∂
y
=
f
(
x
,
y
)
−
f
(
x
,
y
−
1
)
\frac{\partial f}{\partial x}=f(x,y)-f(x-1,y)\\ \frac{\partial f}{\partial y}=f(x,y)-f(x,y-1)
∂x∂f=f(x,y)−f(x−1,y)∂y∂f=f(x,y)−f(x,y−1)
即该点x方向的微分(梯度)为该点前一列的像素值与该点像素值的差值。
∂
2
f
∂
x
2
=
2
f
(
x
,
y
)
−
f
(
x
−
1
,
y
)
+
f
(
x
+
1
,
y
)
∂
2
f
∂
y
2
=
2
f
(
x
,
y
)
−
f
(
x
,
y
−
1
)
+
f
(
x
,
y
+
1
)
\frac{\partial^2 f}{\partial x^2}=2f(x,y)-f(x-1,y)+f(x+1,y)\\ \frac{\partial^2 f}{\partial y^2}=2f(x,y)-f(x,y-1)+f(x,y+1)
∂x2∂2f=2f(x,y)−f(x−1,y)+f(x+1,y)∂y2∂2f=2f(x,y)−f(x,y−1)+f(x,y+1)
即该点x方向的二阶微分为该点前后列像素值与该点像素值的差的和,该点y方向的二阶微分为该点上下行像素值与该点像素值得差的和。
二阶微分的定义保证了以下几点:
1)在恒定灰度区域的微分值为0
2)在灰度台阶或斜坡的起点处微分值非零
可以看出,二阶微分可以检测出图像的边缘、增强细节
对于图像中,某一点来说,该点的一阶微分(梯度值)及二阶微分则为:
∇
f
=
∂
f
∂
x
+
∂
f
∂
y
=
2
f
(
x
,
y
)
−
f
(
x
−
1
,
y
)
−
f
(
x
,
y
−
1
)
∇
2
f
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
=
4
f
(
x
,
y
)
−
f
(
x
−
1
,
y
)
−
f
(
x
,
y
+
1
)
−
f
(
x
,
y
−
1
)
−
f
(
x
+
1
,
y
)
\nabla f= \frac{\partial f}{\partial x}+\frac{\partial f}{\partial y}=2f(x,y)-f(x-1,y)-f(x,y-1)\\ \nabla^2 f= \frac{\partial^2 f}{\partial x^2}+\frac{\partial^2 f}{\partial y^2}=4f(x,y)-f(x-1,y)-f(x,y+1)-f(x,y-1)-f(x+1,y)
∇f=∂x∂f+∂y∂f=2f(x,y)−f(x−1,y)−f(x,y−1)∇2f=∂x2∂2f+∂y2∂2f=4f(x,y)−f(x−1,y)−f(x,y+1)−f(x,y−1)−f(x+1,y)
其中,一阶微分法能够用来检测边缘是否存在。那么二阶微分法,也就是拉普拉斯算子就可以确定边缘的位置。这样可以找到一个模板矩阵
[
0
−
1
0
−
1
4
−
1
0
−
1
0
]
\left[ \begin{matrix} 0 & -1 & 0\\ -1 & 4 & -1\\ 0 & -1 & 0 \end{matrix} \right]
0−10−14−10−10
这个称为四邻域也就是上面的二阶微分法
[
−
1
−
1
−
1
−
1
8
−
1
−
1
−
1
−
1
]
\left[ \begin{matrix} -1 & -1 & -1\\ -1 & 8 & -1\\ -1 & -1 & -1 \end{matrix} \right]
−1−1−1−18−1−1−1−1
这个称为八邻域.也就是一个点的拉普拉斯算子结果是其周围一圈8个像素的和与中间像素8倍的差。
从上面的两种模板中就可以看出,如果一个黑色平面中有一个白点,那么模板矩阵可以使这个白点更亮。由于图像边缘就是灰度发生跳变的区域,所以拉普拉斯模板对边缘检测很有用。
Note:在有的资料中拉普拉斯算子和上面的算子符号正好相反,此时没有影响,两者都是一致的,在后面进行拉普拉斯图像锐化和原图叠加时注意区分符号即可。
此外,将上述四邻域的算子旋转45°后与原算子相加,就变成八邻域的算子了。八邻域的公式表示法如下:
∇
2
f
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
=
8
f
(
x
,
y
)
−
f
(
x
−
1
,
y
−
1
)
−
f
(
x
,
y
−
1
)
−
f
(
x
+
1
,
y
−
1
)
−
f
(
x
,
y
−
1
)
−
f
(
x
+
1
,
y
)
−
f
(
x
−
1
,
y
+
1
)
−
f
(
x
,
y
+
1
)
−
f
(
x
+
1
,
y
+
1
)
\nabla^2 f= \frac{\partial^2 f}{\partial x^2}+\frac{\partial^2 f}{\partial y^2}=8f(x,y)-f(x-1,y-1)-f(x,y-1)\\-f(x+1,y-1)-f(x,y-1)-f(x+1,y)-f(x-1,y+1)-f(x,y+1)-f(x+1,y+1)
∇2f=∂x2∂2f+∂y2∂2f=8f(x,y)−f(x−1,y−1)−f(x,y−1)−f(x+1,y−1)−f(x,y−1)−f(x+1,y)−f(x−1,y+1)−f(x,y+1)−f(x+1,y+1)
将算得的值替换原(x,y)处的像素值,可以得到类似边界的地方。
拉普拉斯图像增强原理及过程
图像锐化处理的作用是使灰度反差增强,从而使模糊图像变得更加清晰。图像模糊的实质就是图像受到平均运算或积分运算,因此可以对图像进行逆运算,如微分运算能够突出图像细节,使图像变得更为清晰,由于拉普拉斯算子是一种微分算子,因此强调的是图像中灰度的突变,并不强调灰度缓慢变化的区域。这将产生把浅灰色边线和突变点叠加到暗色背景中的图像。将原图像和拉普拉斯图像叠加在一起的简单方法,可以复原背景特性并保持拉普拉斯锐化处理的效果,使灰度突变处的对比度得到增强。锐化图像的公式如下:
g
(
x
)
=
{
f
(
x
,
y
)
−
∇
2
f
(
x
,
y
)
,
∇
2
f
(
x
,
y
)
<
0
f
(
x
,
y
)
+
∇
2
f
(
x
,
y
)
,
∇
2
f
(
x
,
y
)
≥
0
g(x)= \begin{cases} f(x,y)-\nabla^2f(x,y),\nabla^2f(x,y)<0\\ f(x,y)+\nabla^2f(x,y),\nabla^2f(x,y)\ge0 \\ \end{cases}
g(x)={f(x,y)−∇2f(x,y),∇2f(x,y)<0f(x,y)+∇2f(x,y),∇2f(x,y)≥0
这种简单的锐化方法既可以产生拉普拉斯锐化处理的效果,同时又能保留背景信息,将原始图像叠加到拉普拉斯变换的处理结果中去,可以使图像中的各灰度值得到保留,使灰度突变处的对比度得到增强,最终结果是在保留图像背景的前提下,突现出图像中小的细节信息。但其缺点是对图像中的某些边缘产生双重响应。
这个过程如下所示:
1.假设原始图像并对其填充:
原始图像:
[
8
1
6
3
5
7
4
9
2
]
\left[ \begin{matrix} 8 & 1 & 6\\ 3 & 5 & 7\\ 4 & 9 & 2 \end{matrix} \right]
834159672
填充图像后结果:
[
8
8
8
1
6
6
6
8
8
8
1
6
6
6
8
8
8
1
6
6
6
3
3
3
5
7
7
7
4
4
4
9
2
2
2
]
\left[ \begin{matrix} 8 & 8 & 8 & 1 & 6 & 6 & 6\\ 8 & 8 & 8 & 1 & 6 & 6 & 6\\ 8 & 8 & 8 & 1 & 6 & 6 & 6\\ 3 & 3 & 3 & 5 & 7 & 7 & 7\\ 4 & 4 & 4 & 9 & 2 & 2 & 2\\ \end{matrix} \right]
88834888348883411159666726667266672
拉普拉斯算子:
[
0
1
0
1
−
4
1
0
1
0
]
\left[ \begin{matrix} 0 & 1 & 0\\ 1 & -4 & 1\\ 0 & 1 & 0 \end{matrix} \right]
0101−41010
2.卷积:
不断计算,直至拉普拉斯算子全部移过图像
3.去除边界,得到结果:
基于OpenCV的Laplace算子的计算
OpenCV中Laplacian函数可以实现对图像的Laplace操作,声明如下
Laplacian( InputArray src,
OutputArray dst, int ddepth,
int ksize = 1, double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT );
参数意义为
src——输入图像
dst——Laplace操作结果
ddepth——输出图像深度,因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S
ksize——拉普拉斯算子核的大小
scale,delta,BORDER_DEFAULT,默认设置就好
对 ksize=1 则给出最快计算结果,相当于对图像采用如下内核做卷积:
[
0
1
0
1
−
4
1
0
1
0
]
\left[ \begin{matrix} 0 & 1 & 0\\ 1 & -4 & 1\\ 0 & 1 & 0 \end{matrix} \right]
0101−41010
在opencv2.4中其源码如下,下面只展示了核大小为1或者3的情况:
void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
double scale, double delta, int borderType )
{
Mat src = _src.getMat();
if (ddepth < 0)
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
if( ksize == 1 || ksize == 3 )
{
float K[2][9] =
{{0, 1, 0, 1, -4, 1, 0, 1, 0},
{2, 0, 2, 0, -8, 0, 2, 0, 2}};
Mat kernel(3, 3, CV_32F, K[ksize == 3]);
if( scale != 1 )
kernel *= scale;
filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType );
}else
{
//ksize等于其他值的情况
}
}
示例代码如下:
//====================================================================//
// Created by liheng on 19-4-2.
//Program:Show the demo the laplacian
//Data:2019.4.2
//Author:liheng
//Version:V1.0
//====================================================================//
#include <opencv2/opencv.hpp>
int main()
{
//load the Original Image and get some informations
cv::Mat src = cv::imread("../Pictures/lena.jpg",0);
cv::namedWindow("OriginalImage");
cv::imshow("OriginalImage",src);
CV_Assert(src.depth() == CV_8U);
//OpenCV solution - Laplacian
cv::Mat dst,abs_dst_laplace;
cv::Laplacian(src,dst,CV_16S,1);
cv::convertScaleAbs(dst,abs_dst_laplace);//CV_16S型的输出图像转变成CV_8U型的图像
//取二值化,使结果表达更清晰
//cv::threshold(abs_dst_laplace,abs_dst_laplace,0,255,cv::THRESH_OTSU | cv::THRESH_BINARY);
//show the result
cv::namedWindow("result_laplacian");
cv::imshow("result_laplacian",abs_dst_laplace);
src = src+abs_dst_laplace;
cv::imshow("result_laplacianEnhance",src);
cv::waitKey(0);
return 0;
}
程序运行结果如下所示,从左到右依次为:原始图像的灰度图,拉普拉斯边缘图像,拉普拉斯图像增强结果:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)