注:本系列来自于图像处理课程实验,用Matlab实现最基本的图像处理算法
1.锐化滤波器
锐化滤波,是将图像的低频部分减弱或去除,保留图像的高频部分,即图像的边缘信息。
图像的边缘、轮廓一般位于灰度突变的地方,也就是图像的高频部分,通常用灰度差分提取边缘轮廓。
图像中边缘轮廓通常是任意方向的,因此我们的差分运算需要具有方向性。各向同性的边缘检测算子对任意方向的边缘轮廓都有相同的检测能力,那么什么是算子?
算子是一个函数空间到函数空间上的映射O:X→X。广义上的算子可以推广到任何空间,如内积空间等。
我们主要学习以下四种差分算子:
- Roberts算子
- Sobel算子
- Prewitt算子
- Laplace算子
2.Roberts算子锐化滤波
(1)Roberts算子
设图像函数为F(x,y),点(x,y)的梯度定义为:
G[F(x,y)]=????????F?x?F?y???????
梯度的幅值定义为:
G[F(x,y)]=(?F?x)2+(?F?y)2 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄√
对于离散图像,我们需要用差分近似表示微分,那么得到近似梯度幅度为:
G[F(x,y)]=[F(x,y)?F(x+1,y)]2+[F(x,y)?F(x,y+1)]2 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄√=|F(x,y)?F(x+1,y)|+|F(x,y)?F(x,y+1)|
交叉一阶差分,得到Roberts算子:
G[F(x,y)]=|F(x,y)?F(x+1,y)|+|F(x,y)?F(x,y+1)|
(2)代码实现
Roberts算子涉及绝对值运算,我们不方便提取出模版来做模版卷积运算,那么直接遍历所有点求出其近似梯度幅值:
function [ edge ] = RobertsOperator( pic )
edge = uint8(zeros(size(pic)));
h = size(pic, 1);
w = size(pic, 2);
for i = 1 : h - 1
for j = 1 : w - 1
edge(i, j) = uint8(abs(pic(i, j) - pic(i + 1, j + 1)) + abs(pic(i, j + 1) - pic(i + 1, j)));
end
end
end
边界点无法按照Roberts算子求交叉差分,这里采取直接忽略边界的方式。需要注意的是把类型强制转换为uint8(abs默认返回double)。
(3)运行结果
3.Sobel算子锐化滤波
(1)Sobel算子
Roberts算子是基于2*2窗口计算近似梯度,而Sobel算子是基于3*3窗口计算近似梯度的,并且Sobel算子并不是各向同性的算子,它分为:
- 水平边缘检测Sobel算子gx
- 垂直边缘检测Sobel算子gy
先给出模版再说明近似梯度的原因:
gx=?????1 0 1?202?101????
gy=?????1 ?2 ?1000121????
gx之所以近似表示水平梯度,是因为它直接求的是3*3窗口内模版中心像素点附近的像素点水平差分之和,中间元素差分乘以了权重系数2表示和模版中心关联度更高。gy可以类似理解。
运用模版卷积运算,可以快速求出水平梯度:
Gx=gx?F3×3
Sobel算子考虑权重,因此抗噪能力优于无权重的Prewitt算子(见后)。
在求出了水平梯度Gx和垂直梯度Gy后,可以得到梯度幅值为:
G=(Gx)2+(Gy)2 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄√
(2)代码实现
为了节约运算量,一般在实现Sobel算子时不直接使用求模运算(平方和再开方),而是比较Gx和Gy中绝对值较大者(水平差分和垂直差分较大者),也就是选取边界轮廓更加明显的方向。
使用模版卷积,直接忽略边界:
function [ edge ] = SobelOperator( pic )
edge = uint8(zeros(size(pic)));
h = size(pic, 1);
w = size(pic, 2);
gx = [-1, -2, -1; 0, 0, 0; 1, 2, 1];
gy = gx‘;
for i = 2 : h - 1
for j = 2 : w - 1
sub = double(pic(i - 1 : i + 1, j - 1 : j + 1));
g1 = abs(sum(sum(sub .* gx)));
g2 = abs(sum(sum(sub .* gy)));
if g1 > g2
edge(i, j) = uint8(g1);
else
edge(i, j) = uint8(g2);
end
end
end
end
还是需要注意:
- 做卷积时用Matlab点乘
- uint8类型转换
(3)运行结果
相比Roberts算子,使用Sobel算子得到的边缘线条更粗,但能一定程度上反映边缘在原始图像中的强度。
4.Prewitt算子锐化滤波
(1)Prewitt算子
前面提到过,Prewitt是Sobel算子的无权重版本,模版如下:
gx=?????1 0 1?101?101????
gy=?????1 ?1 ?1000111????
(2)代码实现
直接修改模版即可:
gx = [-1, -1, -1; 0, 0, 0; 1, 1, 1];
gy = gx‘;
(3)运行结果
Prewitt算子边缘检测和Sobel算子结果相似,但不如其细节丰富。
5.Laplace算子锐化滤波
(1)Laplace算子
之前的三个算子都是一阶梯度算子,最后介绍一个二阶梯度算子: Laplace算子,二维空间的laplace算子定义为各向同性的二阶导数和:
?2F=?2F?x2+?2F?y2
图像中用二阶差分来近似二阶梯度:
?2F?x2=(F(x+1,y)?F(x,y))?(F(x,y)?F(x?1,y))=F(x+1,y)?2F(x,y)+F(x?1,y)
?2F?y2=(F(x,y+1)?F(x,y))?(F(x,y)?F(x,y?1))=F(x,y+1)?2F(x,y)+F(x,y?1)
所以有
?2F=F(x+1,y)+F(x?1,y)+F(x,y+1)+F(x,y?1)?4F(x,y)
由此得到laplace算子的模版:
L=????0 1 01?41010????
(2)代码实现
同样用模版卷积并且忽略边界:
function [ edge ] = LaplaceOperator( pic )
edge = uint8(zeros(size(pic)));
h = size(pic, 1);
w = size(pic, 2);
l = [0, 1, 0; 1, -4, 1; 0, 1, 0];
for i = 2 : h - 1
for j = 2 : w - 1
sub = double(pic(i - 1 : i + 1, j - 1 : j + 1));
d = sum(sum(sub .* l));
edge(i, j) = uint8(d);
end
end
end
(3)运行结果
Laplace算子的边缘检测效果并不如一阶算子的效果,观察一阶导数和二阶导数的图像就可以明白:
二阶导数增强域不是频率最高的部分(边缘),而有一定偏差,并且增强幅度并不如一阶导数。如果求绝对值,图像负y轴部分翻正,会产生双边缘。
书上总结的Laplace算子做锐化滤波的特点
- 对噪声敏感
- 产生双边源
- 缓慢区域产生暗背景