OpenCV入门(16):图像处理之滤波(平滑处理)
一、基础理论
1.1 图像噪声
由于图像采集、处理、传输等过程不可避免的会受到噪声的污染,妨碍人们对图像理解及分析处理。常见的图像噪声有高斯噪声、椒盐噪声等。
椒盐噪声
椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。椒盐噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。

高斯噪声
高斯噪声是指噪声密度函数服从高斯分布的一类噪声。由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。
高斯分布(正太分布):


为了去除噪声,我们引入滤波(平滑)技术:
1.2 平滑(滤波)
“平滑”(滤波)通常又称“模糊”,是一种简单常用的图像处理操作。进行平滑处理的原因有很多,但通常是用来去除噪声和相机失真,平滑在按照一定的原理来降低图像分辨率中也有重要应用。
根据空间滤波增强目的可分为:平滑滤波和锐化滤波;
根据空间滤波的特点可分为:线性滤波和非线性滤波。
- 平滑滤波,能减弱或消除图像中的高频分量,但不影响低频分量。因为高频分量对应图像中的区域边缘等灰度值具有较大、较快变化的部分,平滑滤波将这些分量绿区可减少局部灰度的起伏,使图像变得比较平滑。实际应用中,平滑滤波即可以用来消除噪声,又可以用在提取较大的目标前过滤去除较小的细节或将目标内的小间断连接起来。
 - 锐化滤波,能减弱或消除图像中的低频分量,但不影响高频分量。因为低频分量对应图像中灰度值缓慢变化的区域,因而与图像的整体特性如整体对比度和平均灰度值等有关。锐化滤波将这些分量滤去可使图像反差增加,边缘明显。实际应用中,锐化滤波可用于增强图像中被模糊的细节或景物的边缘。
 - 线性滤波:运算只是对各像素灰度值进行简单处理(如乘一个权值)最后求和。
 - 非线性滤波:如果对像素灰度值的复杂运算,而不是最后求和的简单运算。
 
在实际应用中,图像平滑常用于以下场景:
- 噪声去除:例如相机传感器产生的椒盐噪声、高斯噪声等
 - 预处理步骤:在边缘检测、特征提取等操作前减少噪声干扰
 - 图像简化:降低图像复杂度,突出主要特征
 
在 OpenCV 中,经常用到的二维图像平滑处理有以下 4 种:均值滤波、高斯滤波、中值滤波和双边滤波。
1.3 线性滤波
概述
常见的线性滤波器:
- 低通滤波器:允许低频率通过;
 - 高通滤波器:允许高频率通过;
 - 带通滤波器 :允许一定区域的频率通过;
 - 带阻滤波器 :阻止一定范围内的频率并且允许其他频率通过;
 - 全通滤波器 :允许所有频率通过,仅仅改变相位;
 - 陷波滤波器(Band stop filter):阻止一个狭窄频率范围通过的特殊带阻滤波器。
 
线性滤波原理
线性邻域滤波是一种常用的邻域算子。邻域算子(局部算子)是利用给定像素周围的像素值的决定此像素的最终输出值的一种算子。下面这个图解可以很好的说明这个过程:
邻域算子(局部算子)是利用给定像素周围的像素值的决定此像素的最终输出值的一种算子。而线性邻域滤波是一种常用的邻域算子,像素的输出值取决于输入像素的加权和,具体过程如下图。

假设有 6x6 的图像像素点矩阵。卷积过程:6x6 上面是个 3x3 的窗口,从左向右,从上向下移动,黄色的每个像个像素点值之和取平均值赋给中心红色像素作为它卷积处理之后新的像素值。
1.4 平滑的基本原理
图像平滑本质上是一种邻域运算,通过对像素及其周围邻域内的像素值进行加权平均来实现。这种运算可以用数学公式表示为:

其中:
f(x,y)f(x,y)*f*(*x*,*y*)是原始图像在位置(x,y)(x,y)(*x*,*y*)处的像素值g(x,y)g(x,y)*g*(*x*,*y*)是处理后图像在相同位置的像素值SS*S*是定义的邻域范围(例如3×3、5×5的矩阵)w(i,j)w(i,j)*w*(*i*,*j*)是邻域内每个点的权重值,不同的平滑方法有不同的权重计算方式
二、均值滤波(Mean Filter)
2.1 原理
图像的简单平滑就是均值滤波,对图像中一定邻域内的像素灰度值求平均值,将平均的结果作为中心像素的灰度保存在结果图中。(在多通道图像中,每个通道需要分别计算。)


