滤波:图像处理中的一种基本操作,通过对图像像素及其邻域像素进行某种数学运算来改变图像的特性。
- 线性滤波:输出像素值是输入像素值的线性组合,线性滤波算法有均值滤波,高斯滤波,方框滤波
- 非线性滤波:输出像素值不是输入像素值的线性函数,非线性滤波算法有中值滤波,双边滤波
方框滤波
- 方框滤波:方框滤波计算像素邻域内所有像素值的和(非归一化方框滤波)或平均值(归一化方框滤波,此时等同于均值滤波)。
- 示例程序如下所示:
cv::Mat image = cv::imread("test.png");
if (image.empty()) {
std::cout << "无法加载图像!" << std::endl;
return;
}
cv::Mat normalized, non_normalized;
// 1. 归一化方框滤波(等同于均值滤波)
cv::boxFilter(image, normalized, -1, cv::Size(5, 5), cv::Point(-1, -1), true);
// 2. 非归一化方框滤波(像素值求和)
cv::boxFilter(image, non_normalized, -1, cv::Size(5, 5), cv::Point(-1, -1), false);
cv::imshow("原图", image);
cv::imshow("归一化方框滤波", normalized);
cv::imshow("非归一化方框滤波", non_normalized);
// 查看像素值范围
double min_norm, max_norm, min_non, max_non;
cv::minMaxLoc(normalized, &min_norm, &max_norm);
cv::minMaxLoc(non_normalized, &min_non, &max_non);
std::cout << "归一化方框滤波像素范围: [" << min_norm << ", " << max_norm << "]" << std::endl;
std::cout << "非归一化方框滤波像素范围: [" << min_non << ", " << max_non << "]" << std::endl;
cv::waitKey(0);
高斯滤波
- 高斯滤波:使用高斯函数作为权重,距离中心像素越近的像素权重越大,平滑效果更好且能保留边缘信息
- 示例程序如下所示:
cv::Mat image = cv::imread("test.png");
if (image.empty()) return;
cv::Mat result;
// 不同参数的高斯滤波
// cv::GaussianBlur(输入, 输出, 核大小, X方向标准差, Y方向标准差)
cv::GaussianBlur(image, result, cv::Size(3, 3), 0, 0);
cv::imshow("原图", image);
cv::imshow("3x3高斯滤波(sigma=0)", result);
cv::GaussianBlur(image, result, cv::Size(5, 5), 1.0, 1.0);
cv::imshow("5x5高斯滤波(sigma=1.0)", result);
cv::GaussianBlur(image, result, cv::Size(9, 9), 2.0, 2.0);
cv::imshow("9x9高斯滤波(sigma=2.0)", result);
// 只在一个方向进行高斯模糊
cv::GaussianBlur(image, result, cv::Size(15, 1), 0, 0);
cv::imshow("水平方向高斯滤波", result);
cv::GaussianBlur(image, result, cv::Size(1, 15), 0, 0);
cv::imshow("垂直方向高斯滤波", result);
cv::waitKey(0);
均值滤波
- 均值滤波:用邻域像素的平均值代替中心像素值,即任意一点的像素值都是周围
N*M个像素的算术平均值,起到平滑图像、去除噪声的作用。 - 数学本质:一个矩阵与另一个矩阵的乘积
- 示例程序如下所示:使用不同大小的归一化的卷积核进行均值滤波操作。(归一化的意思是权重和为1)
cv::Mat image = cv::imread("test.png");
if (image.empty()) {
std::cout << "无法加载图像!" << std::endl;
return;
}
cv::Mat result;
// 不同核大小的均值滤波
// 3 x 3的卷积核如下所示
// 1/9 1/9 1/9
// 1/9 1/9 1/9
// 1/9 1/9 1/9
cv::blur(image, result, cv::Size(3, 3)); // 3x3核
cv::imshow("原图", image);
cv::imshow("3x3均值滤波", result);
cv::blur(image, result, cv::Size(5, 5)); // 5x5核
cv::imshow("5x5均值滤波", result);
cv::blur(image, result, cv::Size(9, 9)); // 9x9核
cv::imshow("9x9均值滤波", result);
cv::waitKey(0);
双边滤波
- 双边滤波:结合空间距离和像素值相似性的加权平均,能在平滑图像的同时保持边缘清晰
- 示例程序如下所示:
cv::Mat image = cv::imread("test.png");
if (image.empty()) return;
cv::Mat result;
// 双边滤波参数说明:
// d: 邻域直径
// sigmaColor: 颜色空间的标准差
// sigmaSpace: 坐标空间的标准差
cv::bilateralFilter(image, result, 9, 75, 75);
cv::imshow("原图", image);
cv::imshow("双边滤波(d=9, sigma=75)", result);
cv::bilateralFilter(image, result, 15, 50, 50);
cv::imshow("双边滤波(d=15, sigma=50)", result);
cv::bilateralFilter(image, result, 15, 100, 100);
cv::imshow("双边滤波(d=15, sigma=100)", result);
// 与高斯滤波对比
cv::Mat gaussian_result;
cv::GaussianBlur(image, gaussian_result, cv::Size(15, 15), 0, 0);
cv::imshow("高斯滤波对比", gaussian_result);
cv::waitKey(0);
中值滤波
- 中值滤波:领域像素的中位数
- 示例程序如下所示:
// 创建带椒盐噪声的图像
cv::Mat image = cv::imread("test.png", cv::IMREAD_COLOR);
if (image.empty()) return;
// 添加椒盐噪声(随机出现的白点或黑点)
cv::Mat noisy_image = image.clone();
int noise_amount = 1000; // 噪声点数
for (int i = 0; i < noise_amount; i++) {
int x = rand() % noisy_image.cols;
int y = rand() % noisy_image.rows;
if (i % 2 == 0) {
noisy_image.at<uchar>(y, x) = 255; // 盐噪声
}
else {
noisy_image.at<uchar>(y, x) = 0; // 椒噪声
}
}
cv::Mat result;
// 中值滤波
cv::medianBlur(noisy_image, result, 3); // 3x3核
cv::imshow("带噪声图像", noisy_image);
cv::imshow("3x3中值滤波", result);
cv::medianBlur(noisy_image, result, 5); // 5x5核
cv::imshow("5x5中值滤波", result);
cv::medianBlur(noisy_image, result, 7); // 7x7核
cv::imshow("7x7中值滤波", result);
cv::waitKey(0);
浙公网安备 33010602011771号