一、什么是图像滤波?
图像滤波是对图像进行平滑、锐化或降噪的处理技术。根据处理方式的不同,分为:
-
线性滤波:输出像素是邻域像素的线性组合(卷积运算)
-
非线性滤波:输出像素是邻域像素的非线性组合(排序、选择等)
二、线性滤波
1. 均值滤波 (Mean/Blur Filter)
原理:计算邻域内所有像素的平均值作为输出
核矩阵:
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
特点:
-
平滑图像,降低噪声
-
会模糊边缘和细节
-
核越大,平滑效果越强
应用场景:噪声初步去除、背景虚化
cv::Mat meanColor;cv::blur(srcColor,meanColor,cv::Size(15,15));
参数说明:cv::Size(k, k) 中的 k 为核边长,通常取奇数。核越大,平滑效果越强,但计算量也越大。
注意事项:均值滤波会导致边缘模糊,且模糊程度与核大小成正比,不适合需要保留细节的场景。
2. 高斯滤波 (Gaussian Filter)
原理:使用高斯函数作为权重,距离中心越近的像素权重越大
特点:
-
平滑图像,同时比均值滤波更好地保留边缘
-
各向同性(各方向效果相同)
-
参数 sigma 控制模糊程度
应用场景:高斯噪声去除、图像预处理
cv::Mat gaussianColor;cv::GaussianBlur(srcColor,gaussianColor,cv::Size(15,15),3.0);
参数说明:cv::GaussianBlur 的核大小 (15,15) 与 sigma=3.0 共同决定平滑强度。若 sigma 设为 0,OpenCV 会根据核大小自动计算合适的值。通常核越大、sigma 越大,模糊越明显。
原理扩展:高斯滤波的卷积核是可分离的(先水平后垂直),因此计算效率较高,OpenCV 内部已实现该优化。
3. 拉普拉斯锐化 (Laplacian Sharpen)
原理:拉普拉斯算子检测图像二阶导数,突出边缘;将边缘信息叠加回原图即可增强细节。下例中 5 的权重相当于 原图 × 1 + 拉普拉斯结果 × 1。
核矩阵:
0 -1 0
-1 5 -1
0 -1 0
特点:
-
增强图像边缘和细节
-
可能放大噪声
-
属于高通滤波器
应用场景:图像锐化、边缘增强、细节突出
cv::Mat laplacianKernel=(cv::Mat_<float>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);cv::Mat laplacianColor;cv::filter2D(srcColor,laplacianColor,srcColor.depth(),laplacianKernel);
注意事项:锐化会同时增强噪声,建议在锐化前先进行轻度降噪(如高斯滤波)。若噪声过大,可改用中心权重更小的核(如 0 -1 0; -1 4 -1; 0 -1 0),但锐化强度会减弱。
三、非线性滤波
1. 中值滤波 (Median Filter)
原理:对邻域像素排序,取中值作为输出
特点:
-
去除椒盐噪声(亮点/黑点)效果极佳
-
保留边缘,不会产生新的模糊
-
计算复杂度较高
应用场景:去除椒盐噪声、脉冲噪声
cv::Mat medianColor;cv::medianBlur(srcColor,medianColor,7);
参数说明 :medianBlur 的第三个参数 ksize 必须是大于1的奇数,例如 3, 5, 7... 核越大,去噪能力越强,但图像细节也会被一定程度平滑,且计算时间线性增长。
适用性:中值滤波是去除椒盐噪声的首选,但对于高斯噪声效果不如高斯滤波。
2. 双边滤波 (Bilateral Filter)
原理:同时考虑空间距离和像素值差异的加权平均
特点:
-
保边平滑:去除噪声的同时保留边缘
-
计算复杂度较高
应用场景:皮肤平滑、保留边缘的降噪、图像增强前后处理
cv::Mat bilateralColor;cv::bilateralFilter(srcColor,bilateralColor,15,50,50);
参数详解:
-
d:滤波时的邻域直径。若为非正数,则由σspace计算得出。 -
σcolor:颜色空间的标准差,值越大,越多的颜色被认为"相似"而被平滑。 -
σspace:坐标空间的标准差,值越大,距离越远的像素对当前像素的影响越大。
典型配置:(d=9, σcolor=50, σspace=50) 可达到保边平滑效果。若效果过强或过弱,可同时调整两个 sigma。
性能提示 :双边滤波计算复杂度高,对实时应用不友好。可改用快速近似算法(如 cv::ximgproc::fastBilateralFilter)或先降采样再滤波后上采样。
四、效果对比总结

