4. AI ISP数据准备:RAW数据集的采集、标注与合成方法,以及数据增强策略
做AI ISP这几年,我最大的感触是:算法模型只占30%,剩下70%的功夫全在数据上。你想想看,一个去噪网络在公开数据集上PSNR再高,到了自家sensor上立马翻车——这种事我见过太多次了。
RAW域的数据准备,说白了就是三件事:怎么采、怎么标、怎么造。下面我挨个讲清楚。
4.1 RAW数据的采集:别让sensor拖后腿
采集RAW数据,第一原则是原始性。一定要在ISP管线的最前端把数据截住,也就是Bayer域或者Quad-Bayer域的数据,不能经过任何预处理。
采集场景要覆盖全生命周期:
- 光照条件: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万左右。而合成数据,成本几乎为零。
合成流程如下:
- 选取干净RGB图像(比如DIV2K、Flickr2K)
- 模拟ISP逆过程:将RGB转换回RAW域,包括去马赛克逆过程、白平衡逆过程、Gamma逆过程
- 添加sensor噪声:光子散粒噪声(泊松分布)+ 读出噪声(高斯分布)
- 模拟光学缺陷:镜头渐晕、坏点、固定模式噪声
- 量化到目标位深:比如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通道比例
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 知识体系总览
下面这张图把数据准备的整个流程串起来了:
4.6 避坑指南
最后,我把自己这些年踩过的坑总结一下:
- 不要用JPEG转RAW:JPEG已经做了有损压缩和白平衡,转回去也是假的。我见过有人拿手机拍JPEG然后硬转Bayer,训练出来的模型一塌糊涂。
- 标注数据要留验证集:合成数据虽然方便,但一定要留一部分真实采集数据做验证。否则模型在合成数据上PSNR再高,真实场景也可能翻车。
- 噪声参数要标定:不要用网上随便找的噪声模型。每个sensor的噪声特性都不一样,花一周时间做标定,能省后面三个月调参的时间。
- 数据量不是越多越好:我试过把数据集从1万张扩到10万张,PSNR只涨了0.1dB。关键是数据的多样性——场景、光照、运动状态的覆盖比数量更重要。
我的经验:一个高质量的RAW数据集,大概需要:
- 真实采集:500~1000组(覆盖主要场景)
- 合成数据:5000~10000组(覆盖噪声多样性)
- 增强后:每个epoch随机裁剪,相当于无限数据
这个量级足够训练一个能上板的轻量级AI ISP模型。