[OpenCV] 数字图像处理 C++ 学习——07图像模糊 附完整代码(小白入门篇)

前言

图像模糊是图像处理中非常常见的操作之一,用于减少图像中的噪声和细节,使图像看起来更加平滑。OpenCV 提供了多种模糊技术,如均值模糊、高斯模糊、中值模糊和双边滤波等。本篇博客将介绍几种常用的图像模糊方法,并通过代码示例演示如何在 OpenCV 中实现这些方法,最后附上完整代码以便学习使用。

1.图像卷积

卷积是图像处理中用来实现模糊、锐化等效果的基础操作。它的工作原理是将一个小的核(通常称为滤波器)在图像上滑动,通过核与图像的局部区域进行元素级的乘积和求和,从而计算出新的像素值。卷积操作可以用公式表达为:
G ( x , y ) = ∑ i = − k k ∑ j = − k k K ( i , j ) ⋅ I ( x + i , y + j ) G(x, y) = \sum_{i=-k}^k \sum_{j=-k}^k K(i, j) \cdot I(x+i, y+j) G(x,y)=i=kkj=kkK(i,j)I(x+i,y+j)
其中:

  • G(x, y) 是输出图像的像素值。
  • K(i, j) 是卷积核的值。
  • I(x+i, y+j) 是输入图像的像素值。

下面这张图演示了一个 3x3 的卷积核应用于图像不同位置的过程:
在这里插入图片描述

左图:卷积核覆盖的区域以红色和黄色高亮显示。红色部分是当前像素,黄色部分是卷积核作用的周围像素。

中图:卷积核向下移动一行,覆盖新区域。

右图:卷积核继续移动,覆盖新的区域。

通过卷积,图像中的每个像素都会根据其周围像素的值重新计算,从而实现模糊效果。

2.图像读取

读取图像是下面图像模糊处理的基础,本实验使用了3张图片,有需要可以下载使用。
这一部分不太了解建议从头开始学习[OpenCV] 数字图像处理 C++ 学习——01图像的读取、加载和保存附完整代码(小白入门篇)

图片链接图片1 sherlock.jpg
图片2 椒盐噪声.png
图片3 Bilateral.jpg

	cv::Mat image;
	image = imread("sherlock.jpg");
	if (image.empty()) {
		printf("could not find the image...\n");
		return;
	}
	namedWindow("input image", cv::WINDOW_AUTOSIZE);
	cv::imshow("input image", image);

	cv::Mat gege;
	gege = imread("椒盐噪声.png");
	if (gege.empty()) {
		printf("could not find the image...\n");
		return;
	}
	cv::imshow("gege", gege);

	cv::Mat Bilateral;
	Bilateral = imread("Bilateral.jpg");
	if (Bilateral.empty()) {
		printf("could not find the image...\n");
		return;
	}
	cv::imshow("Bilateral", Bilateral);	

3.均值模糊 (Mean Blurring)

均值模糊是一种简单的图像平滑技术,通过取窗口内所有像素的平均值来替换中心像素的值。它能有效去除图像中的噪声,但也会使边缘变得模糊。均值模糊可以使用 cv::blur() 函数实现。
G ( x , y ) = 1 ( 2 k + 1 ) 2 ∑ i = − k k ∑ j = − k k I ( x + i , y + j ) G(x, y) = \frac{1}{(2k+1)^2} \sum_{i=-k}^k \sum_{j=-k}^k I(x+i, y+j) G(x,y)=(2k+1)21i=kkj=kkI(x+i,y+j)
$G(x, y) $是输出图像在位置 (x, y)的像素值。

I ( x + i , y + j ) I(x+i, y+j) I(x+i,y+j)是输入图像在位置 ( x + i , y + j ) (x+i, y+j) (x+i,y+j)的像素值。

k 是卷积核的半径,卷积核大小为 ( 2 k + 1 ) × ( 2 k + 1 ) (2k+1)×(2k+1) (2k+1)×(2k+1)

例如一个3*3的模板:
在这里插入图片描述

均值模糊代码实现(cv::blur())

cv::blur() 函数来实现均值模糊,使用一个 5x5 的内核,对图像进行简单的平滑处理,适用于一般的噪声去除。

	//均值模糊
	cv::Mat meanBlurredImage;
	cv::blur(image, meanBlurredImage, cv::Size(5, 5)); // 使用 5x5 的内核进行均值模糊
	cv::imshow("meanBlurredImage", meanBlurredImage);