五、完整代码实现
以下是使用 OpenCV 实现上述 5 种滤波的完整 C++ 代码(注意路径和字体设置位置等以实际情况进行调整):
cpp
/**
* 图像滤波效果对比演示程序
* 展示线性滤波与非线性滤波的效果差异
*
* 滤波算法分类:
* - 线性滤波:均值滤波、高斯滤波、锐化(拉普拉斯核)
* - 非线性滤波:中值滤波、双边滤波
*/
#include <opencv2/opencv.hpp>
#include <opencv2/freetype.hpp>
#include <iostream>
int main() {
// ==================== 1. 读取图像 ====================
// cv::imread() 读取图像文件,返回 cv::Mat 对象(矩阵)
// 如果读取失败,返回空矩阵,通过 empty() 判断
cv::Mat src = cv::imread("data/man.jpeg");
if (src.empty()) {
std::cout << "无法读取图像" << std::endl;
return -1;
}
// 克隆图像,避免直接修改原图
cv::Mat srcColor = src.clone();
int imgW = src.cols; // 图像宽度(列数)
int imgH = src.rows; // 图像高度(行数)
// ==================== 2. 线性滤波 ====================
// 线性滤波特点:输出像素是邻域像素的线性组合(卷积运算)
// 公式:g(x,y) = Σ f(x+i, y+j) * h(i,j)
/**
* 均值滤波 (Mean/Blur Filter)
* 原理:计算邻域内所有像素的平均值
* 效果:平滑图像,降低噪声,但会模糊边缘
* cv::blur(输入, 输出, 核大小)
* 核大小 15x15:邻域范围,越大平滑效果越强
*/
cv::Mat meanColor;
cv::blur(srcColor, meanColor, cv::Size(15, 15));
/**
* 高斯滤波 (Gaussian Filter)
* 原理:使用高斯函数作为权重,距离中心越近的像素权重越大
* 效果:平滑图像,同时保留更多边缘信息
* cv::GaussianBlur(输入, 输出, 核大小, sigmaX, sigmaY)
* sigmaX/Y:标准差,控制模糊程度
*/
cv::Mat gaussianColor;
cv::GaussianBlur(srcColor, gaussianColor, cv::Size(15, 15), 3.0);
/**
* 拉普拉斯锐化 (Laplacian Sharpen)
* 原理:使用拉普拉斯算子检测边缘,增强图像锐度
* 核矩阵:
* 0 -1 0
* -1 5 -1
* 0 -1 0
* 效果:边缘更清晰,但可能放大噪声
* cv::filter2D():自定义卷积核滤波
*/
cv::Mat laplacianKernel = (cv::Mat_<float>(3, 3) <<
0, -1, 0,
-1, 5, -1,
0, -1, 0);
cv::Mat laplacianColor;
cv::filter2D(srcColor, laplacianColor, srcColor.depth(), laplacianKernel);
// ==================== 3. 非线性滤波 ====================
// 非线性滤波特点:输出像素是邻域像素的非线性组合(排序、选择等)
// 不满足叠加原理,无法用卷积表示
/**
* 中值滤波 (Median Filter)
* 原理:对邻域像素排序,取中值作为输出
* 效果:去除椒盐噪声(亮点/黑点),同时保留边缘
* cv::medianBlur(输入, 输出, 核大小)
* 核大小必须是奇数:3, 5, 7...
*/
cv::Mat medianColor;
cv::medianBlur(srcColor, medianColor, 7);
/**
* 双边滤波 (Bilateral Filter)
* 原理:同时考虑空间距离和像素值差异的加权平均
* 效果:保边平滑(去除噪声的同时保留边缘)
* cv::bilateralFilter(输入, 输出, 邻域直径, 颜色空间 sigma, 坐标空间 sigma)
* 参数越大,平滑效果越强,边缘保持越好
*/
cv::Mat bilateralColor;
cv::bilateralFilter(srcColor, bilateralColor, 15, 50, 50);
// ==================== 4. 创建画布 ====================
int titleH = 70; // 标题区域高度
int cols = 3; // 每行显示3个
int rows = 2; // 共2行
int canvasW = cols * imgW; // 画布宽度
int canvasH = rows * (imgH + titleH); // 画布高度
// 创建白色画布
cv::Mat canvas(canvasH, canvasW, CV_8UC3, cv::Scalar(40, 40, 40));
// 存储所有处理结果
cv::Mat results[6] = {
srcColor, // 0: 原图
meanColor, // 1: 均值滤波
gaussianColor, // 2: 高斯滤波
laplacianColor, // 3: 拉普拉斯锐化
medianColor, // 4: 中值滤波
bilateralColor // 5: 双边滤波
};
// ==================== 5. 拼接图像 ====================
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int idx = i * cols + j;
if (idx < 6) {
// 计算当前图像在画布上的位置
int x = j * imgW;
int y = i * (imgH + titleH) + titleH;
// 复制图像到画布对应位置
cv::Mat roi = canvas(cv::Rect(x, y, imgW, imgH));
results[idx].copyTo(roi);
// 绘制标题背景区域
cv::Mat labelBg = canvas(cv::Rect(x, y - titleH, imgW, titleH));
labelBg.setTo(cv::Scalar(50, 50, 50));
}
}
}
// ==================== 6. 添加中文标签 ====================
// 使用FreeType2模块加载中文字体,支持中文显示
cv::Ptr<cv::freetype::FreeType2> ft2 = cv::freetype::createFreeType2();
ft2->loadFontData("/System/Library/Fonts/STHeiti Medium.ttc", 0);
// 第一行标签(线性滤波)
ft2->putText(canvas, "原图", cv::Point(30, 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
ft2->putText(canvas, "均值滤波", cv::Point(imgW + 30, 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
ft2->putText(canvas, "高斯滤波", cv::Point(2*imgW + 30, 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
// 第二行标签(非线性滤波)
ft2->putText(canvas, "拉普拉斯锐化", cv::Point(30, imgH + titleH + 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
ft2->putText(canvas, "中值滤波", cv::Point(imgW + 30, imgH + titleH + 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
ft2->putText(canvas, "双边滤波", cv::Point(2*imgW + 30, imgH + titleH + 80 + 20), 30,
cv::Scalar(230, 216, 173), cv::FILLED, cv::LINE_AA, false);
// ==================== 7. 保存并显示 ====================
cv::imwrite("data/filter_comparison.png", canvas);
std::cout << "图片已生成: data/filter_comparison.png" << std::endl;
// 显示图像窗口,按任意键关闭
cv::imshow("滤波效果对比", canvas);
cv::waitKey(0);
return 0;
}
六、快速运行指南
环境要求
-
OpenCV 4.x 已安装
-
C++ 编译器(g++ 或 clang++)
-
macOS / Linux / Windows
编译命令详解
g++filter_comparison.cpp-ofilter_comparison\$(pkg-config --cflags --libs opencv4) -std=c++11 \&&./filter_comparison
各部分含义:

💡提示:在 Windows 上可能需要手动指定 OpenCV 路径,或使用 CMake 构建项目。
查看结果图片


| 滤波类型 | 预期效果 | 实际观察 | 评价 |
|---|---|---|---|
| 原图 | 清晰基准 | 清晰,细节完整 | ✅ 正常 |
| 均值滤波 | 整体模糊,有块状感 | 明显模糊,边缘扩散 | ✅ 符合预期 |
| 高斯滤波 | 平滑模糊,边缘保留较好 | 柔和模糊,比均值更自然 | ✅ 符合预期 |
| 拉普拉斯锐化 | 边缘增强,细节突出 | 出现部分噪点和颗粒感 | ⚠️ 参数可能过强 |
| 中值滤波 | 去噪同时保边缘 | 有一定模糊,但边缘比均值清晰 | ✅ 符合预期 |
| 双边滤波 | 平滑区域,锐化边缘 | 背景平滑,西装条纹和面部边缘稍浅 | ✅ 符合预期 |
Python 版本(可选)
如果不熟悉 C++,也可以用 Python 实现相同效果:
python
import cv2
import numpy as np
src = cv2.imread('man.jpeg')
# 均值滤波
mean = cv2.blur(src, (15, 15))
# 高斯滤波
gaussian = cv2.GaussianBlur(src, (15, 15), 3.0)
# 拉普拉斯锐化
kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]], dtype=np.float32)
laplacian = cv2.filter2D(src, -1, kernel)
# 中值滤波
median = cv2.medianBlur(src, 7)
# 双边滤波
bilateral = cv2.bilateralFilter(src, 15, 50, 50)
# 拼接并保存...
七、结语
选择合适的滤波算法需要根据具体需求:
-
快速平滑 → 均值滤波
-
保边平滑 → 双边滤波
-
去椒盐噪声 → 中值滤波
-
边缘增强 → 拉普拉斯锐化
-
通用预处理 → 高斯滤波
创作不易,禁止抄袭,转载请附上原文链接及标题