高斯滤波在图像处理概念下,将图像频域处理和时域处理相联系,作为低通滤波器使用,可以将低频能量(比如噪声)滤去,起到图像平滑作用。
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值用。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
我们常说的高斯模糊就是使用高斯滤波器完成的,高斯模糊是低通滤波的一种,也就是滤波函数是低通高斯函数,但是高斯滤波是指用高斯函数作为滤波函数,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
在图像处理中,高斯滤波一般有两种实现方式,一是用离散化窗口滑窗卷积,另一种通过傅里叶变换。最常见的就是第一种滑窗实现,只有当离散化的窗口非常大,用滑窗计算量非常大(即使用可分离滤波器的实现)的情况下,可能会考虑基于傅里叶变化的实现方法。
由于高斯函数可以写成可分离的形式,因此可以采用可分离滤波器实现来加速。所谓的可分离滤波器,就是可以把多维的卷积化成多个一维卷积。具体到二维的高斯滤波,就是指先对行做一维卷积,再对列做一维卷积。这样就可以将计算复杂度从O(M*M*N*N)降到O(2*M*M*N),M,N分别是图像和滤波器的窗口大小。
高斯模糊是一个非常典型的图像卷积例子,本质上,高斯模糊就是将(灰度)图像 I 和一个高斯核进行卷积操作:
其中 * 表示卷积操作; Gσ 是标准差为σ 的二维高斯核,定义为:
这里补充以下卷积的知识:
卷积是分析数学中一种重要的运算。
设:f(x),g(x)是R1上的两个可积函数,作积分:
可以证明,关于几乎所有的实数x,上述积分是存在的。这样,随着x的不同取值,这个积分就定义了一个新函数h(x),称为函数f与g的卷积,记为h(x)=(f*g)(x)。
卷积是一个单纯的定义,本身没有什么意义可言,但是其在各个领域的应用是十分广泛的,在滤波中可以理解为一个加权平均过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到,而如何加权则是依据核函数高斯函数。
平均的过程:
对于图像来说,进行平滑和模糊,就是利用周边像素的平均值
“中间点”取”周围点”的平均值,就会变成1。在数值上,这是一种”平滑化”。在图形上,就相当于产生”模糊”效果,”中间点”失去细节。
显然,计算平均值时,取值范围越大,”模糊效果”越强烈。
上面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。
如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。
而正态分布显然是一种可取的权重分配模式。由于图像是二维的,所以需要使用二维的高斯函数:
二维高斯函数图像:
一维高斯函数:
中心点就是原点,μ等于0:
二维高斯函数(中心为原点):
计算平均值的时候,我们只需要将”中心点”作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值,而这就是上述的与二维高斯核进行卷积的过程。
计算权重矩阵的过程:
假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:
假定σ=1.5,则模糊半径为1的权重矩阵如下:
这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵:
有了权重矩阵,就可以计算高斯模糊的值了。
中心点以及周边n个点,每个点乘以自己的权重值并将这些值相加,就是中心点的高斯模糊的值。对所有点重复这个过程,就得到了高斯模糊后的图像。
如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。
对于边界点来说,周边没有足够的点,一个变通方法是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵
基于上述的原理,进行编程实现:
java版:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Test {
/**
* 简单高斯模糊算法
*
* @param args
* @throws IOException [参数说明]
*
* @return void [返回类型说明]
* @exception throws [违例类型] [违例说明]
* @see [类、类#方法、类#成员]
*/
public static void main(String[] args)
throws IOException {
BufferedImage img = ImageIO.read(new File("d:\\My Documents\\psb.jpg"));
System.out.println(img);
int height = img.getHeight();
int width = img.getWidth();
int[][] matrix = new int[3][3];
int[] values = new int[9];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
readPixel(img, i, j, values);
fillMatrix(matrix, values);
img.setRGB(i, j, avgMatrix(matrix));
}
}
ImageIO.write(img, "jpeg", new File("d:/test.jpg"));//保存文件
}
private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
int xStart = x - 1;
int yStart = y - 1;
int current = 0;
for (int i = xStart; i < 3 + xStart; i++) {
for (int j = yStart; j < 3 + yStart; j++) {
int tx = i;
if (tx < 0) {
tx = -tx;
} else if (tx >= img.getWidth()) {
tx = x;
}
int ty = j;
if (ty < 0) {
ty = -ty;
} else if (ty >= img.getHeight()) {
ty = y;
}
pixels[current++] = img.getRGB(tx, ty);
}
}
}
private static void fillMatrix(int[][] matrix, int... values) {
int filled = 0;
for (int i = 0; i < matrix.length; i++) {
int[] x = matrix[i];
for (int j = 0; j < x.length; j++) {
x[j] = values[filled++];
}
}
}
private static int avgMatrix(int[][] matrix) {
int r = 0;
int g = 0;
int b = 0;
for (int i = 0; i < matrix.length; i++) {
int[] x = matrix[i];
for (int j = 0; j < x.length; j++) {
if (j == 1) {
continue;
}
Color c = new Color(x[j]);
r += c.getRed();
g += c.getGreen();
b += c.getBlue();
}
}
return new Color(r / 8, g / 8, b / 8).getRGB();
}
}
以上java代码就是根据上述原理实现的,而使用python完成这个功能就要简单的多得多,因为Scipy有用来做滤波操作的 scipy.ndimage.filters 模块。该模块使用快速一维分离的方式来计算卷积:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from numpy import *
from scipy.ndimage import filters
#读取图片,灰度化并转为数组
im = array(Image.open('./source/test.jpg').convert('L'))
#进行σ = 2的高斯滤波
im2 = filters.gaussian_filter(im,2)
#进行σ = 5的高斯滤波
im3 = filters.gaussian_filter(im,5)
#进行σ = 10的高斯滤波
im4 = filters.gaussian_filter(im,10)
#显示图像
gray()
subplot(141)
title('source')
imshow(im)
subplot(142)
title('sigma=2')
imshow(im2)
subplot(143)
title('sigma=5')
imshow(im3)
subplot(144)
title('sigma=10')
imshow(im4)
show()
guassian_filter() 函数的最后一个参数表示标准差,下面是该函数的API:
运行结果:
如果打算模糊一幅彩色图像,只需简单地对每一个颜色通道进行高斯模糊:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from numpy import *
from scipy.ndimage import filters
import copy
#读取图片,灰度化并转为数组
im = array(Image.open('./source/test.jpg'))
#r通道
r = im[:,:,0]
#g通道
g = im[:,:,1]
#b通道
b = im[:,:,2]
#对r通道进行σ = 2的高斯滤波
r = filters.gaussian_filter(r,2)
#对g通道进行σ = 2的高斯滤波
g = filters.gaussian_filter(g,2)
#对b通道进行σ = 2的高斯滤波
b = filters.gaussian_filter(b,2)
#组合各通道
im2 = copy.deepcopy(im)
im2[:,:,0] = r
im2[:,:,1] = g
im2[:,:,2] = b
#显示图像
subplot(121)
title('source')
imshow(im)
subplot(122)
title('After GaussFilter')
imshow(im2)
show()
运行结果:
本篇博客主要介绍了高斯滤波的原理以及实现,以及python scipy的滤波库的使用,希望对大家有所帮助~