2.2 API
void blur(InputArray src, OutputArray dst, Size ksize, 
          Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT);
参数说明:
src:输入图像dst:输出图像,与输入图像大小和类型相同ksize:卷积核大小,例如Size(3,3)表示 3×3 的矩阵anchor:锚点位置,默认值(-1,-1)表示锚点位于核中心borderType:边界处理方式
2.3 示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
    // 读取图像
    Mat image = imread("./lena.jpg", IMREAD_COLOR); // opencv.jpg
    if (image.empty()) {
        cout << "Could not open or find the image" << endl;
        return -1;
    }
    // 均值滤波
    Mat blurred;
    //blur(image, blurred, Size(5, 5)); // 使用5×5的卷积核
    blur(image, blurred, Size(15, 15)); // 使用15×15的卷积核
    // 显示原图和处理后的图像
    imshow("Original Image", image);
    imshow("Blurred Image (Mean Filter)", blurred);
    waitKey(0);
    return 0;
}
滤波器尺寸小,会保留更多细节,平滑模糊效果差一些;滤波器尺寸大,一次处理的图像区域也大,丢失细节更多,模糊效果好一些。
使用 5×5 的卷积核,效果图如下所示:

使用 15×15 的卷积核,效果图如下所示:

可能上面的 lena 图没有噪点,所以看不出滤波的效果,下面换个有噪点的图片,还是使用 5×5 的卷积核,效果图如下所示:

可以看到图案边缘的噪点基本都平滑处理掉了,虽然画面模糊了一些。
2.4 适用场景
均值滤波适用于去除图像中的随机噪声,但可能会导致图像边缘变得模糊。
三、高斯滤波(Gaussian Filter)
3.1 原理
高斯滤波是一种基于高斯函数的平滑处理方法。与均值滤波不同,高斯滤波在计算像素平均值时,会给临近像素赋予更高的权重,而给边缘像素赋予较低的权重。高斯滤波在去除噪声的同时,能够更好地保留图像的边缘信息。

高斯分布(正态分布)
正态分布(高斯分布)是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平滑结果时,只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。如下图所示:

3.2 API
void GaussianBlur(InputArray src, OutputArray dst, Size ksize,
                  double sigmaX, double sigmaY=0,
                  int borderType=BORDER_DEFAULT);
参数说明:
src和dst:输入 / 输出图像ksize:卷积核大小,必须是奇数sigmaX:X 方向的高斯核标准差sigmaY:Y 方向的高斯核标准差,默认与sigmaX相同borderType:边界处理方式
3.3 示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
    // 读取图像
    Mat image = imread("lena.jpg", IMREAD_COLOR); // opencv.jpg
    if (image.empty()) {
        cout << "Could not open or find the image" << endl;
        return -1;
    }
    // 高斯滤波
    Mat gaussianBlur;
    GaussianBlur(image, gaussianBlur, Size(5, 5), 0, 0); // 5×5卷积核,标准差自动计算
    // 显示原图和处理后的图像
    imshow("Original Image", image);
    imshow("Gaussian Blur", gaussianBlur);
    waitKey(0);
    return 0;
}
高斯滤波后的效果图如下所示:


3.4 适用场景
高斯滤波适用于去除图像中的高斯噪声,并且在保留图像边缘信息方面表现较好。
四、中值滤波(Median Filter)
4.1 原理
中值滤波是一种非线性平滑处理方法。它的原理是将图像中每个像素的值替换为其周围像素的中值。中值滤波在去除椒盐噪声(即图像中随机出现的黑白点)时非常有效。

