目录
引言
在图像处理中,噪声是影响图像质量的常见问题,可能由传感器性能、环境干扰等多种因素导致。图像平滑处理(Image Smoothing)通过抑制噪声来增强图像质量,同时尽可能保留图像的重要特征(如边缘、纹理)。本文将详细介绍 OpenCV 中四种常用的平滑处理方法,包括原理、实现及适用场景。
一、图像平滑的基本概念
图像平滑本质上是一种低通滤波操作:通过模糊图像来减弱高频分量(噪声、边缘等变化剧烈的区域),保留低频分量(平滑区域)。核心目标是:
- 去除图像中的噪声(如高斯噪声、椒盐噪声)
- 减少图像细节,简化后续处理(如特征提取、目标检测)
OpenCV 提供了多种平滑处理函数,其核心原理是通过卷积操作实现 —— 用一个卷积核(滤波窗口)在图像上滑动,计算窗口内像素的加权平均值作为中心像素的新值。
(1)椒盐噪声生成函数
生成噪声的方法有很多种,这里只提供一种思路。
import numpy as np
def add_peppersalt_noise(image, n=10000):
result = image.copy()
h, w = image.shape[:2] # 获取图片的高和宽
for i in range(n): # 生成n个椒盐噪声
x = np.random.randint(1, h) #在1~h之间随机产生一个数
y= np.random.randint(1, w) #在1~w之间随机产生一个数
if np.random.randint(0, 2) == 0: #随机产生0和1,两者产生的概率相同
result[x, y] = 0
else:
result[x,y] = 255
return result
#随机产生黑点和白点,总共产生10000个椒盐噪声点
image=cv2.imread('Dog.png')
image=cv2.resize(image,(400,400))
cv2.imshow('yunatu',image)
cv2.waitKey(0)
noise=add_peppersalt_noise(image)
cv2.imshow('noise',noise)
cv2.waitKey(0)
二、四种常用平滑处理方法
1.均值滤波
原理:
均值滤波(Mean filtering):是指用当前像素点周围nxn个像素值的均值来代替当前像素值。边界点的处理可以扩展当前图像的周围像素点padding。
特点
- 计算速度快,实现简单。
- 缺点:会模糊图像边缘,对噪声的抑制效果一般。
import cv2
dst=cv2.blur(src,ksize,anchor,borderType)
参数:
dst是返回值,src是需要处理的图像,kszie是滤波核(卷积核)的大小,anchor是锚点,默认值是(-1,-1)一般无需更改 borderType是边界样式,一般无需更改 一般情况下,使用dst=cv2.blur(src,ksize)即可。
import cv2
import numpy as np
def add_peppersalt_noise(image,n=10000):
result=image.copy()
h,w=image.shape[:2]
for i in range(n):
x=np.random.randint(1,h)
y=np.random.randint(1,w)
if np.random.randint(0,2)==0:
result[x,y]=0
else:
result[x,y]=255
return result
image=cv2.imread('Dog.png')
image=cv2.resize(image,(400,400))
cv2.imshow('yuantu',image)
cv2.waitKey(0)
noise=add_peppersalt_noise(image)
cv2.imshow('noise',noise)
cv2.waitKey(0)
blur_1 = cv2.blur(noise, (3, 3)) # 卷积核为3,3 效果一般,清晰度一般
cv2.imshow('blur_1', blur_1)
cv2.waitKey(0)
效果:核越大损失的特征会增加,减少特征损失的方法就是设置padding边界填充,可以使周围的边缘的点利用次数增加。
2.方框滤波
原理:
方框滤波是指用当前像素点周围nXn个像素值的和来替代当前像素值。
dst=cv2.boxFilter(src,ddepth,ksize,anchor,normalize,borderType)
参数: dst是返回值,表示进行方框滤波后得到的处理结果。 ● src 是需要处理的图像,即原始图像。 ● ddepth是处理结果图像的图像深度,一般使用-1表示与原始图像使用相同的图像深度。(可以理解为数据类型) ● ksize 是滤波核的大小。滤波核大小是指在滤波处理过程中所选择的邻域图像的高 度和宽度。 ● anchor 是锚点,(指对应哪个区域) ● normalize 表示在滤波时是否进行归一化。 1.当值为True时,归一化,用邻域像素值的和除以面积。 此时方框滤波与 均值滤波 效果相同。 2.当值为False时,不归一化,直接使用邻域像素值的和。和>255时使用255
boxFilter_1 = cv2.boxFilter(noise,-1,(3,3),normalize = True)
cv2.imshow('boxFilter_1',boxFilter_1)
cv2.waitKey(0)
boxFilter_2 = cv2.boxFilter(noise,-1,(3,3),normalize = False)
cv2.imshow('boxFilter_2',boxFilter_2)
cv2.waitKey(0)
效果:做了归一化之后图像更加均衡,不做归一化中心点的值是周围像素值的和,所以中心点的数值大概率会大于255,大于255的值会被设为255,所以不做归一化整个图像会呈现出更亮的效果。
3.高斯滤波
原理:对整幅图像进行加权平均的过程,每一个像素点的值,都是由其本身和邻域内的其他像素值经过加权平均后得到。
GaussianB = cv2.GaussianBlur(noise,(3,3),1) #标准差为1,标准正态分布。
cv2.imshow('GaussianBlur',GaussianB)
cv2.waitKey(0)
4.中值滤波
原理:中值滤波:会取当前像素点及其周围临近像素点(一共有奇数个像素点)的像素值,将这些像素值从小到大排序,然后将位于中间位置的像素值作为当前像素点的像素值。
[0,48,56,95,128,130,212,215,250]
参数:
cv2.medianBlur(src, ksize[, dst])
参数说明: src:输入图像。 ksize:滤波器的大小,它是一个整数,表示在水平和垂直方向上的像素数量。例如,5表示一个5x5的滤波器。 dst:输出图像,通常是一个NumPy数组。如果为None,则会创建一个新的数组来存储结果。
medianB = cv2.medianBlur(noise,5)
cv2.imshow('medianBlur',medianB)
cv2.waitKey(0)
cv2.destroyAllWindows()
总结:通过上面的对比,可以看出中值滤波处理这样的噪声点的效果比其他的平滑效果要更好。
三、小案列:视频椒盐噪声去除与实时滤波
在视频处理中,噪声会严重影响图像质量,影响后续分析。本案例将展示如何给视频添加椒盐噪声,并使用中值滤波实时去除噪声,通过对比原始视频、带噪声视频和滤波后视频,直观感受中值滤波的去噪效果。
1.案例效果说明
本案例实现以下功能:
读取本地视频文件
为视频帧添加椒盐噪声(随机出现的黑白点)
使用中值滤波实时去除噪声
同时显示原始视频、带噪声视频和滤波后视频
2.代码解析
1. 导入库
import cv2 # 导入OpenCV库,用于图像处理和视频操作
import numpy as np # 导入NumPy库,用于数值计算和随机数生成
2. 椒盐噪声添加函数
def add_peppersalt_noise(image, n=10000):
# 复制原始图像,避免直接修改输入图像(保护原图数据)
result = image.copy()
# 获取图像的高度(h)和宽度(w),shape[:2]表示取前两个维度(忽略通道数)
h, w = image.shape[:2]
# 循环n次,生成n个噪声点
for i in range(n):
# 随机生成噪声点的x坐标(0到h-1之间)
x = np.random.randint(0, h)
# 随机生成噪声点的y坐标(0到w-1之间)
y = np.random.randint(0, w)
# 50%概率生成黑色噪声点,50%生成白色噪声点
if np.random.randint(0, 2) == 0:
result[x, y] = 0 # 黑色噪声点(BGR通道均为0)
else:
result[x, y] = 255 # 白色噪声点(BGR通道均为255)
# 返回添加噪声后的图像
return result
- 功能:给图像添加椒盐噪声(随机出现的黑白点)
- 参数:
image
为输入图像,n
为噪声点数量(默认 1000 个) - 原理:通过随机坐标在图像上生成黑白点,模拟椒盐噪声特征
3. 视频读取与初始化
# 创建视频捕获对象,读取本地视频文件(路径需替换为实际视频位置)
video = cv2.VideoCapture(r'C:\Users\23967\xwechat_files\wxid_v89f4ju66y4h22_d879\msg\file\2025-08\test.avi')
# 检查视频是否成功打开
if not video.isOpened():
print("无法打开视频文件 'test.avi'") # 打开失败时提示
exit() # 退出程序
cv2.VideoCapture
:用于读取视频文件或摄像头流isOpened()
:检查视频是否成功加载,失败则退出程序
4. 视频帧处理循环
while True:
# 读取一帧视频,ret为布尔值(是否读取成功),frame为当前帧图像
ret, frame = video.read()
# 如果读取失败(如视频结束),退出循环
if not ret:
print("视频播放完毕或读取失败")
break
# 给当前帧添加椒盐噪声
noisy_frame = add_peppersalt_noise(frame)
# 使用中值滤波去除噪声,参数3表示3x3的卷积核(必须为奇数)
filtered_frame = cv2.medianBlur(noisy_frame, 3)
# 显示三个窗口进行对比
cv2.imshow('Original Video', frame) # 原始视频窗口
cv2.imshow('Video with Noise', noisy_frame) # 带噪声视频窗口
cv2.imshow('Filtered Video', filtered_frame)# 滤波后视频窗口
# 等待25毫秒(控制视频播放速度),按'q'键退出循环
if cv2.waitKey(25) & 0xFF == ord('q'):
break
- 核心流程:逐帧读取视频→添加噪声→滤波处理→显示对比
cv2.medianBlur
:中值滤波函数,特别适合去除椒盐噪声(用邻域像素的中值替换中心像素,能有效剔除极端值)cv2.waitKey(25)
:控制视频帧率(约 40 帧 / 秒),同时监听按键事件
5. 资源释放
video.release() # 释放视频捕获对象,关闭视频文件
cv2.destroyAllWindows()# 关闭所有OpenCV创建的窗口,释放内存
- 必须在程序结束时调用,避免资源占用、
完整代码如下:
import cv2
import numpy as np
def add_peppersalt_noise(image, n=1000):
result = image.copy()
h, w = image.shape[:2]
for i in range(n):
x = np.random.randint(0, h)
y = np.random.randint(0, w)
if np.random.randint(0, 2) == 0:
result[x, y] = 0
else:
result[x, y] = 255
return result
video = cv2.VideoCapture(r'C:\Users\23967\xwechat_files\wxid_v89f4ju66y4h22_d879\msg\file\2025-08\test.avi')
if not video.isOpened():
print("无法打开视频文件 'test.avi'")
exit()
while True:
ret, frame = video.read()
if not ret:
print("视频播放完毕或读取失败")
break
noisy_frame = add_peppersalt_noise(frame)
filtered_frame = cv2.medianBlur(noisy_frame, 3)
cv2.imshow('Original Video', frame)
cv2.imshow('Video with Noise', noisy_frame)
cv2.imshow('Filtered Video', filtered_frame)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()