第二章:去噪的基石——空间域滤波与频域滤波

各位同学,欢迎来到实战手册的第二章。

上一章我们聊了噪声的本质,说白了就是搞清楚了「敌人长什么样」。这一章,我们就要亮出第一波武器了——滤波。我个人一直觉得,滤波是图像去噪的「内功心法」。你招式学得再多,内功不行,照片该糊还是糊,该有噪点还是有噪点。

这一章我会把空间域和频域这两大类方法掰开揉碎了讲。嗯,咱们先别急着上深度学习那些花里胡哨的东西,先把地基打牢。

核心观点:没有万能的滤波器,只有最合适的场景。理解每种滤波器的「脾气」,你才能在实战中选对工具。

图像去噪滤波 空间域滤波 均值滤波 高斯滤波 中值滤波 频域滤波 低通滤波 高通滤波 小波变换 经典去噪算法对比 → 实战选型指南

2.1 空间域滤波:直接在像素上动手

空间域滤波,说白了就是直接拿像素周围的邻居来算。你想想看,一个噪点通常跟周围的像素长得不一样,那我们把它跟邻居「平均」一下,是不是就顺眼多了?

我最早接触图像处理时,第一个学的就是均值滤波。当时觉得这玩意儿太简单了,不就是算个平均值嘛。后来在项目里吃了亏才明白——简单的东西,往往坑最多。

2.1.1 均值滤波

均值滤波的原理,就是用一个窗口滑过图像,把窗口内所有像素的灰度值加起来,除以像素个数,用这个平均值代替中心像素的值。

// 均值滤波核心代码(3x3窗口)
void boxFilter(unsigned char* src, unsigned char* dst, int width, int height) {
    int kernel[3][3] = {{1,1,1}, {1,1,1}, {1,1,1}};
    int sum, ksum = 9;
    for(int y=1; y<height-1; y++) {
        for(int x=1; x<width-1; x++) {
            sum = 0;
            for(int ky=-1; ky<=1; ky++)
                for(int kx=-1; kx<=1; kx++)
                    sum += src[(y+ky)*width + (x+kx)];
            dst[y*width + x] = sum / ksum;
        }
    }
}

我曾经踩过的坑:均值滤波会把边缘也「平均」掉。有一次做文档扫描件去噪,用了均值滤波,结果文字边缘全糊了,像泡过水一样。后来我才意识到——均值滤波只适合平坦区域,遇到边缘就得换招。

2.1.2 高斯滤波

高斯滤波跟均值滤波的区别在哪?说白了,均值滤波是「人人平等」,高斯滤波是「近亲远疏」。离中心像素越近的邻居,权重越大;越远的,权重越小。这个权重分布,就是高斯函数。

我个人习惯用高斯滤波做预处理。比如在手机夜景模式里,先来一轮轻度高斯滤波,把最刺眼的高频噪点压一压,后面再做细节增强就不会放大噪声了。

// 5x5高斯核生成(sigma=1.0)
float gaussianKernel[5][5];
float sigma = 1.0f, sum = 0.0f;
int half = 2;
for(int y=-half; y<=half; y++) {
    for(int x=-half; x<=half; x++) {
        float val = exp(-(x*x + y*y) / (2*sigma*sigma));
        gaussianKernel[y+half][x+half] = val;
        sum += val;
    }
}
// 归一化
for(int i=0; i<5; i++)
    for(int j=0; j<5; j++)
        gaussianKernel[i][j] /= sum;

实战技巧:sigma值选1.0到1.5之间,对手机摄影来说比较安全。sigma太大,照片会像蒙了一层雾。我一般控制在1.2左右,既能去噪,又不损失太多细节。

2.1.3 中值滤波

中值滤波就更有意思了。它不取平均,而是取窗口内所有像素的「中位数」。你想想看,如果窗口里有个椒盐噪声(纯白或纯黑的点),取平均会被它带偏,但取中位数就完全不受影响。

