4. AI ISP数据准备:RAW数据集的采集、标注与合成方法,以及数据增强策略

做AI ISP这几年,我最大的感触是:算法模型只占30%,剩下70%的功夫全在数据上。你想想看,一个去噪网络在公开数据集上PSNR再高,到了自家sensor上立马翻车——这种事我见过太多次了。

RAW域的数据准备,说白了就是三件事:怎么采、怎么标、怎么造。下面我挨个讲清楚。

4.1 RAW数据的采集:别让sensor拖后腿

采集RAW数据,第一原则是原始性。一定要在ISP管线的最前端把数据截住,也就是Bayer域或者Quad-Bayer域的数据,不能经过任何预处理。

我曾经踩过的坑:某次项目用了手机厂商提供的“RAW”数据,结果发现里面偷偷做了黑电平校正和坏点修复。模型训练完在真机上一跑,暗部偏色严重。后来我要求所有采集数据必须从sensor直接dump,不经过任何ISP模块。

采集场景要覆盖全生命周期:

  • 光照条件:0.1 lux(月光级)到100000 lux(正午阳光),每档至少3组
  • 色温范围:2000K(烛光)到7500K(阴天),用标准色卡做参考
  • 运动状态:静态、慢速平移、快速抖动(模拟手持)
  • 目标物体:人脸、文字、自然场景、纹理密集区、纯色块
采集参数 推荐范围 注意事项
曝光时间 1/1000s ~ 2s 长曝光需三脚架,避免抖动模糊
ISO 100 ~ 6400 高ISO下噪声大,但正是训练去噪网络需要的
Bayer格式 10bit/12bit/14bit 位深越高,动态范围越丰富
分辨率 与目标sensor一致 不要resize,保持原生像素

我个人习惯在采集时同步记录元数据:增益值、曝光时间、镜头光圈、色温估计值。这些信息在后续合成和标注时非常有用。

4.2 标注方法:GT从哪来?

RAW域的标注比RGB域麻烦得多。RGB图像人眼能直接看,RAW图像是马赛克,人根本没法标。所以我们需要间接获取Ground Truth。

4.2.1 多帧融合法

这是最可靠的方法。对同一静态场景拍多帧(比如16~64帧),然后做配准和平均。噪声是随机的,平均后信噪比提升sqrt(N)倍。我一般拍32帧,平均后的图像基本可以当作干净GT。

# 多帧平均伪代码
def generate_gt_from_multiple_frames(raw_frames):
    # raw_frames: list of numpy arrays, shape [H, W]
    # 先做配准(这里省略)
    aligned_frames = register_frames(raw_frames)
    # 逐像素平均
    gt = np.mean(aligned_frames, axis=0)
    return gt
小技巧:多帧平均前一定要做亚像素配准。我试过不做配准直接平均,结果边缘模糊得一塌糊涂。用光流法或者相位相关法都能搞定。

4.2.2 低ISO参考法

如果场景不允许拍多帧(比如有人脸),可以用低ISO拍一张作为参考。低ISO下噪声极小,可以近似当作GT。但要注意:低ISO意味着长曝光或大光圈,可能引入运动模糊或景深变化。

4.2.3 合成标注

用计算机图形学渲染出“完美”的RAW图像,然后人为添加噪声、模糊、坏点等退化。这种方法的好处是GT干净,坏处是合成数据与真实sensor数据有domain gap。

4.3 数据合成:让数据量翻10倍

真实采集成本太高。我算过一笔账:采集1000组高质量RAW数据,包括场景布置、设备调试、人工标注,成本大概在20万左右。而合成数据,成本几乎为零。

合成流程如下:

  1. 选取干净RGB图像(比如DIV2K、Flickr2K)
  2. 模拟ISP逆过程:将RGB转换回RAW域,包括去马赛克逆过程、白平衡逆过程、Gamma逆过程
  3. 添加sensor噪声:光子散粒噪声(泊松分布)+ 读出噪声(高斯分布)
  4. 模拟光学缺陷:镜头渐晕、坏点、固定模式噪声
  5. 量化到目标位深:比如12bit RAW

核心公式:噪声模型

I_noisy = I_clean + sqrt(I_clean * α) * N(0,1) + N(0, β)

其中α是散粒噪声系数(与ISO正相关),β是读出噪声方差。这两个参数需要从实际sensor标定得到。

4.4 数据增强策略:别让模型过拟合

数据增强在RAW域和RGB域有很大不同。RGB域常用的色彩抖动、对比度调整,在RAW域不能乱用——因为RAW数据有严格的物理意义。

4.4.1 几何增强(安全)

  • 随机翻转:水平、垂直、对角线(注意Bayer模式要同步翻转)
  • 随机旋转:90°、180°、270°(Bayer模式保持对齐)
  • 随机裁剪:从大图中抠patch,常用256x256或512x512

4.4.2 光度增强(需谨慎)

  • 增益调整:模拟不同ISO,乘以随机系数0.5~2.0
  • 黑电平偏移:模拟sensor温度变化,加随机偏移
  • 色温偏移:在RAW域调整R/B通道比例
注意:不要在RAW域做Gamma校正、对比度拉伸、饱和度调整。这些操作会破坏RAW数据的线性特性,导致模型学到错误映射。我见过有人把RGB域的增强策略直接搬过来用,结果模型在真实数据上完全失效。

4.4.3 噪声增强(关键)

这是AI ISP数据增强的核心。真实sensor的噪声不是固定的,它会随温度、增益、曝光时间变化。所以我们要模拟噪声的多样性:

  • 不同ISO下的噪声强度
  • 不同温度下的读出噪声
  • 行噪声、列噪声(sensor的固定模式噪声)
  • 量化噪声
# 噪声增强示例
def noise_augmentation(raw, iso, temperature):
    # 根据ISO计算散粒噪声系数
    shot_noise_scale = iso / 100.0 * 0.01
    # 根据温度计算读出噪声
    read_noise_scale = 0.5 + temperature * 0.02
    
    shot_noise = np.sqrt(raw * shot_noise_scale) * np.random.randn(*raw.shape)
    read_noise = read_noise_scale * np.random.randn(*raw.shape)
    
    return raw + shot_noise + read_noise

4.5 知识体系总览

下面这张图把数据准备的整个流程串起来了:

RAW域AI ISP数据准备流程 RAW域AI ISP数据准备流程 数据采集 数据标注 数据合成 数据增强 几何增强 光度增强 噪声增强 训练数据集 采集+标注+合成 → 增强 → 训练集

4.6 避坑指南

最后,我把自己这些年踩过的坑总结一下:

  • 不要用JPEG转RAW:JPEG已经做了有损压缩和白平衡,转回去也是假的。我见过有人拿手机拍JPEG然后硬转Bayer,训练出来的模型一塌糊涂。
  • 标注数据要留验证集:合成数据虽然方便,但一定要留一部分真实采集数据做验证。否则模型在合成数据上PSNR再高,真实场景也可能翻车。
  • 噪声参数要标定:不要用网上随便找的噪声模型。每个sensor的噪声特性都不一样,花一周时间做标定,能省后面三个月调参的时间。
  • 数据量不是越多越好:我试过把数据集从1万张扩到10万张,PSNR只涨了0.1dB。关键是数据的多样性——场景、光照、运动状态的覆盖比数量更重要。

我的经验:一个高质量的RAW数据集,大概需要:

  • 真实采集:500~1000组(覆盖主要场景)
  • 合成数据:5000~10000组(覆盖噪声多样性)
  • 增强后:每个epoch随机裁剪,相当于无限数据

这个量级足够训练一个能上板的轻量级AI ISP模型。