ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ISP图像处理三大域:Raw、RGB、YUV的划分逻辑与实战调试

ISP图像处理三大域:Raw、RGB、YUV的划分逻辑与实战调试 做图像处理这一行天天挂在嘴边的就是ISP、Raw域、RGB域、YUV域这几个词。面试新人我经常问一句你去马赛克之后、白平衡之前数据在哪个域很多候选人能说出流程顺序但问他为什么锐化只能放YUV域、为什么坏点矫正一定要在Raw域做就卡住了。说白了三个域不是简单的“格式转换”背后是传感器物理特性、人眼感知特性和硬件成本互相博弈后的最优解。这篇文章我就把Raw域、RGB域、YUV域这三个概念彻底拆开讲清楚。内容包括每个域的数据长相、典型算法、为什么这么划分以及实际调试里怎么快速判断问题出在哪个域。适合刚入门的ISP算法工程师、嵌入式视觉开发、FPGA图像处理方向的同学也适合那些已经调了一年两年但某些细节还模棱两可的朋友。看完你至少能回答坏点矫正为什么不能放到RGB域做、CCM矩阵为什么是3x3、为什么YUV420能省一半带宽但看着还行。1. 先看清ISP pipeline这条主线1.1 一张照片从sensor到屏幕经历了什么图像工程师的工作对象本质上是一整条ISP pipeline。简化之后大概是这个顺序sensor曝光输出Raw数据然后进黑电平校正、坏点矫正、镜头阴影校正接着去马赛克、白平衡、颜色校正、Gamma再转成YUV做降噪、锐化、对比度调节最后输出给编码器或者显示设备。如果你去翻各家芯片厂商的ISP文档会发现模块顺序略有差异。比如有的方案把白平衡放在去马赛克之前直接在Raw域乘增益有的方案放在去马赛克之后。但有一条主线基本不变数据在这个过程中会经历Raw、RGB、YUV三种形态。可以说整条pipeline就是一场从“传感器看到的原始世界”到“人眼感知的世界”的逐步翻译。很多新人最大的迷惑点就在这里既然最终要给人眼看为什么不一开始就输出RGB答案很简单sensor物理上做不到。CMOS sensor每个像素上面覆盖一层彩色滤光片只能感知一种颜色分量相邻像素拼在一起才构成马赛克图案也就是Bayer阵列。所以在最源头数据天然就是Raw的。后面所有处理本质上就是在补全信息、还原颜色、优化观感。1.2 为什么要设计成三个域你可能会想能不能省略某个域说实话不能。Raw域是数据源头你绕不开YUV域是将来的输出形态你也绕不开RGB域是颜色科学的中间表示同样绕不开。三个域各有各的数学特性和物理含义算法在哪一步做直接决定效果上限和硬件成本。打个比方Raw域是一块刚买回来的生猪肉有毛、有血水、有腥味。RGB域是经过清洗、切块、腌制后的半成品看着已经像道菜了。YUV域是最后下锅调味、装盘的状态摆盘上桌直接给人吃。你在生肉阶段就撒味精肯定不对在半成品阶段做超深度清洗也多余。每个阶段处理的事必须匹配那个阶段的数据特性。所以理解三个域的区别本质上是理解一套“什么阶段该做什么事”的逻辑。Pipeline里的每个模块放哪个位置不是拍脑袋定的而是由数据特性和算法需求共同决定的。这篇文章后面讲的每个算法归属你都可以用这个逻辑倒推验证。2. 三种域的数据长什么样差异在哪2.1 Raw域每个像素只有一种颜色分量Raw域最常见的形态是Bayer阵列排列方式通常有RGGB、BGGR、GRBG、GBRG四种。无论哪种排列每一个像素位置只有R、G、B三个通道里的一个值。比如RGGB模式下第一行是R G R G第二行是G B G B奇偶行交替。所以一张1920x1080的Raw图虽然最终看起来像灰度图但每个像素存的是某个颜色通道的强度。Raw域的数据通常是线性的也就是曝光量翻倍像素值近似翻倍。位深一般是10bit、12bit、14bitMIPI接口传输时常见RAW10、RAW12格式。正因为是线性数据Raw域特别适合做跟光强有关的物理模型运算比如坏点检测、黑电平校正、镜头阴影校正。这些操作都基于一个假设像素响应与入射光强成正比。这里有个新手容易忽略的细节Raw域还带着大量“传感器病”。比如黑电平偏移暗电流导致暗部不为零、坏点死点、热点、镜头阴影边缘光强衰减、固定模式噪声FPN。这些缺陷在Raw域是有明确物理模型的修起来简单高效。一旦做完去马赛克进入RGB域像素之间的空间关系被打乱缺陷和颜色混在一起再想精准修复就非常痛苦。2.2 RGB域三通道颜色与Gamma空间的坑经过去马赛克之后每个像素点都有完整的R、G、B三个值这就是RGB域。听起来简单但RGB域有个巨大的坑它有两种状态线性RGB和非线性RGB一般说RGB域默认指非线性、经过Gamma编码后的RGB。线性RGB是去马赛克后、Gamma之前的那个状态。此时三个通道的数值仍然与光强成正比但人眼看这个图会觉得暗部太黑、亮部过曝对比度很奇怪。因为人眼对暗部亮度变化的感知更加敏感呈一种非线性关系。所以ISP会做一个Gamma校正把线性数据映射为非线性数据。做完Gamma之后才进入所谓RGB色彩空间比如sRGB、Display P3这些。判断你手里的RGB数据处于哪个阶段最直观的办法是看灰阶曲线或者直接看图像。如果在中间调附近亮度跳变很突兀暗部一片死黑大概率是线性RGB如果亮度过渡平滑自然明暗对比符合日常照片的观感那是Gamma之后的RGB。这个区分非常重要因为CCM的标定、白平衡的统计、饱和度调节全都依赖当前RGB的准确状态。我在实际调试里见过不止一次有人拿线性RGB数据去套Gamma之后的CCM矩阵结果整体偏色改了半个月最后发现是域搞错了。2.3 YUV域亮度与色度分离的好处YUV域把图像拆成一路亮度Y和两路色度U、V。Y反映明暗信息U、V反映颜色差异。它和RGB最大的区别是人眼对亮度细节敏感对色度细节不敏感。所以YUV域天然支持色度下采样比如YUV420格式Y全分辨率保留U、V各抽掉75%的信息人眼几乎分辨不出区别。正因为这个特性YUV域是视频编码、显示传输、图像存储的主流格式。JPEG、H.264、H.265、HDMI、MIPI DSI底层通通是YUV或者更直接的亮色分离格式。做ISP输出的时候最后一步基本都是RGB转YUV然后送给编码器或者显示控制器。YUV域的数据特性是“信息已按人眼感知权重重新排列”。亮度通道包含了大部分结构细节适合做边缘锐化、对比度增强色度通道信息量稀疏适合做针对性降噪、肤色保护。如果你在RGB域对三个通道同时做锐化边缘会出现彩色过冲画面看起来脏兮兮的。而在YUV域只对Y通道锐化既能增强轮廓感又不会破坏颜色的纯净度这就是域划分带来的巨大好处。三个域的差异用一张表可以看得很明白特性Raw域RGB域YUV域像素内容每像素单通道Bayer每像素R、G、B三通道Y亮度U/V色度典型位深10bit / 12bit / 14bit8bit / 10bit8bit / 10bit线性关系线性线性RGB或Gamma后RGBGamma后非线性跟人眼关系传感器视角颜色科学视角感知与编码视角存储带宽最低1/3于RGB888最高YUV420约为RGB888一半典型算法黑电平、坏点、LSCAWB、CCM、Gamma降噪、锐化、增强3. 每个域里到底做哪些算法为什么这样划分3.1 Raw域先治“传感器病”Raw域的核心任务是修数据尽量还原sensor本来应该输出的干净线性信号。顺序通常是黑电平校正、坏点矫正、镜头阴影校正有的pipeline还会在这里做第一级降噪。黑电平校正为什么必须在Raw域因为sensor存在暗电流即使完全遮光像素也会有一个非零的基底值比如12bit下典型黑电平是64。如果不减掉这个offset后续所有颜色计算都会被叠加一个大常数暗部会偏灰、偏色而且白平衡统计也会被严重污染。减掉黑电平之后暗部的零才真正对应“没有光”。坏点矫正也是Raw域的专利。坏点分两种死点和亮点。死点是永远不响应光输出固定低值亮点是持续输出高值或者随机跳变。为什么不能放到RGB域再做因为坏点在Bayer阵列里是单个像素到了RGB域一个位置的值已经是由周围像素插值出来的坏点的影响被扩散成一片彩色伪影想定位原始坏点位置都困难。镜头阴影校正LSC同样依赖Raw域的线性特性。镜头边缘的光强衰减可以用一个增益曲面去补偿这个增益曲面是跟光强线性相乘的关系。如果在Gamma之后做非线性映射会改变增益的倍数关系四角补偿就不均匀了。顺便说一句热词里反复出现的CIS ISP坏点矫正指的就是这一级处理。Raw域里还会做线性化处理。有些sensor输出不是完全线性的特别是HDR sensor在长短曝光融合之前需要把各帧映射到同一线性亮度域这个操作也只能在Raw域完成。3.2 RGB域让颜色“像人眼看到的”RGB域的核心任务是颜色还原和视觉映射。最主要的三件事白平衡AWB、颜色校正矩阵CCM、Gamma校正。有些方案还会在这里做色调映射Tone Mapping和色彩增强。白平衡的本质是在不同色温光源下白色物体在Raw域里R、G、B响应并不相等比如白炽灯下R分量偏高荧光灯下B分量偏高。AWB算法会估计一个光源色温然后给R和B通道乘上不同增益让白色回归中性。这个增益调节可以放在Raw域做也可以放在RGB域做主要看统计模块在哪。但有一点是共识必须在Gamma之前做否则非线性映射会扭曲通道比例关系。CCM矩阵为什么是3x3因为sensor滤光片的光谱响应曲线和人眼视锥细胞的光谱响应不匹配直接输出的RGB经过人眼观察会偏色。CCM通过一个3x3矩阵把sensor RGB线性变换到标准色彩空间的RGB本质上是一次坐标系变换。CCM的标定很大程度依赖标准色卡比如X-Rite ColorChecker这是ISP调试中比较考验基本功的一环。Gamma校正在RGB域做的原因前面提过人眼对暗部更敏感对亮部不敏感。所以用非线性编码把暗部细节拉开亮部压缩视觉上更舒服编码效率也更高。注意Gamma不是一个可选项而是整个色彩管道的基石。你后面做的饱和度调节、肤色亮度调整、对比度拉伸全都建立在Gamma后的RGB空间里这个空间的数据分布决定了所有参数的实际效果。3.3 YUV域给观感做减法与加法进入YUV域之后主要目标是面向显示和编码做观感优化。常见的有亮度降噪、色度降噪、边缘锐化、对比度增强、饱和度调节以及肤色保护类算法。降噪放在YUV域有个天然优势可以把噪声分成亮度噪声和色度噪声分别处理。暗部的亮度噪声看起来是颗粒感色度噪声看起来是彩色斑点。在YUV域做降噪既能针对性地抹掉色度噪声又能在Y通道保留更多细节效果比RGB域统一降噪好得多。很多手机夜景算法的最后一层精修就是在YUV域完成的。锐化放在YUV域准确说是只对Y通道锐化。这是业内默认做法原因就是避免颜色过冲。你可以试试在RGB域对三个通道同时加USM锐化边缘处一定出现红边或者蓝边的彩色伪影。而在YUV域Y通道锐化后边缘对比度提升U、V通道不动颜色信息不受影响画面看起来清爽很多。热词里提到的ISP图像效果调试有很大一块工作就是在练这个“只动Y不动UV”的手感。还有一个容易被忽略的点YUV域的饱和度调节本质是调节U、V通道的幅度。但人在看照片时对肤色偏色极其敏感。所以成熟ISP方案里的饱和度调整往往带肤色保护区只对色相落在肤色区间的像素做特殊处理防止肤色发青发绿。这些精细化调节放在YUV域做数据结构天然支持按色相划分区域RGB域反而没这么直观。4. 实际调试中怎么判断当前在哪个域4.1 从数据本身一眼看穿调试ISP时最实用的技能不是读文档而是拿到一帧中间数据能立刻判断它属于哪个域。第一招是看文件后缀和位深DNG、RAW、Bayer文件基本是Raw域BMP、PNG、PPM如果三个通道等位深大概率是RGB域YUV后缀或裸数据标明YUV420/422的就是YUV域。第二招是看像素布局。你用图像查看器打开一个Raw文件如果放大后能看到马赛克纹理每四个像素呈现RGGB重复图案那肯定是Raw域。RGB域放大后每个像素都有完整三通道颜色连续变化平滑没有马赛克。注意如果图像解码方式不对RGB图也可能显示成花屏或噪点但不会呈现规则的Bayer图案。第三招是看暗部行为。Raw域数据一般有黑电平偏移所以直方图最左端不是零而是停留在一个固定值附近。RGB域的Gamma空间暗部会被拉伸直方图在暗部可能有一个小峰。YUV域就更明显了U、V通道直方图通常是以0为中心的对称分布类似钟形曲线而Y通道直方图则跟灰度图差不多。看一眼直方图形状基本就能确定域。4.2 结合寄存器、配置和pipeline定位如果说数据观察是“猜”那查硬件寄存器配置就是“验”。MIPI CSI接口收到的sensor输出格式会明确告诉你是RAW10、RGB565还是YUV422。如果你看到的是RAW10那所有后面的处理起点都在Raw域不要怀疑。另外大多数ISP芯片的调试工具都会提供pipeline断点采样功能。你可以把某个模块的输出单独导出比如去马赛克之后导出的数据应该已经是RGB域。我习惯的做法是在pipeline里按固定顺序抓几个关键节点——Raw进ISP前、去马赛克后、Gamma后、RGB转YUV后——各存一帧图并把它们的直方图和像素格式记录下来。这样遇到问题时翻历史数据很快就能定位是哪个节点之前出的问题。初学者最容易犯的错是为了省事直接拿最终YUV画面去反推Raw域的问题。比如你发现画面边缘有红色和绿色的交替伪彩其实问题可能出在去马赛克的插值方向判断上而这个模块在RGB域入口处早就执行完了。你在最终画面后面加再强的降噪都压不住正确做法是回到Raw域检查LSC和去马赛克参数。所以养成“数据在哪一步变成什么形式”的习惯比掌握任何公式都重要。5. 常见问题速查哪个域出了毛病这里整理一张我在实际调试和带人过程中高频遇到的问题速查表方便你排查时直接对照。故障现象大概率出问题的域可能原因排查方向暗部整体偏紫/偏蓝Raw域或RGB前级黑电平未校正干净暗部offset参与颜色计算抓Raw直方图检查黑电平钳位值图像有规则小亮点/黑点Raw域坏点矫正没开或阈值过宽用全黑帧和全白帧检测坏点图四角明显变暗Raw域LSC增益曲面未校准或校准图过曝检查LSC校正表确认参考灰板曝光适中边缘出现彩色锯齿/伪彩RGB域去马赛克插值方向判断错误检查方向判断的梯度阈值和色差平滑参数白色物体不白整体偏暖/偏冷RGB域AWB色温估计偏差抓灰卡区域计算R/G和B/G比值判断增益方向色卡颜色偏移严重饱和异常RGB域CCM矩阵标定不准或标定光源不对用标准光源重新拍摄色卡计算新CCM边缘亮边彩色过冲YUV域锐化过度或误对U/V通道做了锐化确认锐化只加在Y通道查看锐化强度曲线暗部彩色噪点严重YUV域色度降噪强度不够单独调大U/V通道降噪强度观察彩噪变化整体对比度奇怪暗部断层RGB域Gamma曲线处理错误或线性RGB当Gamma RGB用导出Gamma前后中间数据对比亮度映射曲线这张表只覆盖了最典型的情况实际项目里现象往往是多个域的问题叠加。我的经验是先判断问题属于“物理缺陷”还是“颜色问题”物理缺陷优先怀疑Raw域颜色问题优先怀疑RGB域观感细节问题优先怀疑YUV域。三个方向逐个排查效率最高。再分享一个独家技巧当你怀疑白平衡或CCM有问题时不要只看彩色图先看灰度图。如果纯灰卡拍摄出来R、G、B通道的最大值和最小值分布有很大偏差那说明白平衡通道增益没对齐如果灰卡中性但彩色色块全部偏色那才是CCM需要重新标定。这个区分能帮你省掉大量瞎调时间。6. 新手调ISP的顺序建议6.1 按依赖关系从前到后调调ISP最忌讳一上来就动最后的锐化、饱和度这些“好看”参数。因为这些参数的最终效果严重依赖于前级输出的数据准不准。我的建议是严格按照pipeline顺序来先确保sensor出图正常再看Raw域黑电平、坏点、LSC有没有问题然后重点调去马赛克接着调白平衡和CCM最后才碰Gamma和YUV域的观感增强。为什么这么排因为前级错误会在后级被放大。比如Raw域黑电平没校准白平衡统计时暗部像素贡献了错误色温AWB就会偏你再去调CCM等于在错误数据上做二次校正永远调不干净。反过来把前级基础打牢后级很多参数几乎不用怎么动画面就八九不离十了。我带人的时候经常说一句话调ISP先分域再定模块最后试参数。如果一个问题你调了好几天都调不好先别继续堆参数停下来问问自己我是不是在错误的域里试图解决一个属于另一个域的问题6.2 用中间数据代替“看最终画面”刚开始做ISP调试的工程师总习惯盯着最终画面说“这里偏色了”“那里有噪声”。但最终画面是整条pipeline所有模块叠加的结果你很难只靠肉眼判断问题从哪来。所以一定要养成导出中间数据的习惯每调一个模块就用调试工具抓一帧该模块输出前后的数据来对比。举个实际例子画面出现暗部彩噪。有人直接在YUV域的色度降噪模块把强度拉到很高结果暗部是干净了但整体饱和度被拉低颜色变得灰扑扑。正确做法是先从Raw域抓图分析噪声来源看是不是sensor增益太高、黑电平校正不够、Raw域一级降噪没起作用。如果Raw域已经把噪声底子压住了YUV域只需要非常小的色度降噪就能达到干净效果而且不伤颜色。另外调完一个模块之后最好把关键中间数据导出存档。比如Raw域的坏点图表、去马赛克后的边缘放大图、CCM前后的色卡对比。这些数据后面排查问题非常有用我自己就吃过亏当时没存中间数据后来现场反馈某个场景偏色我根本不知道是后续修改哪版参数引起的。6.3 写在最后的一点体会踩过很多坑之后我最大的体会是ISP处理里的Raw、RGB、YUV三个域不是一个简单的名词概念而是一整套思考问题的方式。拿到任何图像问题第一反应不是“调哪个参数”而是“这个问题发生在哪个域”。想清楚这个再动手调参往往事半功倍。最后再分享一个小技巧多给自己留几个“标记帧”。平时调试时准备一组固定场景的测试图包含色卡、灰阶卡、高光暗部过渡场景每次改版都把这组图重新跑一遍对比差异。这样你很快就能发现自己改动对各个域产生了什么影响也能在团队协作时快速定位是不是某个域的参数被改动过。这个习惯真能帮你省下大把加班时间。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进