结果
在这里插入图片描述

4.高斯模糊 (Gaussian Blurring)

高斯模糊是通过高斯核函数对图像进行卷积来实现的。它能够有效地平滑图像,同时减少边缘的模糊程度。高斯模糊是通过在模糊过程中给像素分配不同的权重来实现的。OpenCV 提供的 cv::GaussianBlur() 函数可以用来实现高斯模糊。

高斯滤波器详解

在这里插入图片描述

左侧图像展示了 1D 高斯分布函数,其中 G(x)表示一个标准的高斯曲线。曲线的高度由标准差 σ控制。标准差越大,曲线越平缓,模糊效果越明显;标准差越小,曲线越尖锐,模糊效果越弱。

右侧图像展示了 2D 高斯分布的形状,它是 1D 高斯函数在二维空间中的扩展。这里 G(x,y) 描述了一个高斯核的形状,核的中心有最高的权重(离中心越近的像素对结果影响越大),四周逐渐减少。高斯核通过与图像进行卷积操作,使图像达到平滑的效果。

高斯模糊代码实现 (cv::GaussianBlur())

高斯模糊采用高斯函数计算加权平均值,更强调中心像素的影响,从而有效地减少噪声并保留一定的边缘特性。

	//高斯模糊
	cv::Mat gaussianBlurredImage;
	cv::GaussianBlur(image, gaussianBlurredImage, cv::Size(5, 5), 0.5); // 使用 5x5 的高斯内核和标准差为 0.5 进行高斯模糊
	cv::imshow("gaussianBlurredImage", gaussianBlurredImage);

结果

左图为标准差0.5高斯模糊,右图为标准差3.0高斯模糊,右侧图像比左侧图像更模糊,所以标准差越大,曲线越平缓,模糊效果越明显。
在这里插入图片描述

5.中值模糊 (Median Blurring)

中值模糊通过在窗口内取像素值的中值来替换中心像素值,适合去除“椒盐噪声”。与均值模糊相比,中值模糊能更好地保留图像的边缘信息。使用 cv::medianBlur() 函数来实现中值模糊。
G ( x , y ) = median { I ( x + i , y + j ) ∣ − k ≤ i , j ≤ k } G(x, y) = \text{median} \{ I(x+i, y+j) \mid -k \leq i, j \leq k \} G(x,y)=median{I(x+i,y+j)ki,jk}
$median $表示在卷积核范围内取所有像素值的中值。

k是卷积核的半径。

中值模糊代码实现 (cv::medianBlur())

	//中值模糊
	cv::Mat medianBlurredImage;
	cv::medianBlur(gege, medianBlurredImage, 5); // 使用 5x5 的内核进行中值模糊
	cv::imshow("medianBlurredImage", medianBlurredImage);

结果:

左图显示了未处理的图像,其中存在明显的“椒盐噪声”;右图经过中值模糊处理,噪声被有效去除,“哥哥”明显变得更加平滑和清晰。
在这里插入图片描述

6.双边滤波 (Bilateral Filtering)

双边滤波是一种高级的图像模糊技术,它不仅考虑像素的空间距离,还考虑像素的颜色差异,从而在平滑图像的同时保持边缘锐利。OpenCV 提供的 cv::bilateralFilter() 函数可以用来实现双边滤波。
G ( x , y ) = 1 W p ∑ i = − k k ∑ j = − k k I ( x + i , y + j ) ⋅ e − i 2 + j 2 2 σ s 2 ⋅ e − ( I ( x + i , y + j ) − I ( x , y ) ) 2 2 σ r 2 G(x, y) = \frac{1}{W_p} \sum_{i=-k}^k \sum_{j=-k}^k I(x+i, y+j) \cdot e^{-\frac{i^2 + j^2}{2\sigma_s^2}} \cdot e^{-\frac{(I(x+i, y+j) - I(x, y))^2}{2\sigma_r^2}} G(x,y)=Wp1i=kkj=kkI(x+i,y+j)e2σs2i2+j2e2σr2(I(x+i,y+j)I(x,y))2
W p Wp Wp 是归一化因子,确保权重总和为1。

σ s σs σs 是空间标准差,控制空间距离的权重。

