图像噪声基础:噪声类型与数学表示

做图像处理这些年,我有个很深的体会——不懂噪声,就别谈降噪。就像医生看病,连病原体长什么样都不知道,开什么药都是瞎蒙。

这一章,咱们就把图像噪声的底裤扒干净。我会从最常见的三种噪声讲起,再给出它们的数学模型。嗯,这部分可能有点数学味,但别怕,我会用项目里的实际例子帮你理解。

什么是图像噪声?

说白了,噪声就是图像里不该出现的随机信号。你拍一张纯色的墙,放大一看,像素值不是完全均匀的,有的亮一点,有的暗一点——这就是噪声。

我刚开始做图像处理时,总觉得噪声是硬件的问题,跟我算法没关系。后来被现实狠狠教育了一顿:噪声无处不在,而且每种噪声的脾气都不一样。

核心观点:噪声不是bug,是图像采集和传输过程中不可避免的物理现象。我们的目标不是消灭噪声(不可能),而是把它控制在人眼或后续算法能接受的范围内。

三种最常见的噪声类型

实际项目中,90%以上的噪声都可以归为以下三类。我按遇到的频率排个序:

噪声类型 产生原因 典型场景 我的踩坑记录
高斯噪声 传感器热噪声、电子电路抖动 暗光拍摄、长曝光 监控摄像头在夜晚几乎全是高斯噪声
椒盐噪声 传输错误、存储介质坏道 老旧摄像头、无线传输 无人机图传经常出现黑白点
泊松噪声 光子计数统计特性 低光照、医学成像 显微镜图像在弱光下特别明显

高斯噪声:最普遍的噪声

高斯噪声是图像处理界的「常客」。它的特点是:每个像素的噪声值服从正态分布。

数学上长这样:

概率密度函数:p(x) = (1 / (σ * √(2π))) * exp(-(x - μ)² / (2σ²))

其中:
- μ = 均值(通常为0)
- σ = 标准差(控制噪声强度)

我个人习惯把高斯噪声想象成「每个像素上叠加了一个随机小扰动」。扰动的大小由σ决定,σ越大,图像越花。

实战经验:我在做手机夜景模式时,发现ISO越高,高斯噪声的σ值越大。ISO 800以下基本不用管,ISO 3200以上就得下猛药了。

给图像加高斯噪声的代码很简单:

import numpy as np
import cv2

def add_gaussian_noise(image, sigma=25):
    noise = np.random.normal(0, sigma, image.shape)
    noisy = image + noise
    return np.clip(noisy, 0, 255).astype(np.uint8)

# 用法示例
img = cv2.imread('test.jpg', 0)
noisy_img = add_gaussian_noise(img, sigma=30)

椒盐噪声:最显眼的噪声

椒盐噪声,说白了就是图像上随机出现的一些纯白或纯黑的点。白的叫「盐」,黑的叫「椒」。

为什么叫这个名字?你想想看,往一盘菜里撒点盐和胡椒,是不是就这种效果?

数学模型更直接:

对于每个像素位置 (i, j):
  - 以概率 p/2 设为 0(黑点,椒)
  - 以概率 p/2 设为 255(白点,盐)
  - 以概率 1-p 保持原值

其中 p 是噪声密度,范围 0~1

我曾经接手过一个项目,客户说他们的监控画面「全是雪花点」。我一看,好家伙,椒盐噪声密度高达0.3,也就是30%的像素都坏了。后来发现是传输线路的屏蔽层老化导致的。

注意:椒盐噪声虽然看起来吓人,但其实比高斯噪声好处理。中值滤波几行代码就能搞定。但要注意,噪声密度超过0.5时,中值滤波的效果会明显下降。

生成椒盐噪声的代码:

def add_salt_pepper_noise(image, prob=0.05):
    output = image.copy()
    # 椒噪声(黑点)
    mask_pepper = np.random.random(image.shape) < prob/2
    output[mask_pepper] = 0
    # 盐噪声(白点)
    mask_salt = np.random.random(image.shape) < prob/2
    output[mask_salt] = 255
    return output

泊松噪声:最「物理」的噪声

泊松噪声跟前面两种不太一样。它来源于光的量子特性——光子到达传感器的数量本身就是一个随机过程。

数学上,泊松噪声的模型是:

观测到的像素值 ~ Poisson(λ)

其中 λ = 真实的光子数(也就是无噪声时的像素值)

泊松分布的概率质量函数:
P(k) = (λ^k * e^(-λ)) / k!

k = 观测到的光子数
λ = 期望光子数

这里有个有意思的特性:泊松噪声的方差等于均值。也就是说,信号越强的地方,噪声也越强。这跟高斯噪声完全不同——高斯噪声的强度跟信号无关。

我在做医学X光图像处理时,对这个体会特别深。X光成像本身就是光子计数过程,低剂量拍摄时,图像暗部的噪声特别明显,就是因为泊松噪声在作怪。

实用技巧:处理泊松噪声时,我建议先做方差稳定化变换(比如Anscombe变换),把泊松噪声转换成近似的高斯噪声,再用高斯噪声的方法处理。这样效果会好很多。

模拟泊松噪声的代码:

def add_poisson_noise(image):
    # 泊松噪声的强度与像素值成正比
    # 需要先把像素值缩放到合适的范围
    scaled = image / 255.0 * 100  # 缩放因子可调
    noisy = np.random.poisson(scaled)
    return np.clip(noisy / 100 * 255, 0, 255).astype(np.uint8)

三种噪声的对比总结

为了让你一眼看明白,我画了张对比表:

特性 高斯噪声 椒盐噪声 泊松噪声
分布形态 连续、对称 离散、二值 离散、偏态
与信号关系 独立 独立 相关(方差=均值)
视觉表现 颗粒感、模糊 黑白点 暗部颗粒明显
常用降噪方法 高斯滤波、双边滤波 中值滤波 Anscombe变换+高斯滤波
参数控制 σ(标准差) p(密度) λ(均值)

噪声模型的知识体系

下面这张图,是我自己梳理的噪声知识框架。每次带新人时,我都会先让他们看这个:

图像噪声知识体系 图像噪声 高斯噪声 椒盐噪声 泊松噪声 正态分布 参数: μ, σ 二值分布 参数: p 泊松分布 参数: λ 核心要点 • 高斯噪声:传感器热噪声,与信号独立 • 椒盐噪声:传输错误,表现为黑白点 • 泊松噪声:光子计数统计,方差=均值 降噪算法选择依据 识别噪声类型 → 选择合适的降噪策略 → 平衡降噪与锐化

为什么必须搞懂噪声类型?

你可能会问:知道这些数学公式有什么用?我直接调个滤波函数不就行了?

嗯,这里有个坑。我曾经接手过一个项目,同事用高斯滤波去处理椒盐噪声,结果越滤越花。为什么?因为高斯滤波对椒盐噪声基本无效,反而会把噪声扩散到周围像素。

选错降噪方法,比不降噪还糟糕。

所以我的建议是:拿到一张带噪图像,先花30秒判断噪声类型。怎么判断?

  • 看直方图:高斯噪声的直方图是平滑的钟形,椒盐噪声会在0和255处出现尖峰
  • 看局部区域:放大暗部区域,如果颗粒感均匀,大概率是高斯噪声;如果出现孤立黑白点,就是椒盐噪声
  • 看亮度关系:如果暗部噪声明显比亮部严重,很可能是泊松噪声

重要提醒:实际图像往往是多种噪声的混合体。比如手机夜景照片,既有传感器的高斯噪声,又有光子计数的泊松噪声。这时候就需要组合策略了——后面的章节我会详细讲。