计算机视觉(opencv)实战五——图像平滑处理(均值滤波、方框滤波、高斯滤波、中值滤波)附加:视频逐帧平滑处理


图像/视频平滑处理

图像平滑(smoothing)也称为"模糊处理"(blurring),是图像处理中常用的一种技术。通过消除图像中的噪声或细节,使图像看起来更加平滑、柔和,从而弱化或消除图像中的突变、噪点和细微纹理。

图像平滑在实际应用中非常重要,例如去噪、降低图像细节对后续处理(如边缘检测、分割)的影响,以及改善视觉效果等。


常用的滤波方法

均值滤波(Average/Blur)

均值滤波通过取邻域像素的平均值来替代中心像素值,从而达到平滑效果。

复制代码
  dst = cv2.blur(src, ksize)

示例代码:

复制代码
  blur_1 = cv2.blur(noise, (3, 3))   # 小卷积核
  blur_2 = cv2.blur(noise, (63, 63)) # 大卷积核
  • dst:处理后的图像

  • src:原始图像

  • ksize:卷积核大小,例如 (3, 3)

  • anchor:锚点,默认 (-1, -1),一般无需修改

  • borderType:边界处理方式,默认即可

方框滤波(Box Filter)

方框滤波类似均值滤波,但提供是否归一化的选项。

复制代码
  dst = cv2.boxFilter(src, ddepth, ksize, normalize=True)

示例代码:

复制代码
  boxFilter_1 = cv2.boxFilter(noise, -1, (3, 3), normalize=True)
  boxFilter_2 = cv2.boxFilter(noise, -1, (3, 3), normalize=False)
  • ddepth:输出图像深度,通常使用 -1 表示与原图相同

  • normalize:是否对邻域像素求平均

    • True → 归一化,相当于均值滤波

    • False → 不归一化,直接求和

高斯滤波(Gaussian Blur)

高斯滤波使用高斯函数对邻域像素加权平均,更加注重中心像素,能更自然地平滑图像。

复制代码
  GaussianB = cv2.GaussianBlur(src, ksize=(3,3), sigmaX=1)

示例代码:

复制代码
  GaussianB = cv2.GaussianBlur(noise, (3,3), sigmaX=1)
  • ksize:滤波器大小

  • sigmaX/sigmaY:X/Y方向的标准差

  • dst:输出图像,可省略

中值滤波(Median Blur)

中值滤波用邻域像素的中位数替代中心像素,特别适合去除椒盐噪声。

复制代码
  medianB = cv2.medianBlur(src, ksize=3)

示例代码:

复制代码
  medianB = cv2.medianBlur(noise, 3)
  • ksize 必须为奇数

  • 对椒盐噪声去除效果明显


案例演示:去除椒盐噪声

1️⃣ 导入库

复制代码
import cv2
import numpy as np
  • cv2:OpenCV库,用于图像读取、显示和处理。

  • numpy:用于数组和矩阵操作,这里用来生成噪声坐标。


2️⃣ 定义椒盐噪声函数

复制代码
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(low=1, high=h)
        y = np.random.randint(low=1, high=w)
        if np.random.randint(low=0, high=2) == 0:
            result[x, y] = 0      # 黑色噪声(椒)
        else:
            result[x, y] = 255    # 白色噪声(盐)
    return result
  • image.copy():复制原图,避免修改原图。

  • h, w = image.shape[:2]:获取图像高度和宽度,用于随机生成噪声位置。

  • 循环 n 次随机生成椒盐噪声像素:

    • np.random.randint(1, h) 随机生成行坐标

    • np.random.randint(1, w) 随机生成列坐标

    • 随机选择 0(黑)或 255(白)作为噪声值

作用:生成带有椒盐噪声的图像,用于测试滤波器的去噪能力。


3️⃣ 读取图像

复制代码
image = cv2.imread('tiger.jpg')
cv2.imshow('yuntu', image)
cv2.waitKey(0)
  • cv2.imread():读取图像,返回 NumPy 数组(BGR格式)。

  • cv2.imshow():显示图像窗口

  • cv2.waitKey(0):等待按键,按任意键关闭窗口


