一、图像噪声的添加与理解
1.1 椒盐噪声的添加与特点
椒盐噪声是图像处理中常见的一种噪声,因其呈现出随机的黑白像素点,类似撒在图像上的盐和胡椒而得名。通过以下代码,我实现了向图像添加椒盐噪声的功能:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def add_salt_pepper_noise(image, salt_vs_pepper=0.5, amount=0.01):
"""
添加椒盐噪声到图像
参数:
image: 输入的图像(numpy数组)
salt_vs_pepper: 椒盐比例,0.5表示盐和椒的数量相等
amount: 噪声数量占总像素的比例
返回:
添加噪声后的图像
"""
# 创建图像副本以避免修改原图
noisy_image = np.copy(image)
# 获取图像尺寸
rows, cols = noisy_image.shape[:2]
# 计算要添加的噪声像素总数
num_salt = np.ceil(amount * rows * cols * salt_vs_pepper)
num_pepper = np.ceil(amount * rows * cols * (1.0 - salt_vs_pepper))
# 添加盐噪声(白色像素)
coords = [np.random.randint(0, i - 1, int(num_salt)) for i in (rows, cols)]
noisy_image[coords[0], coords[1]] = 255
# 添加椒噪声(黑色像素)
coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in (rows, cols)]
noisy_image[coords[0], coords[1]] = 0
return noisy_image
# 读取图像
image = cv2.imread('lena.jpg', 0) # 以灰度模式读取图像
# 检查图像是否成功读取
if image is None:
print("无法读取图像,请检查文件路径")
else:
# 添加椒盐噪声(2%的像素被添加噪声,盐椒比例1:1)
noisy_image = add_salt_pepper_noise(image, salt_vs_pepper=0.5, amount=0.02)
# 显示原图和添加噪声后的图像
plt.figure(figsize=(8, 5))
plt.subplot(121)
plt.title('原始图像')
plt.imshow(image, cmap='gray')
plt.axis('off')
plt.subplot(122)
plt.title('添加椒盐噪声后的图像')
plt.imshow(noisy_image, cmap='gray')
plt.axis('off')
plt.tight_layout()
plt.show()
# 保存添加噪声后的图像
cv2.imwrite('qiaoyan_nosiy_lena.jpg', noisy_image)
实现原理:
- 首先计算需要添加的盐噪声(白色像素)和椒噪声(黑色像素)的数量
- 使用
np.random.randint
随机生成噪声像素的位置 - 将对应位置的像素值设为 255(盐噪声)或 0(椒噪声)
关键参数:
salt_vs_pepper
:控制盐噪声与椒噪声的比例,0.5 表示两者数量相等amount
:控制噪声强度,0.02 表示 2% 的像素会被添加噪声
1.2 高斯噪声的添加与特点
高斯噪声是另一种常见噪声,其像素值分布符合高斯分布,在实际场景中(如相机传感器噪声)较为常见。以下是添加高斯噪声的实现代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def add_gaussian_noise(image, mean=0, sigma=25):
"""
添加高斯噪声到图像
参数:
image: 输入的图像(numpy数组)
mean: 高斯分布的均值
sigma: 高斯分布的标准差,控制噪声强度
返回:
添加噪声后的图像
"""
# 创建与输入图像形状相同的高斯噪声
gaussian = np.random.normal(mean, sigma, image.shape)
# 将噪声添加到图像
noisy_image = image + gaussian
# 将像素值裁剪到0-255范围
noisy_image = np.clip(noisy_image, 0, 255)
# 转换回uint8类型
noisy_image = noisy_image.astype(np.uint8)
return noisy_image
# 读取图像
image = cv2.imread('lena.jpg', 0) # 以灰度模式读取图像
# 检查图像是否成功读取
if image is None:
print("无法读取图像,请检查文件路径")
else:
# 添加高斯噪声(均值0,标准差30)
noisy_image = add_gaussian_noise(image, mean=0, sigma=30)
# 显示原图和添加噪声后的图像
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.title('原始图像')
plt.imshow(image, cmap='gray')
plt.axis('off')
plt.subplot(122)
plt.title('添加高斯噪声后的图像')
plt.imshow(noisy_image, cmap='gray')
plt.axis('off')
plt.tight_layout()
plt.show()
# 保存添加噪声后的图像
cv2.imwrite('gaosi_nosiy_lena.jpg', noisy_image)
实现原理:
- 使用
np.random.normal
生成符合高斯分布的噪声矩阵 - 将噪声矩阵与原始图像相加
- 使用
np.clip
将像素值限制在 0-255 范围内 - 转换回
uint8
类型以便显示和保存
关键参数:
mean
:高斯分布的均值,控制噪声的中心位置sigma
:标准差,控制噪声的强度和分布范围
二、图像滤波去噪实践
2.1 均值滤波:简单有效的线性滤波
均值滤波是最基础的线性滤波方法,通过计算像素邻域的平均值来平滑图像:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('dogsp.jpeg')
# 2 均值滤波(5x5卷积核)
blur = cv.blur(img, (5, 5))
# 3 图像显示
plt.figure(figsize=(8, 5), dpi=100)
plt.subplot(121), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv.cvtColor(blur, cv.COLOR_BGR2RGB)), plt.title('均值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
实现原理:
- 使用
cv.blur
函数实现均值滤波 - 卷积核大小
(5, 5)
表示使用 5x5 的窗口计算平均值
特点:
- 优点:算法简单,计算速度快
- 缺点:会模糊图像细节,对椒盐噪声效果不佳
2.2 高斯滤波:保留边缘的平滑方法
高斯滤波利用高斯核进行加权平均,对高斯噪声有很好的抑制作用:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('dogGauss.jpeg')
# 2 高斯滤波(3x3核,X方向标准差1)
blur = cv.GaussianBlur(img, (3, 3), 1)
# 3 图像显示
plt.figure(figsize=(8, 5), dpi=100)
plt.subplot(121), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv.cvtColor(blur, cv.COLOR_BGR2RGB)), plt.title('高斯滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
实现原理:
cv.GaussianBlur
使用高斯核进行卷积- 核大小
(3, 3)
,X 方向标准差为 1,Y 方向标准差默认与 X 相同
特点:
- 对高斯噪声效果显著
- 相比均值滤波,能更好地保留图像边缘
- 高斯核的权重分布使得中心像素影响更大
2.3 中值滤波:椒盐噪声的克星
中值滤波是一种非线性滤波方法,特别适合去除椒盐噪声:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('dogsp.jpeg')
# 2 中值滤波(5x5窗口)
blur = cv.medianBlur(img, 5)
# 3 图像展示
plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv.cvtColor(blur, cv.COLOR_BGR2RGB)), plt.title('中值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()
实现原理:
cv.medianBlur
将窗口内的像素值排序后取中值- 5x5 窗口表示每次取 25 个像素的中值作为中心像素值
特点:
- 对椒盐噪声有极佳的去除效果
- 能有效保护图像边缘
- 非线性操作使其在处理极端像素值时更有效
三、学习总结与实践心得
3.1 噪声与滤波方法的匹配
通过实践,我总结出不同噪声与滤波方法的匹配关系:
- 椒盐噪声:中值滤波效果最佳,因为它能有效去除极端像素值而不模糊边缘
- 高斯噪声:高斯滤波最为合适,因为其原理与噪声分布匹配
3.2 滤波参数的影响
-
核大小:
- 较大的核会产生更强的平滑效果,但会丢失更多细节
- 建议从 3x3 开始尝试,根据效果逐步调整
-
标准差(高斯滤波):
- 标准差越大,高斯核越宽,平滑效果越强
- 通常设为 5-30,根据噪声强度调整
-
噪声比例(添加噪声时):
- 小比例 (0.01-0.05) 适用于模拟轻微噪声
- 大比例 (0.1 以上) 用于测试算法鲁棒性
3.3 实践中的注意事项
-
图像读取与显示:
- OpenCV 以 BGR 模式读取图像,matplotlib 使用 RGB,需注意转换
- 始终检查图像是否成功读取,避免空指针错误
-
数据类型转换:
- 添加噪声时需注意保持图像数据类型一致
- 浮点型图像在显示前需转换为 uint8
3.4总结
-
图像噪声
- 椒盐噪声:图像中随机出现的白点或者黑点
- 高斯噪声:噪声的概率密度分布是正态分布
-
图像平滑
-
均值滤波:算法简单,计算速度快,在去噪的同时去除了很多细节部分,将图像变得模糊
cv.blur()
-
高斯滤波: 去除高斯噪声
cv.GaussianBlur()
-
中值滤波: 去除椒盐噪声
cv.medianBlur()
-