4. 原始图像数据获取与格式解析

在汽车图像质量调试中,ISP 输出的 YUV 或 RGB 图像已经过降噪、去马赛克、色调映射等处理,很多缺陷会被掩盖或改变形态。要真正定位镜头阴影、坏点、暗电流、色彩串扰、噪声底等问题,必须回到传感器输出的 RAW 数据。本节围绕“拿到 RAW、看懂 RAW、导出可分析图像”这条主线展开,重点讲清 Bayer 排列、位深、打包模式以及 onsemi 私有元数据的解析方法。

一、RAW 数据的本质:Bayer 阵列与 CFA 排列

绝大多数车载 CMOS 传感器在每个像素上只放置一个颜色滤光片,形成 Color Filter Array(CFA)。最常见的排列是 2×2 重复单元,即 Bayer 模式。四种典型排列为 RGGB、BGGR、GRBG、GBRG,命名方式是按 2×2 单元从左到右、从上到下的颜色顺序读取。例如 RGGB 表示第一行是 R、G,第二行是 G、B。

RAW 文件本身通常不携带颜色信息,只有每个像素的灰度值。如果 Bayer 相位判断错误,去马赛克后会出现明显的红绿或蓝绿偏色,且偏色区域呈棋盘格状。因此解析 RAW 的第一步是确认 CFA 排列,并与传感器寄存器中 CFA_PATTERN 或 onsemi 元数据中的 Bayer 字段交叉验证。

二、位深与打包模式:从 8bit 到 16bit 容器

位深决定每个像素的量化精度。车载传感器常见 10bit、12bit、14bit,部分高动态场景使用 16bit 或压缩 RAW。位深越高,暗部层次和动态范围保留越好,但数据量也越大。例如 1920×1080、12bit 的 RAW 单帧约 1920×1080×12/8 ≈ 3.11MB;若用 16bit 容器存储,则约 4.15MB。

打包模式是解析 RAW 时最容易出错的地方。常见模式包括:

  • Unpacked(非打包):每个像素占 2 字节,低 12 位有效,高 4 位补零或填充。解析时直接按 16bit 读取再右移或掩码即可。
  • Packed(紧凑打包):多个像素的有效位连续拼接,例如 12bit packed 中每 3 字节承载 2 个像素。解析时必须按位域提取,不能按字节对齐读取。
  • MIPI RAW10/RAW12:每 4 个像素一组,额外字节存放低位。RAW10 中 5 字节承载 4 个像素,RAW12 中 3 字节承载 2 个像素。这类格式在 CSI-2 传输中很常见,解析时要按组还原。

判断打包模式是否解析正确,可以观察直方图:若低位被错误截断,直方图会出现梳状间隙;若字节序错误,图像会出现规律性条纹或整体亮度异常。

三、onsemi 私有元数据解析

onsemi 传感器通常在 RAW 帧的头部或尾部嵌入私有元数据(Embedded Data / Metadata),用于记录曝光、增益、温度、帧号、坏点校正状态、CFA 相位、黑电平等信息。这些数据不在标准 MIPI 像素流中,而是通过额外的数据行或独立寄存器读出。

解析 onsemi 元数据时,需要先确认三个关键参数:元数据起始地址、每行字节数、字段偏移表。常见做法是从传感器数据手册中获取 Embedded Data 的行数和每行长度,再按字段定义逐位解析。例如某型号在帧头嵌入 4 行元数据,每行 16 字节,其中第 0~1 字节为帧号,第 2~3 字节为曝光行数,第 4~5 字节为模拟增益,第 6~7 字节为数字增益,第 8~9 字节为传感器温度,第 10 字节为 CFA 相位。

解析时要注意字节序(onsemi 多为小端或大端需查手册确认)和有效位宽。例如模拟增益字段可能只有 12 位有效,高 4 位为保留位。若直接按 16 位读取,会得到错误增益值,进而影响后续噪声分析。

RAW 数据获取与解析链路 CMOS 传感器 Bayer CFA 曝光 MIPI CSI-2 传输 RAW10 / RAW12 Packed 位流 接收端 / 采集卡 解包 + 元数据分离 帧缓存 解析工具 Python / MATLAB rawpy / 自研脚本 Bayer 2×2 单元(RGGB 示例) R G G B 位深与打包模式 Unpacked:2 字节/像素,低 12 位有效 Packed:3 字节承载 2 个 12bit 像素 MIPI RAW10:5 字节承载 4 个像素 onsemi 私有元数据字段 偏移 0x00:帧号(2B) 偏移 0x02:曝光行数(2B) 偏移 0x04:模拟增益(2B,12bit 有效) 偏移 0x06:数字增益(2B) 偏移 0x08:温度(2B,有符号) 偏移 0x0A:CFA 相位(1B) 导出可分析图像与验证要点 ① 按 CFA 相位去马赛克 → 检查偏色与棋盘格 ② 直方图检查低位截断与梳状间隙 ③ 黑电平与增益归一化 → 暗电流/噪声底分析 ④ 元数据交叉验证曝光/增益/温度一致性

四、使用工具导出可分析图像

拿到 RAW 后,通常需要导出为可分析的图像格式,如 16bit TIFF、PNG 或 NumPy 数组。以 Python 为例,若已知图像宽高、位深、Bayer 相位和打包模式,可以用 NumPy 按位域解包,再重塑为二维数组。以下是一个 12bit packed 的解包示例:

import numpy as np

def unpack_12bit_packed(data, width, height):
    # 每 3 字节承载 2 个 12bit 像素
    data = np.frombuffer(data, dtype=np.uint8)
    data = data.reshape(-1, 3)
    p0 = (data[:, 0].astype(np.uint16) << 4) | (data[:, 1].astype(np.uint16) >> 4)
    p1 = ((data[:, 1].astype(np.uint16) & 0x0F) << 8) | data[:, 2].astype(np.uint16)
    pixels = np.empty(data.shape[0] * 2, dtype=np.uint16)
    pixels[0::2] = p0
    pixels[1::2] = p1
    return pixels.reshape(height, width)

解包后,建议先做黑电平扣除和增益归一化,再导出 16bit TIFF。若使用 rawpy,可以直接读取 DNG 或 RAW 文件,并通过 raw.postprocess() 控制输出色彩空间和位深。但要注意,rawpy 默认会应用白平衡和去马赛克,若要做纯 RAW 分析,应关闭这些选项,或直接读取 raw.raw_image。

五、结果判读与常见问题

导出图像后,可以从以下几个维度判断解析是否正确:

  • 偏色:若整体偏红或偏蓝,可能是 CFA 相位错误或白平衡未归一化。
  • 棋盘格:若出现规律性明暗交替,通常是 Bayer 相位与去马赛克算法不匹配。
  • 条纹:若出现水平或垂直条纹,可能是打包模式解析错误或字节序问题。
  • 直方图间隙:若直方图出现梳状间隙,说明低位被截断或位深映射错误。
  • 元数据异常:若曝光、增益、温度字段明显偏离合理范围,应检查字节序和有效位宽。
在实际调试中,建议先用一帧均匀亮场(如积分球或均匀白板)验证解析链路,再切换到实际场景。均匀亮场下,若图像中心与四角亮度差异明显,则可能是镜头阴影或传感器响应非均匀性,而非解析错误。

完成 RAW 解析和导出后,后续的噪声分析、坏点检测、色彩校正才有可靠的数据基础。下一阶段将基于这些可分析图像,展开具体的图像质量评估与调优。