4️⃣ 添加椒盐噪声

复制代码
noise = add_peppersalt_noise(image)
cv2.imshow('noise', noise)
cv2.waitKey(0)
  • 调用 add_peppersalt_noise,生成带噪声的图像

  • 显示带噪声的图像,可以看到随机分布的黑白点


5️⃣ 均值滤波(Average Blur)

复制代码
blur_1 = cv2.blur(noise, (3, 3))
cv2.imshow('blur_(3, 3)', blur_1)
cv2.waitKey(0)

blur_2 = cv2.blur(noise, (63, 63))
cv2.imshow('blur_(63, 63)', blur_2)
cv2.waitKey(0)
  • cv2.blur():对图像进行均值滤波

  • (3, 3) vs (63, 63)

    • 小卷积核 (3x3):轻微平滑,噪声略有消除

    • 大卷积核 (63x63):强烈平滑,细节和噪声都模糊

作用:消除噪声,但大核可能导致图像模糊严重。


6️⃣ 方框滤波(Box Filter)

复制代码
boxFilter_1 = cv2.boxFilter(noise, -1, ksize=(3, 3), normalize=True)
cv2.imshow('boxFilter_1', boxFilter_1)
cv2.waitKey(0)

boxFilter_2 = cv2.boxFilter(noise, -1, ksize=(3, 3), normalize=False)
cv2.imshow('boxFilter_2', boxFilter_2)
cv2.waitKey(0)
  • cv2.boxFilter() 类似均值滤波,但可选择是否归一化:

    • normalize=True → 等价于均值滤波

    • normalize=False → 直接求和,可能产生像素溢出(大于255时截断)

  • ddepth=-1 表示输出图像与原图同样深度

作用:提供更灵活的滤波控制,既可平滑,也可测试非归一化效果。


7️⃣ 高斯滤波(Gaussian Blur)

复制代码
GaussianB = cv2.GaussianBlur(noise, ksize=(3,3), sigmaX=1)
cv2.imshow('GaussianBlur', GaussianB)
cv2.waitKey(0)
  • 高斯滤波器对邻域像素加权,中心像素权重更高

  • ksize=(3,3):滤波器大小

  • sigmaX=1:标准差,控制模糊程度

  • 对椒盐噪声和细节平滑效果更自然


8️⃣ 中值滤波(Median Blur)

复制代码
medianB = cv2.medianBlur(noise, ksize=3)
cv2.imshow('medianBlur', medianB)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 中值滤波取邻域像素中位数替换中心像素

  • 特别适合去除椒盐噪声

  • ksize 必须为奇数,越大去噪效果越强,但可能损失细节


🔹 总结

  • 均值滤波 / 方框滤波:简单、快速,但对椒盐噪声不够鲁棒

  • 高斯滤波:平滑自然,对高斯噪声更有效

  • 中值滤波:对椒盐噪声最有效,保留边缘效果更好

通过调整滤波器类型和卷积核大小,可以实现不同程度的图像平滑和去噪效果。


扩展案例:视频逐帧平滑处理

视频格式不是一定要是avi格式,可以是mp4等等

复制代码
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(low=1, high=h)
        y = np.random.randint(low=1, high=w)
        if np.random.randint(low=0, high=2) == 0:
            result[x, y] = 0
        else:
            result[x, y] = 255
    return result


video = cv2.VideoCapture('test.avi')  


while True:   # 每一帧
    ret, frame = video.read()
    if not ret:  # 判断是否读取到帧
        break
    cv2.imshow('video', frame)

    noise = add_peppersalt_noise(frame)  # 添加椒盐噪声
    cv2.imshow('noise', noise)

    medianB = cv2.medianBlur(noise, ksize=3)  # 中值滤波
    cv2.imshow('medianBlur', medianB)

    if cv2.waitKey(1) == 27:  # 1表示每一帧的间隔,27表示按键'Esc'
         break

video.release()
cv2.destroyAllWindows()