3. RAW域噪声特性分析
任务目标
本案例通过对RAW格式图像添加已知参数的高斯噪声与泊松噪声,定量分析亮度通道与色度通道的噪声分布特性,建立RAW域噪声模型的基本认知。
核心原理
RAW域噪声主要由两部分构成:光子散粒噪声(泊松分布,与信号强度相关)和读出噪声(近似高斯分布,与信号无关)。在亮度通道上,噪声随信号强度增大而增大(泊松分量主导);在色度通道上,由于色彩插值(demosaic)的邻域运算,噪声呈现空间相关性且幅度通常低于亮度噪声。本案例通过合成噪声RAW图,分别统计亮度与色度通道的噪声标准差随信号强度的变化曲线,验证上述特性。
环境依赖
- Python 3.8+
- numpy、scipy(仅用于读取TIFF格式RAW)
- opencv-python(用于色彩插值)
完整实现代码
import numpy as np
import cv2
# ---------- 1. 生成无噪声RAW(Bayer BGGR,14bit) ----------
def generate_clean_raw(h=256, w=256):
"""生成平滑亮度渐变的RAW图,便于统计不同信号强度下的噪声"""
# 亮度从暗到亮渐变(覆盖0~16383的14bit范围)
gradient = np.linspace(0, 16383, w, dtype=np.float32)
raw = np.tile(gradient, (h, 1))
# 模拟彩色场景:R/G/B通道增益不同
raw[0::2, 0::2] *= 0.8 # R位置
raw[0::2, 1::2] *= 1.0 # Gr位置
raw[1::2, 0::2] *= 1.0 # Gb位置
raw[1::2, 1::2] *= 1.2 # B位置
return raw
# ---------- 2. 添加泊松+高斯噪声 ----------
def add_raw_noise(raw, gain=1.0, sigma_read=2.0):
"""
模拟RAW域噪声:
- 泊松分量:光子到达率与信号强度成正比,经增益gain转换为电子数
- 高斯分量:读出噪声,标准差sigma_read(ADU)
"""
# 电子数 = 信号(ADU) / gain
electrons = raw / gain
# 泊松噪声(光子散粒噪声)
noisy_electrons = np.random.poisson(electrons).astype(np.float32)
# 读出噪声(高斯)
noisy_electrons += np.random.normal(0, sigma_read, raw.shape)
# 转回ADU
noisy_raw = noisy_electrons * gain
return np.clip(noisy_raw, 0, 16383)
# ---------- 3. 色彩插值(简单双线性) ----------
def demosaic_bayer(raw_bggr):
"""将Bayer BGGR格式转为RGB三通道(使用OpenCV)"""
raw_8bit = (raw_bggr / 16383 * 255).astype(np.uint8)
rgb = cv2.cvtColor(raw_8bit, cv2.COLOR_BayerBG2RGB)
return rgb.astype(np.float32) / 255.0
# ---------- 4. 亮度/色度噪声统计 ----------
def analyze_noise(clean_rgb, noisy_rgb, bin_edges):
"""
统计不同亮度区间内,亮度噪声与色度噪声的标准差
返回: (亮度均值bin, 亮度噪声std, 色度噪声std)
"""
# 亮度 = RGB均值,色度 = RGB与亮度之差
clean_lum = clean_rgb.mean(axis=2)
noisy_lum = noisy_rgb.mean(axis=2)
lum_noise = noisy_lum - clean_lum
clean_chroma = clean_rgb - clean_lum[:, :, np.newaxis]
noisy_chroma = noisy_rgb - noisy_lum[:, :, np.newaxis]
chroma_noise = noisy_chroma - clean_chroma
chroma_noise_mag = np.sqrt((chroma_noise ** 2).sum(axis=2))
bin_centers, lum_std, chroma_std = [], [], []
for i in range(len(bin_edges) - 1):
mask = (clean_lum >= bin_edges[i]) & (clean_lum < bin_edges[i + 1])
if mask.sum() < 50:
continue
bin_centers.append((bin_edges[i] + bin_edges[i + 1]) / 2)
lum_std.append(lum_noise[mask].std())
chroma_std.append(chroma_noise_mag[mask].std())
return np.array(bin_centers), np.array(lum_std), np.array(chroma_std)
# ---------- 5. 主流程 ----------
if __name__ == "__main__":
np.random.seed(42)
clean_raw = generate_clean_raw(512, 512)
noisy_raw = add_raw_noise(clean_raw, gain=2.0, sigma_read=4.0)
clean_rgb = demosaic_bayer(clean_raw)
noisy_rgb = demosaic_bayer(noisy_raw)
# 亮度归一化到0~1区间,分10个bin统计
clean_lum_norm = clean_rgb.mean(axis=2)
bin_edges = np.linspace(0, 1, 11)
centers, lum_std, chroma_std = analyze_noise(clean_rgb, noisy_rgb, bin_edges)
# 打印统计结果
print("亮度区间中心 | 亮度噪声std | 色度噪声std")
for c, l, ch in zip(centers, lum_std, chroma_std):
print(f"{c:.3f} | {l:.4f} | {ch:.4f}")
# 验证:亮度噪声随信号增强而增大(泊松分量),色度噪声相对平坦
# 预期输出:亮度std从暗部约0.01增至亮部约0.05,色度std约0.01~0.02
运行方式
python raw_noise_analysis.py
验证方法与判定标准
- 运行成功标志:程序无异常退出,打印出10行左右的统计表格。
- 噪声特性验证:观察输出的亮度噪声std列,应呈现随亮度区间中心值增大而增大的趋势(暗部约0.01,亮部约0.04~0.06),这验证了泊松噪声分量随信号增强的特性。
- 色度噪声对比:色度噪声std应明显小于亮度噪声std(约为其1/3~1/2),且随亮度变化幅度较小,这验证了demosaic后色度通道噪声被空间平均抑制的特性。
- 可重复性:固定随机种子(seed=42),每次运行结果应完全一致。
关键说明
- 本案例使用合成RAW而非真实传感器数据,目的是在已知噪声参数条件下建立定量分析基准;真实RAW噪声分析需先做黑电平校正和镜头阴影校正。
- gain参数模拟传感器模拟增益(单位e-/ADU),gain越大则泊松噪声相对读出噪声越显著。
- demosaic算法会改变噪声统计特性,本案例使用最简单的双线性插值,实际ISP中更复杂的插值算法会进一步改变色度噪声的空间分布。