4.2 API
void medianBlur(InputArray src, OutputArray dst, int ksize);
参数说明:
src和dst:输入 / 输出图像ksize:卷积核大小,必须是奇数
4.3 示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
    // 读取图像
    Mat image = imread("lena.jpg", IMREAD_COLOR);
    if (image.empty()) {
        cout << "Could not open or find the image" << endl;
        return -1;
    }
    // 添加椒盐噪声
    Mat noisyImage = image.clone();
    int noiseAmount = 10000;
    for (int i = 0; i < noiseAmount; i++) {
        int x = rand() % noisyImage.cols;
        int y = rand() % noisyImage.rows;
        if (i % 2 == 0) {
            noisyImage.at<Vec3b>(y, x) = Vec3b(255, 255, 255); // 白点
        } else {
            noisyImage.at<Vec3b>(y, x) = Vec3b(0, 0, 0);       // 黑点
        }
    }
    // 中值滤波
    Mat medianFiltered;
    medianBlur(noisyImage, medianFiltered, 5); // 使用5×5邻域
    // 显示原图、噪声图和处理后的图像
    imshow("Original Image", image);
    imshow("Noisy Image", noisyImage);
    imshow("Median Filtered", medianFiltered);
    waitKey(0);
    return 0;
}
中值滤波后的效果图如下所示:

4.4 适用场景
中值滤波适用于去除图像中的椒盐噪声,并且在保留图像边缘信息方面表现较好。
五、双边滤波(Bilateral Filter)
5.1 原理
双边滤波是一种非线性的平滑处理方法,它结合了空间邻近度和像素值相似度。与高斯滤波不同,双边滤波在平滑图像的同时,能够保留图像的边缘信息。这是因为双边滤波不仅考虑像素之间的空间距离,还考虑像素值之间的差异。
一些滤波器再去除噪声的同时会模糊掉图像边缘,为了一定程度上保留边缘,可以选择双边滤波,它是一种保边去噪的滤波方法,它同时考虑了空间距离和颜色差异两个因素:
- 空间域权重:与高斯滤波类似,距离越近权重越高
 - 值域权重:颜色差异越小权重越高
 
5.2 API
void bilateralFilter(InputArray src, OutputArray dst, int d,
                     double sigmaColor, double sigmaSpace,
                     int borderType=BORDER_DEFAULT);
参数说明:
src和dst:输入 / 输出图像d:过滤时使用的像素邻域直径sigmaColor:颜色空间滤波器的标准差sigmaSpace:坐标空间滤波器的标准差borderType:边界处理方式
5.3 示例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
    // 读取图像
    Mat image = imread("lena.jpg", IMREAD_COLOR); // board.jpg
    if (image.empty()) {
        cout << "Could not open or find the image" << endl;
        return -1;
    }
    // 双边滤波
    Mat bilateralFiltered;
    bilateralFilter(image, bilateralFiltered, 15, 80, 80);
    // d=15: 表示在过滤时选取的邻域直径为15像素
    // sigmaColor=80: 颜色空间滤波器的标准差,值越大表示颜色差异越大的像素会被混合在一起
    // sigmaSpace=80: 坐标空间滤波器的标准差,值越大表示距离越远的像素会相互影响
    // 显示原图和处理后的图像
    imshow("Original Image", image);
    imshow("Bilateral Filtered", bilateralFiltered);
    waitKey(0);
    return 0;
}
双边滤波后的效果图如下所示:


5.4 适用场景
双边滤波适用于在去除噪声的同时保留图像的边缘信息,常用于图像美化或预处理。
六、总结与对比
| 方法 | 类型 | 原理 | 优点 | 缺点 | 适用场景 | 
|---|---|---|---|---|---|
| 均值滤波 | 线性 | 邻域平均值 | 速度快 | 模糊边缘 | 初步预处理 | 
| 高斯滤波 | 线性 | 基于高斯函数的加权平均 | 抑制高斯噪声 | 计算复杂度较高 | 大多数场景 | 
| 中值滤波 | 非线性 | 邻域中值替换 | 抑制椒盐噪声 | 不适合高斯噪声 | 椒盐噪声处理 | 
| 双边滤波 | 非线性 | 考虑空间和颜色差异 | 保留边缘 | 计算复杂度极高 | 美颜、细节保留场景 | 
参考:
OpenCV(十一)图像滤波(平滑处理)(平均、中值、高斯、双边滤波)_c++_睿智-华为开发者空间
OpenCV C++ 图像平滑和几何变换_c++ opencv进行平滑滤波-CSDN博客
                                
                                
                
            
        
浙公网安备 33010602011771号