2 图像噪声模型与评估
在图像采集、传输和存储过程中,由于成像设备物理限制、外部环境干扰、信号压缩等因素,图像常常不可避免地受到各种噪声的污染。这些噪声不仅影响图像的可视质量,也会干扰后续如目标检测、语义分割等高层计算机视觉任务的准确性。因此,理解常见图像噪声模型及其影响,掌握图像质量的客观评价指标,是从事图像处理和计算机视觉研究不可或缺的基础能力。
本小节将系统介绍三种典型的图像噪声类型:高斯噪声、椒盐噪声以及与相机ISO相关的感光噪声(ISO Noise),并进一步讲解用于评价图像质量和降噪效果的常用指标,如信噪比(SNR)、峰值信噪比(PSNR)等。
2.1 噪声模型
2.1.1 高斯噪声
高斯噪声是一种常见的噪声类型,其像素值的扰动服从高斯分布(正态分布)。高斯噪声通常由成像传感器中的热噪声或电子噪声引起,尤其在低光照条件下更为明显。它的特点是噪声值在整个图像中呈随机分布,且大多数噪声值较小,少数噪声值较大。
高斯噪声图像通常可以表示为:
[ I’(x, y) = I(x, y) + n(x, y) ] 其中: - (I(x, y)) 是原始图像(无噪图像)在位置(x,y)的像素值。 - (I’(x, y)) 是有噪声图像在位置(x,y)的像素值。 - (n(x, y)) 是在位置(x,y)的随机噪声值,随机噪声服从均值为\mu、均方差为\sigma的高斯分布,其概率密度函数(PDF)为:
[ f(z) = e^{-} ] ()通常假设为0(即无偏噪声),均方差() 越大表示噪声强度大。
高斯噪声可以通过以下步骤在图像上模拟生成: 1. 为每个像素生成一个服从高斯分布的随机数,通常使用均值 (),标准差 () 可根据需要调整。 2. 将随机噪声值加到原始像素值上。 3. 对结果进行裁剪,确保像素值在有效范围内(例如,灰度图像为 [0, 255])。
例3.1:给一张灰度图添加高斯噪声,代码如下,结果如图3-1-1所示。
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
image = cv2.imread('./imgs/tu3001.png', cv2.IMREAD_GRAYSCALE)
#以灰度图读取图像
# image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_COLOR) # 如果是彩色图
# 生成高斯噪声
gaussian_noise = np.random.normal(0, 0.1 * 255, image.shape)
# 噪声的强度为0.1*255=25.5,gaussian_noise与image同大小
# 将噪声添加到图像上
noisy_image = image + gaussian_noise
#np.clip(noisy_image, 0, 255)确保像素值在有效范围内(0-255),小于0的置0,大于255的置255
#astype(np.uint8)将数据类型设为uint8
noisy_image = np.clip(noisy_image, 0, 255).astype(np.uint8)
# 显示或保存结果
plt.rcParams['font.sans-serif'] = ['SimHei'] #中文标签字体
plt.subplot(1,2,1) #显示1行2列子图第1个子图
plt.axis('off') #关闭子图坐标轴
plt.gray() #灰度显示
plt.title('原图(Gray)') #子图标题
plt.imshow(image) #显示图像
plt.subplot(1,2,2) #显示1行2列子图第2个子图
plt.axis('off') #关闭子图坐标轴
plt.title('高斯噪声图像') #子图标题
plt.imshow(noisy_image) #显示图像
plt.show() #显示创建的所有图形/图像
<img src="./chapter3/GaussianNoisyGray.png" alt="高斯噪声图像" >
<br>
<center style="font-size:16px">图3-1-1 灰度图添加高斯噪声 </center>
例3.2:给一张RGB彩色图像添加高斯噪声,代码如下,结果如图3-1-2所示。
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取RGB彩色图像
image = cv2.imread('./imgs/tu3001.png', cv2.IMREAD_COLOR) # 如果是彩色图
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) #Opencv读取图像是BGR色彩空间,plt采用标准RGB色彩空间,所以需要把image从BGR转换成RGB
# 生成高斯噪声
gaussian_noise = np.random.normal(0, 0.1 * 255, image.shape)
# 噪声的强度为0.1*255=25.5,gaussian_noise与image同大小
# 将噪声添加到图像上
noisy_image = image + gaussian_noise
#np.clip(noisy_image, 0, 255)确保像素值在有效范围内(0-255),小于0的置0,大于255的置255
#astype(np.uint8)将数据类型设为uint8
noisy_image = np.clip(noisy_image, 0, 255).astype(np.uint8)
# 显示或保存结果
plt.rcParams['font.sans-serif'] = ['SimHei'] #支持中文显示
plt.subplot(1,2,1) #显示1行2列子图第1个子图
plt.axis('off') #关闭子图坐标轴
plt.title('原图') #子图标题
plt.imshow(image) #显示图像
plt.subplot(1,2,2) #显示1行2列子图第2个子图
plt.axis('off') #关闭子图坐标轴
plt.title('高斯噪声图像') #子图标题
plt.imshow(noisy_image) #显示图像
plt.show() #显示创建的所有图形/图像
<img src="./chapter3/GaussianNoisyColor.png" alt="高斯噪声图像" >
<br>
<center style="font-size:16px">图3-1-1 RGB图添加高斯噪声 </center>
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
image = cv2.imread('./imgs/tu3001.png', cv2.IMREAD_COLOR)
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB) #图像色彩空间从BGR转换至RGB,便于plt显示
#以灰度图读取图像
salt_pepper_ratio = 0.1 #控制产生椒盐噪声像素点的比例
h, w = image.shape[:2] # 获取图片的高和宽
number_salt_pepper = int(salt_pepper_ratio * h * w) #生成椒盐点总数量
noisy_image = np.copy(image)
for i in range(number_salt_pepper):
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,0生成椒噪声,1生成盐噪声,两者产生的概率相同
noisy_image[x, y] = [0,0,0]
else:
noisy_image[x,y] = [255,255,255]
# 显示或保存结果
plt.rcParams['font.sans-serif'] = ['SimHei'] #支持中文显示
plt.subplot(1,2,1) #显示1行2列子图第1个子图
plt.axis('off') #关闭子图坐标轴
plt.title('RGB原图') #子图标题
plt.imshow(image) #显示图像
plt.subplot(1,2,2) #显示1行2列子图第2个子图
plt.axis('off') #关闭子图坐标轴
plt.title('椒盐噪声图像') #子图标题
plt.imshow(noisy_image) #显示图像
plt.show() #显示创建的所有图形/图像
从上述两个例子可以看到,高斯噪声在图像中表现为细小的、均匀分布的像素值波动,类似于“雪花”效应。它对图像的整体对比度和细节清晰度有一定影响,但在高强度时可能显著降低图像质量。实际应用中,高斯噪声常用于模拟低光照条件下的成像效果。
2.1.2 椒盐噪声
椒盐噪声(Salt-and-Pepper Noise)是一种非连续的噪声类型,表现为图像中随机出现的黑点(椒噪声,接近0)和白点(盐噪声,接近255)。这种噪声通常由传感器故障、模数转换错误或数据传输中的位错误引起。
椒盐噪声可以看作是一种二值噪声模型,其特点是部分像素被替换为最大值或最小值,而其他像素保持不变。其概率模型为:
[ P(z) = \begin{cases} p_a & \text{if } z = 0 \text{ (椒噪声)} \\ p_b & \text{if } z = 255 \text{ (盐噪声)} \\ 1 - p_a - p_b & \text{if } z = I(x, y) \end{cases}]
其中: - (p_a) 是椒噪声的概率。 - (p_b) 是盐噪声的概率。 - 通常 (p_a + p_b ),表示噪声只影响小部分像素。
椒盐噪声的模拟生成步骤如下: 1. 随机选择图像中一定比例(例如,5%)的像素。 2. 将这些像素随机赋值为0(椒噪声)或255(盐噪声)。 3. 其余像素保持原始值不变。
例3.3 灰度图像添加10%比例椒盐噪声的示例代码如下,效果如图3-1-3所示。
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
image = cv2.imread('./imgs/tu3001.png', cv2.IMREAD_GRAYSCALE)
#以灰度图读取图像
salt_pepper_ratio = 0.1 #控制产生椒盐噪声像素点的比例
h, w = image.shape[:2] # 获取图片的高和宽
number_salt_pepper = int(salt_pepper_ratio * h * w) #生成椒盐点总数量
noisy_image = np.copy(image)
for i in range(number_salt_pepper):
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,0生成椒噪声,1生成盐噪声,两者产生的概率相同
noisy_image[x, y] = 0
else:
noisy_image[x,y] = 255
# 显示或保存结果
plt.rcParams['font.sans-serif'] = ['SimHei'] #支持中文显示
plt.subplot(1,2,1) #显示1行2列子图第1个子图
plt.axis('off') #关闭子图坐标轴
plt.gray() #灰度显示
plt.title('原图(Gray)') #子图标题
plt.imshow(image) #显示图像
plt.subplot(1,2,2) #显示1行2列子图第2个子图
plt.axis('off') #关闭子图坐标轴
plt.title('椒盐噪声图像') #子图标题
plt.imshow(noisy_image) #显示图像
plt.show() #显示创建的所有图形/图像
<img src="./chapter3/tu3-3.png" alt="椒盐噪声图像" >
<br>
<center style="font-size:16px">图3-1-3 灰度图添加椒盐噪声图像 </center>
例3.4 灰度图像添加10%比例椒盐噪声的示例代码如下,效果如图3-1-4所示。
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图像
image = cv2.imread('./imgs/tu3001.png', cv2.IMREAD_COLOR)
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB) #图像色彩空间从BGR转换至RGB,便于plt显示
#以灰度图读取图像
salt_pepper_ratio = 0.1 #控制产生椒盐噪声像素点的比例
h, w = image.shape[:2] # 获取图片的高和宽
number_salt_pepper = int(salt_pepper_ratio * h * w) #生成椒盐点总数量
noisy_image = np.copy(image)
for i in range(number_salt_pepper):
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,0生成椒噪声,1生成盐噪声,两者产生的概率相同
noisy_image[x, y] = [0,0,0]
else:
noisy_image[x,y] = [255,255,255]
# 显示或保存结果
plt.rcParams['font.sans-serif'] = ['SimHei'] #支持中文显示
plt.subplot(1,2,1) #显示1行2列子图第1个子图
plt.axis('off') #关闭子图坐标轴
plt.title('RGB原图') #子图标题
plt.imshow(image) #显示图像
plt.subplot(1,2,2) #显示1行2列子图第2个子图
plt.axis('off') #关闭子图坐标轴
plt.title('椒盐噪声图像') #子图标题
plt.imshow(noisy_image) #显示图像
plt.show() #显示创建的所有图形/图像
<img src="./chapter3/tu3-4.png" alt="椒盐噪声图像" >
<br>
<center style="font-size:16px">图3-1-4 RGB彩色图像添加椒盐噪声图像 </center>
椒盐噪声在图像中表现为明显的黑白点,容易引起视觉干扰,并对边缘检测、特征提取等任务产生较大影响。由于其非连续性,椒盐噪声通常需要专门的滤波方法(如中值滤波)来去除。
2.1.3 ISO噪声
ISO噪声是指在数码相机中由于高感光度(ISO值)设置而引入的噪声。在高ISO设置下,相机传感器会放大信号以捕获更多光线,但同时也会放大噪声,导致图像质量下降。ISO噪声通常是高斯噪声和其他噪声(如光子噪声)的复合效应,尤其在低光照条件下更为显著。
ISO噪声的数学建模较为复杂,因为它不仅包含高斯噪声,还可能包括光子噪声(服从泊松分布)和读出噪声等。其简化模型通常假设为高斯噪声或者近高斯噪声。实际中,ISO噪声的强度还与传感器的性能、像素大小和环境光照条件有关。
ISO噪声在高ISO设置下会导致图像出现明显的颗粒感,尤其在暗部区域更为显著。它对图像的动态范围和色彩保真度有较大影响,是数码摄影中的主要噪声来源之一。实际应用中,ISO噪声的控制需要权衡感光度和图像质量。
2.2 图像质量评估指标
为了量化噪声对图像质量的影响,信噪比(SNR)和峰值信噪比(PSNR)是两种常用的评估指标。它们通过比较原始图像与噪声图像的差异,为图像处理算法的性能提供客观依据。
2.2.1 信噪比(SNR)
定义
信噪比(Signal-to-Noise Ratio, SNR)是衡量信号强度与噪声强度的相对关系的指标。在图像处理中,SNR表示原始图像信号与噪声之间的功率比,通常以分贝(dB)为单位,其定义为:
[ = 10 ( ) ]
其中: - (Var(I)) 表示无噪声(原始)图像的方差,其具体计算为: [ Var(I) = {x=0}^{M-1} {y=0}^{N-1} I(x, y)^2 ] 其中 (M N) 是图像的分辨率,(I(x, y)) 是原始图像的像素值。
- (Var(I’-I)) 表示(I)与形变(噪声)图像(I’)之差的方差,即噪声的方差,其具体计算为: [ Var(I’-I) = {x=0}^{M-1} {y=0}^{N-1} (I’(x, y) - I(x, y))^2 ] 其中 (I’(x, y)) 是噪声图像的像素值。
SNR值越高,表示噪声对图像的影响越小,图像质量越高。
2.2.2 峰值信噪比(PSNR)
峰值信噪比(Peak Signal-to-Noise Ratio, PSNR)是另一种广泛使用的图像质量评估指标,与SNR类似,PSNR同样以分贝为单位,其公式为:
[ = 10 ( ) ]
其中 (L) 是图像像素的最大可能值(例如,8位灰度图像为255)。
PSNR与SNR都是基于误差方差,用于量化噪声影响,值越高表示图像质量越好。不同之处在于SNR考虑信号和噪声的功率比,适用于多种信号处理场景,而PSNR基于最大像素值,更多用于图像压缩和去噪任务的评估。
在计算机视觉研究中,PSNR因其简单性和标准化程度更高而更常使用,如比较不同去噪算法的性能;评估压缩算法在不同压缩率下的图像质量;比较不同传感器或相机在不同ISO设置下的图像质量;在生成对抗网络(GAN)或超分辨率任务中,PSNR常用于评估生成图像与真实图像的相似度。