σ r σr σr是颜色标准差,控制像素值相似性的权重。

在平缓区域

在图像变化平缓的区域,邻域中的像素值$ I(x+i,y+j)$与中心像素 $I(x,y) $相差不大,因此颜色相似性项 e − ( I ( x + i , y + j ) − I ( x , y ) ) 2 2 σ r 2 e^{-\frac{(I(x+i, y+j) - I(x, y))^2}{2\sigma_r^2}} e2σr2(I(x+i,y+j)I(x,y))2 接近于 1。此时,双边滤波公式中的空间距离项$ e{-\frac{i2 + j2}{2\sigma_s2}}$ 起主要作用,双边滤波的效果类似于高斯滤波,对图像进行平滑处理。
图片来自于网络

在剧烈变化区域(如边缘)

在图像的边缘区域,邻域中的像素值$ I(x+i,y+j) 与中心像素 与中心像素 与中心像素I(x,y) $ 之间的差异较大。这时,颜色相似性项 e − ( I ( x + i , y + j ) − I ( x , y ) ) 2 2 σ r 2 e^{-\frac{(I(x+i, y+j) - I(x, y))^2}{2\sigma_r^2}} e2σr2(I(x+i,y+j)I(x,y))2 会趋近于 0。由于这个权重很小,这些颜色差异大的像素对输出$ G(x,y)$的影响也非常小。因此,双边滤波在这种情况下能够保持边缘的清晰度,避免了普通高斯滤波导致的边缘模糊。

图片来自于网络

双边滤波代码实现 (cv::medianBlur())

cv::bilateralFilter() 函数,内核大小为 9,空间和颜色标准差均为 75。双边滤波可以在去除噪声的同时保持图像边缘清晰。

	//双边模糊
	cv::Mat bilateralFilterImage;
	cv::bilateralFilter(Bilateral, bilateralFilterImage, 9, 75, 75); // 使用双边滤波,窗口大小为9,空间和颜色标准差均为75
	cv::imshow("bilateralFilterImage", bilateralFilterImage);

结果:

右图经过双边滤波处理,皮肤细节得到了平滑,面部的边缘和特征线条仍然保持清晰。

在这里插入图片描述

完整代码

#include<opencv2/opencv.hpp>
#include<highgui.hpp>

using namespace cv;
using namespace std;

void image_blur()
{
	cv::Mat image;
	image = imread("sherlock.jpg");
	if (image.empty()) {
		printf("could not find the image...\n");
		return;
	}
	namedWindow("input image", cv::WINDOW_AUTOSIZE);
	cv::imshow("input image", image);

	cv::Mat gege;
	gege = imread("椒盐噪声.png");
	if (gege.empty()) {
		printf("could not find the image...\n");
		return;
	}
	cv::imshow("gege", gege);

	cv::Mat Bilateral;
	Bilateral = imread("Bilateral.jpg");
	if (Bilateral.empty()) {
		printf("could not find the image...\n");
		return;
	}
	cv::imshow("Bilateral", Bilateral);

	//均值模糊
	cv::Mat meanBlurredImage;
	cv::blur(image, meanBlurredImage, cv::Size(5, 5)); // 使用 5x5 的内核进行均值模糊
	cv::imshow("meanBlurredImage", meanBlurredImage);
	//高斯模糊
	cv::Mat gaussianBlurredImage;
	cv::GaussianBlur(image, gaussianBlurredImage, cv::Size(5, 5), 0.5); // 使用 5x5 的高斯内核和标准差为 0.5 进行高斯模糊
	cv::imshow("gaussianBlurredImage", gaussianBlurredImage);
	//中值模糊
	cv::Mat medianBlurredImage;
	cv::medianBlur(gege, medianBlurredImage, 5); // 使用 5x5 的内核进行中值模糊
	cv::imshow("medianBlurredImage", medianBlurredImage);
	//双边模糊
	cv::Mat bilateralFilterImage;
	cv::bilateralFilter(Bilateral, bilateralFilterImage, 9, 75, 75); // 使用双边滤波,窗口大小为9,空间和颜色标准差均为75
	cv::imshow("bilateralFilterImage", bilateralFilterImage);

	cv::waitKey(0);
}
int main() 
{
	image_blur();         //图像模糊处理
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mirror_zAI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值