1. RAW 域基础:什么是 RAW 图像、RAW 与 RGB 的区别、Bayer 阵列格式、RAW 文件的数据结构

各位同学,咱们今天聊 RAW 域。说实话,我入行头两年一直在 RGB 图像上做降噪,效果总差口气。后来一位老前辈点醒我——「你处理的是已经加工过的数据,原始信息早丢了」。从那以后,我才真正开始啃 RAW 域。

这一章,咱们把 RAW 域的基础打牢。你想想看,如果连传感器吐出来的原始数据长什么样都不清楚,后面做降噪模型,基本就是盲人摸象。

1.1 什么是 RAW 图像

RAW 图像,说白了就是相机传感器直接输出的「数字底片」。它没经过任何 ISP(图像信号处理器)的加工——没有去马赛克、没有白平衡、没有伽马校正、没有降噪。你按下快门那一瞬间,传感器上每个像素点记录的光电信号,原封不动地存了下来。

核心认知:RAW 图像是线性的、未压缩的、每个像素只记录单一颜色通道的原始数据。它是整个图像处理管线的「起点」,也是信息量最完整的阶段。

我个人习惯把 RAW 比作「面粉」,RGB 图像是「面包」。面粉可以做成面包、馒头、面条,但一旦烤成面包,就再也变不回面粉了。做 AI 降噪也一样——在 RAW 域做,你能保留最多的信号细节;在 RGB 域做,很多噪声已经被 ISP 的非线性处理「固化」了,很难再分离干净。

1.2 RAW 与 RGB 的区别

很多刚接触的同学会问:RAW 和 RGB 不都是图像吗?区别在哪?

区别大了。我整理了一个对比表,你一看就明白:

对比维度 RAW 图像 RGB 图像
数据来源 传感器直接输出 经过 ISP 管线处理
颜色信息 每个像素只有一种颜色(R/G/B 之一) 每个像素有完整的 R/G/B 三个通道
位深 通常 10-14 bit 通常 8 bit
线性度 线性响应(光子数 → 数字值) 非线性(伽马校正、色调映射等)
噪声特性 接近传感器原始噪声分布 噪声被 ISP 处理扭曲
文件大小 较大(无损或轻微压缩) 较小(有损压缩为主)
典型格式 .dng, .cr2, .nef, .arw .jpg, .png, .bmp

这里有个关键点:RAW 是线性的。这意味着像素值和场景亮度成正比。你做降噪模型时,噪声模型可以建模为信号相关的泊松-高斯混合分布。但 RGB 图像经过伽马校正后,噪声和信号的关系变得极其复杂,模型很难拟合。

我的经验:曾经有个项目,在 RGB 域做降噪,PSNR 死活提不上去。后来我把数据换成 RAW 域重新训练,同样的网络结构,PSNR 直接涨了 2-3 dB。原因很简单——RAW 域的噪声更「干净」,模型学起来更容易。

1.3 Bayer 阵列格式

好,现在问题来了:传感器怎么用单色像素记录彩色图像?

答案是——在传感器表面覆盖一层彩色滤光片阵列(CFA)。最常见的模式就是 Bayer 阵列,由 Bryce Bayer 在 1976 年发明。它的排列方式是:

  • 50% 绿色(G):因为人眼对绿色最敏感
  • 25% 红色(R)
  • 25% 蓝色(B)

典型的 2×2 单元排列有两种:

  • RGGB:第一行 R G,第二行 G B
  • BGGR:第一行 B G,第二行 G R

不同的相机厂商会用不同的排列顺序。比如索尼倾向 RGGB,有些手机传感器用 BGGR。你在做 RAW 域降噪时,必须知道你的数据用的是哪种排列,否则后续处理全错。

避坑指南:我曾经接手过一个项目,团队之前的人把 Bayer 排列搞反了,结果模型训练了两个月,推理出来的图像全是彩色条纹。排查了整整一周才发现是排列顺序的问题。所以,拿到 RAW 数据的第一件事——确认 Bayer 排列。

下面这张图展示了 Bayer 阵列的结构和它如何映射到最终的彩色图像:

Bayer 阵列 → 彩色图像流程 Bayer 阵列(RGGB) R G R G G B G B R G R G G B G B 去马赛克 Demosaic + 插值 RGB 彩色图像 R G B R G B G R R G B G G B R G 关键说明: • 左侧:Bayer 阵列中每个像素只记录一种颜色(R/G/B) • 中间:去马赛克算法通过插值补全每个像素缺失的两个颜色通道 • 右侧:最终每个像素都有完整的 R/G/B 三通道值,形成彩色图像 • 降噪模型在 RAW 域处理的是左侧的数据,信息量最大、噪声最原始

1.4 RAW 文件的数据结构

RAW 文件不是单纯的像素数据,它有一套完整的「包装」。我拆解一下典型的 RAW 文件结构:

  1. 文件头(Header):包含相机型号、传感器尺寸、位深、Bayer 排列、ISO、快门速度等元数据
  2. 元数据区(Metadata):可能包含 EXIF 信息、制造商私有数据、色彩矩阵等
  3. 图像数据区(Image Data):实际的 Bayer 像素值,通常经过无损或近无损压缩
  4. 缩略图(Thumbnail):嵌入一张小尺寸 JPEG 预览图,方便快速浏览
  5. IFD(Image File Directory):TIFF 兼容的目录结构,指向各个数据块

以最常见的 DNG(Digital Negative)格式为例,它的底层其实是 TIFF 格式的变体。你可以用 libtiff 或 rawpy 库直接读取。

实用技巧:我个人习惯用 Python 的 rawpy 库读取 RAW 文件。它封装了 LibRaw,能直接拿到 Bayer 数据、白平衡系数、色彩矩阵等关键信息。下面是一段示例代码:

import rawpy
import numpy as np

# 读取 RAW 文件
raw = rawpy.imread('example.dng')

# 获取 Bayer 原始数据(形状:H×W,每个像素单通道)
bayer_raw = raw.raw_image  # dtype: uint16

# 获取 Bayer 排列模式
bayer_pattern = raw.raw_pattern  # 例如 [[0,1],[1,2]] 表示 RGGB

# 获取白平衡系数
wb_multipliers = raw.camera_whitebalance

# 获取色彩矩阵
color_matrix = raw.color_matrix

print(f"图像尺寸: {bayer_raw.shape}")
print(f"位深: {raw.raw_image.dtype}")
print(f"Bayer 模式: {bayer_pattern}")
print(f"白平衡系数: {wb_multipliers}")

# 注意:raw_image 是线性数据,可以直接用于降噪模型训练
# 不需要任何 ISP 处理

这段代码跑完后,你拿到的 bayer_raw 就是最原始的传感器数据。嗯,这里要注意——raw.raw_image 返回的是 uint16 数组,但实际有效位深可能只有 10-14 bit,高位可能全是 0。做归一化时记得除以 2^bit_depth - 1,而不是 65535。

我的习惯:训练降噪模型时,我会把 RAW 数据归一化到 [0, 1] 区间,然后以 float32 精度输入网络。推理完成后,再反归一化回 uint16 保存。这样可以避免精度损失。

1.5 为什么 AI 降噪要在 RAW 域做?

最后,我总结一下为什么我们这门课要聚焦 RAW 域:

  • 噪声模型更简单:RAW 域的噪声主要是泊松-高斯混合模型,物理意义明确,模型容易拟合
  • 信息量最大:RAW 有 10-14 bit 的动态范围,RGB 只有 8 bit,暗部细节保留更多
  • 避免 ISP 干扰:伽马校正、色调映射等非线性操作会扭曲噪声分布,增加降噪难度
  • 端到端优化空间大:你可以把降噪和去马赛克、白平衡等 ISP 模块联合优化

再次提醒:不要拿到 RAW 数据就直接当 RGB 处理。我见过有人把 Bayer 数据 reshape 成 H×W×3 然后送进 CNN,结果模型学出来的全是伪影。正确的做法是保持 Bayer 的 4 通道(R/G1/G2/B)或直接处理单通道 Bayer 图。

好了,这一章的基础知识就到这里。RAW 域的门道其实很深,但只要你理解了 Bayer 阵列、线性特性和文件结构,后面讲降噪模型时就不会觉得吃力。