我记得有一次做老照片修复,照片上有大量扫描产生的椒盐噪声。均值滤波和高斯滤波都试了,效果惨不忍睹。换成中值滤波后,那些白点黑点像变魔术一样消失了。嗯,中值滤波对付椒盐噪声,就是降维打击。

三种空间域滤波对比:

滤波器去噪能力边缘保留计算速度适用场景
均值滤波★★☆☆☆★☆☆☆☆★★★★★平坦区域、快速预览
高斯滤波★★★☆☆★★☆☆☆★★★★☆通用预处理、轻度去噪
中值滤波★★★★☆★★★★☆★★★☆☆椒盐噪声、文字边缘

2.2 频域滤波:换个角度看问题

空间域滤波是在像素层面操作,那频域滤波呢?说白了,就是把图像从「空间坐标」变换到「频率坐标」。你想想看,一张照片里,平坦区域对应低频,边缘和纹理对应高频,噪声通常也落在高频区域。

所以频域去噪的思路就很清晰了——把高频部分砍掉一部分,再变回空间域。这就是低通滤波的核心思想。

2.2.1 低通滤波

低通滤波在频域里做,其实就是一个「保留低频,衰减高频」的操作。最常用的就是理想低通滤波、巴特沃斯低通滤波和高斯低通滤波。

我个人在实际项目中很少用理想低通,因为它太「硬」了,会在图像边缘产生振铃效应——就是那种一圈一圈的伪影,看着特别假。高斯低通滤波就平滑得多,过渡自然。

// 频域低通滤波流程(伪代码)
1. 对图像做FFT(快速傅里叶变换),得到频域数据
2. 生成低通滤波器掩膜(比如高斯型)
3. 频域数据与掩膜逐元素相乘
4. 做IFFT(逆傅里叶变换),得到去噪后的图像

注意:频域滤波的边界处理很关键。如果图像边界不连续,FFT会产生高频泄漏。我建议在做FFT之前,先对图像做边缘延拓(比如镜像对称),能有效减少边界伪影。

2.2.2 小波变换

小波变换比傅里叶变换高明在哪?傅里叶变换只能告诉你「有哪些频率成分」,但不知道这些频率出现在图像的哪个位置。小波变换就不一样了,它能同时给出频率和位置信息——这就是所谓的「时频局部化」。

我记得在手机HDR+算法里,小波变换被用来做多帧融合时的细节分离。把图像分解成低频近似分量和高频细节分量,然后对不同分量做不同的处理。低频部分做去噪,高频部分做增强,互不干扰。

// 小波去噪的经典三步
1. 分解:对图像做小波变换,得到近似系数和细节系数
2. 阈值处理:对细节系数做软阈值或硬阈值处理
   - 软阈值:系数小于阈值的置零,大于的向零收缩
   - 硬阈值:系数小于阈值的置零,大于的保留原值
3. 重构:用处理后的系数做逆小波变换

我的经验:软阈值去噪效果更平滑,但会损失一些边缘锐度。硬阈值保留边缘更好,但可能残留一些噪声点。我一般先用软阈值做一轮粗去噪,再用硬阈值做一轮精修。两轮下来,效果就比较理想了。

2.3 经典去噪算法对比

好了,前面讲了这么多方法,到底该用哪个?我整理了一张对比表,方便你快速选型。

算法噪声类型边缘保留计算开销手机端可行性
均值滤波高斯噪声极低实时
高斯滤波高斯噪声一般实时
中值滤波椒盐噪声中等实时
频域低通高频噪声一般高(FFT)需优化
小波变换多种噪声需硬件加速

你可能会问:「那我到底该选哪个?」我的建议是——看场景。如果是实时预览,用高斯滤波就够了,速度快,效果也还行。如果是后期处理,小波变换是更好的选择,虽然慢一点,但质量高。如果是椒盐噪声,别犹豫,直接上中值滤波。

嗯,这一章的内容就到这儿。滤波是去噪的基石,把这些基础打牢了,后面学非局部均值、BM3D这些高级算法时,你才能理解它们到底「高级」在哪。


公众号:蓝海资料掘金营,微信deep3321