ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ISP调试核心:搞懂Raw域、RGB域、YUV域三大数据形态

ISP调试核心:搞懂Raw域、RGB域、YUV域三大数据形态 先说一个我面试新人的经典问题调试ISP时工具里给你同一帧画面的三张图一张灰绿带马赛克、一张有颜色但发暗、一张看着最“正常”这三张分别是什么能答上来的不算多。这个问题不是考记忆力而是因为如果你分不清ISP处理中的Raw域、RGB域、YUV域后面调起图像来就像闭着眼睛开车——看到一个现象根本不知道是pipeline里哪一级搞出来的。做图像工程师这几年我越来越觉得对这三个域的认知深度直接决定了你在ISP调试里的定位速度。很多人一上来就背pipeline框图把黑电平、坏点矫正、去马赛克、白平衡、CCM、gamma、降噪、锐化这些名词记得滚瓜烂熟但真要处理一张偏色或者满是噪点的图时还是不知道从哪里下手。原因很简单没有建立起“哪个域的故障长什么样”的条件反射。这篇文章我想把Raw域、RGB域、YUV域这几个概念彻底拆开讲一遍包括每个域的底层数据形态、核心算法、调试要点以及那些我在实际项目里踩过的坑。不管你是刚接触ISP的应届生还是做了几年嵌入式、FPGA、相机调试的老手如果能耐心看完至少下次看到一张异常图能先判断出问题出在哪个域。1. 三个域到底指什么先从一张Raw图说起1.1 一个最常见的理解误区很多教程喜欢把ISP画成一长串框图然后标记“这里是Raw域这里是RGB域这里是YUV域”。框图画得没错但问题是如果只记名字不记数据形态一到实战就会傻眼。举个我自己经历过的例子。早年在做一颗车载sensor的调试当时需要把sensor输出的裸数据用工具导出来看我第一次打开那张raw图时整个人都不好了。整张图灰蒙蒙的带着明显的暗绿色调放大后还能看到密密麻麻的方格纹理。我当时第一反应是数据通道配置错了但反复检查寄存器都没有问题。后来带我的师傅说了一句让我记到今天的话你看到的这一切都是Raw数据最正常的样子。Raw域、RGB域、YUV域这三个词本质上描述的是图像数据在ISP流水线不同阶段的存在形式。Raw域是sensor直接吐出来的单通道Bayer数据RGB域是每个像素都有完整R、G、B三分量的彩色数据YUV域则把颜色拆成亮度Y和两个色差分量U、V。它们不是一个东西经过简单调色后的不同版本而是数据组织方式完全不同的三个世界。1.2 为什么图像工程师必须把三者分开看说到底区分这三个域是为了回答一个问题某个算法应该在什么数据形态下执行效果才最正确或者说效果才不会被破坏。这个道理和做饭有点像。买菜、洗菜、切菜、炒菜是不同的阶段每个阶段处理食材的方式不一样你不能在切菜阶段就想着把菜炒熟也不能在炒菜阶段才想起来洗菜。ISP也一样黑电平、坏点矫正是Raw域做的去马赛克、白平衡、CCM是过渡到RGB域后做的降噪、锐化、饱和度调整放在YUV域更合适。如果忘记了这个先后关系把算法放错位置轻则效果不佳重则会把图像处理出不可逆的伪影。所以这篇文章不会只讲概念我会把每个域的数据特征、典型算法、调试手法和踩坑记录都串起来讲希望能给你搭一个完整的认知框架。2. Raw域一切从sensor输出的单通道数据开始2.1 为什么Raw图看起来灰蒙蒙、绿油油的先回答开头那个问题。很多人第一次看Raw图都会被它的“丑”吓到。但这份丑是有原因的。第一Raw数据是线性光响应数据。sensor上的光电二极管把光子转成电子电子数量跟光强在很大范围内是线性关系。这意味着一个亮度值为200的像素它实际接收到的光量就是亮度值100像素的两倍。听起来很合理对吧但问题在于我们平时看习惯了经过gamma校正和色彩增强的sRGB图像那种图像在暗部会提亮在高光会压缩整体对比度和观感都更接近人眼。Raw数据没有经过这些处理直接把线性响应摊在0到102310bit或者0到1638314bit的数值范围里所以在普通显示器上看起来会特别暗暗部细节几乎看不清。第二Raw图看起来发绿是因为Bayer pattern里绿色像素占了整整一半。常见的RGGB排布中一个2x2的小方块里有两个G只有一个R和一个B。如果按灰度图去显示Raw数据绿色像素位置的灰度值天然就会更亮一些整张图就会呈现出一种偏绿褐的色调。这不是sensor有病而是Bayer阵列的固有特征。第三你放大Raw图看到的“方格纹理”其实是马赛克本身。每个像素只记录了R、G、B三色中的一种显示时人为用灰度去渲染就会留下规则的格子状图案。这也是Raw域最本质的特征它不是一张完整的彩色图像而是一堆还没拼好的拼图碎片。2.2 Raw域的核心算法黑电平、坏点矫正、镜头阴影sensor吐出来的Raw数据虽然“原始”但并不能直接用于后续处理必须先在Raw域做几个基础校正。第一个是黑电平校正Black Level Correction。sensor的电路在完全没有光照时输出并不是严格的0而是会有一个偏置值这个偏置就是黑电平。它来源于暗电流、像素复位噪声和读出电路的偏置。如果不把这个偏置减掉整幅图像的黑色就不纯而且在进行白平衡增益时还会把误差一起放大。黑电平的标定方法很简单就是把镜头完全盖住让sensor在全黑环境下输出统计每个通道的平均值这个值就是黑电平。注意R、G、B通道的黑电平不一定完全一样需要分开统计。第二个是坏点矫正DPCDefect Pixel Correction。传感器在制造和长期使用过程中难免会有个别像素输出异常有的恒亮有的恒暗有的输出值明显偏离真实光照。坏点分两种静态坏点和动态坏点。静态坏点出厂时已经标定好一般在初始化阶段加载一张坏点表去修动态坏点则是在运行时实时检测基本思路是拿当前像素和周围邻居做比较差异超过阈值就认定为坏点用邻域值替代。动态坏点的阈值调起来很讲究调大了漏检画面上会留白点调小了误杀正常的高频细节比如头发丝、树叶边缘会被当成坏点磨掉产生模糊和“水彩化”痕迹。第三个是镜头阴影校正LSCLens Shading Correction。镜头的边缘进光量天然小于中心所以Raw图四周会比中心暗这种亮度衰减叫lens shading有些镜头还会带来颜色阴影也就是中心和边缘的色温不一致。校正思路是存一张逐像素的增益图然后在Raw域把四周的像素乘上对应的增益。这里有个关键点因为Raw是线性数据乘法增益能够真实恢复光强度。如果放到gamma之后再做非线性变换已经改变了增益和亮度之间的对应关系边缘的正中心亮度可能恢复了但中间调和高光部分会出现非常奇怪的亮带。2.3 Raw域的调试技巧与常见坑关于Raw域的调试我有一条铁律先确认原始数据是干净的再谈后面怎么调。具体来说我拿到任何一颗新sensor都会先做三件事。第一确认Bayer排布。RGGB、BGGR、GRBG、GBRG这四种排布必须从sensor datasheet或寄存器配置里确认清楚。排布写错是灾难性的后面去马赛克出来的颜色会整体花掉很多人会误导成CCM或AWB的问题调半天发现是排布错了。第二盖镜头盖看黑电平统计值。如果Raw平均值离标称黑电平很远先查寄存器配置别急着动算法。第三拍一张均匀亮度的灰卡或者对着白墙找固定位置的亮点和暗点。如果发现固定位置的坏点先查DPC有没有生效。还有一个非常常见的坑直接在普通看图软件里打开Raw文件看到一片乱码就以为数据坏了。正确做法是使用ISP调试工具比如海思、高通、安霸的tuning工具或者用Python的cv2、rawpy之类的库做bayer预览或者干脆先按灰度显示用人眼去检查局部的异常纹理。我再说一个看Raw图的心理建设不要用sRGB的审美标准去评价Raw图。看到它暗、看到它绿、看到它花都是正常的。如果一个Raw图看起来直接就很鲜艳透亮反而要怀疑数据是不是已经被处理过或者被错误地转成了RGB显示。3. RGB域彩色世界从去马赛克开始重建3.1 去马赛克从Bayer到真彩色的插值艺术Raw域是单通道的要变成真正的彩色图像第一步就是去马赛克Demosaic。它的任务是每个像素自己只记录了一种颜色需要用周围的像素信息把另外两个缺失的颜色猜出来。最简单的去马赛克算法是双线性插值就是取周围同色像素的平均值。速度快但后果很典型边缘会出现锯齿有高频细节的区域会出现彩色的摩尔纹。稍微讲究一点的做法会先判断边缘方向沿着边缘方向插值而不是横跨边缘插值这样边缘就能保持锐利。再高级一点的做法会做色彩一致性约束尽量减少边缘处的伪彩。去马赛克的质量直接决定整张图的上限。后面所有算法做的都是“锦上添花”但在去马赛克这一步丢失的细节后面再努力也找不回来。这就是为什么现在很多高端设备开始使用AI去马赛克本质上就是用更强的先验知识去重建缺失的颜色信息。如果你是在FPGA上做ISP去马赛克还有一个工程层面的难点。Bayer数据是按行输出的每行只保留一种颜色要计算出某个像素的RGB必须等它周围几行数据全部到位。所以硬件上一般要准备三行甚至更多的行缓存line buffer。很多FPGA ISP的边缘花屏、横纹问题追根溯源都是行缓存没做够或者跨时钟域没有处理好。3.2 白平衡为什么要在线性RGB域做去马赛克之后图像变成了每个像素都有R、G、B三分量的RGB图但这个RGB图的颜色还不准。这里有两大误差源一是光源色温二是sensor自身的光谱响应。先解决光源色温问题。人眼有很强的色彩恒常性一张白纸在暖黄灯光下看着是白的在阴天冷光下看着也是白的但sensor没有这个能力它忠实记录光线的原始颜色所以在低色温暖光下白纸拍出来就是偏黄的。白平衡AWB要做的就是估计当前光源色温然后给R、G、B三个通道分别乘上不同的增益让中性色重新变成中性色。这里有一个关键问题白平衡增益在哪个域做答案是在线性光的RGB域做或者等效地在Raw域直接做。为什么必须在线性域因为人眼对亮度的感知和光的物理强度不是线性关系如果数据已经做了gamma校正那么此时去乘通道增益不同亮度区域的改变幅度是不一样的会导致高光出现奇怪的色晕阴影部分颜色又拉不回来。实际ISP实现中AWB增益大多数是在demosaic之前直接乘在Raw数据上这在线性数学上是等效的逻辑上也可以看作线性RGB域的操作。调试白平衡有一个非常朴素但高效的方法拍一张标准的灰卡或白纸看R、G、B三通道的直方图是否重合。如果三个通道直方图错开那肯定先查AWB增益不要急着动别的参数。3.3 CCM色彩校正与Gamma映射AWB解决了光源色温导致的偏色但sensor自身的光谱响应曲线和人眼并不完全一致。即便白平衡已经准确很多颜色拍出来还是不够正红色不够纯、绿色偏黄、蓝色偏紫。这时候需要CCMColor Correction Matrix它本质上是一个3x3矩阵把sensor的色彩空间映射到标准色彩空间比如sRGB。CCM一般要针对不同色温分别标定调试工具里通常会有多组CCM用于不同光照环境。CCM之后是gamma校正。gamma做了一件看起来很简单但意义重大的事把线性光映射为非线性编码。标准和常用的sRGB gamma值大约是2.2它接近人眼对亮度的感知特性。之所以必须做这个非线性变换是因为8bit图像总共只有256个灰度级如果采用线性编码暗部从0到10的灰度差异在显示器上会非常粗糙色阶断裂肉眼可见。gamma校正把更多的编码空间分配给了暗部让暗部过渡更细腻。但gamma带来了一个非常重要的“禁令”一旦数据过了gamma它就不再是线性光了。所有必须在线性域完成的处理比如白平衡增益、镜头阴影校正、CCM都必须严格放在gamma之前。如果处理顺序错了比如在gamma之后的非线性RGB域做白平衡或者CCM就会出现我在3.2里说的那种诡异的亮度相关偏色。这条规则是ISP调试里不可破坏的底线。3.4 RGB域调试时该怎么看图RGB域是色彩问题的高发区也是新手最容易瞎调参数的环节。我的建议是按顺序排查永远不要跳步。第一步灰卡测试。拍灰卡看RGB三通道直方图是否重叠。如果不重叠先查AWB把三个通道的增益调到位。第二步白平衡准确后再看色卡。用标准24色色卡在调试工具里看每个色块在色度图上的位置和目标坐标对比。如果某一组颜色偏差明显比如肤色偏红或者天空偏青再用CCM去修。注意CCM是强耦合的矩阵改一个系数整个色域都会受到影响所以每次调整的幅度要小并且要反复确认其他颜色没有被带偏。我见过太多人一上来就调CCM结果越调越乱。记住AWB没有校正之前你在CCM里看到的颜色偏差是不可信的因为光源偏色和色彩响应误差混在一起。先把中性色调准剩下的颜色误差才是CCM要解决的问题。RGB域的另一个重要判断点是线性和非线性的分界线。在调试工具里demosaic刚出来的RGB图是线性的看起来会比较暗此时先去判断AWB、CCM。gamma之后的RGB图看起来已经接近人眼感知了这时候的颜色调整要非常克制因为这时你看到的偏差很可能不是RGB域的问题而是YUV域色调映射的问题盲目调整只会把前面的成果毁掉。4. YUV域把图像转成人眼更舒服的格式4.1 从RGB到YUV亮度与色彩分离的本质经过gamma之后RGB图像已经是一张能看的彩色图了但ISP的pipeline到这儿通常不会结束。接下来大部分相机和视频系统会把RGB转成YUV然后才输出给编码器或显示器。这一步不是多此一举而是有非常实际的理由。人眼对亮度信息的敏感度远高于对颜色信息的敏感度。YUV格式恰好把亮度Y和色度U、V完全分开这样我们就可以针对性地做处理细节、纹理、边缘主要放在Y通道管颜色偏差、彩色噪声主要放在UV通道调整。更关键的是YUV格式天然支持色度子采样比如视频里最常见的YUV 4:2:0UV通道的分辨率只有Y通道的四分之一直接省掉一半的带宽和存储空间而人眼基本察觉不到。RGB到YUV的转换是一个标准的线性变换。以BT.709为例大致是Y 0.2126R 0.7152G 0.0722BUV分量则通过RG差值来构造。这个变换没有信息损失在理想情况下是可逆的。不过在实际工程里由于位深和量化精度的限制来回转换会产生误差积累所以好的ISP设计会尽量减少重复的往返转换。4.2 YUV域的核心算法降噪、锐化、饱和度YUV域里最常见的算法有三个降噪NR、锐化、饱和度调整。降噪是YUV域的拿手好戏。sensor的噪声在弱光和高ISO下特别明显表现为亮度噪声和色度噪声两种形态。亮度噪声是颗粒感色度噪声是彩色斑点。在RGB域做降噪的问题在于RGB三通道的噪声相互关联你压制一个通道的噪声可能让另一个通道出现颜色偏差而在YUV域你可以对Y通道做适中强度的降噪来保持细节对UV通道则可以放心大胆地做更强的平滑因为人眼对彩色噪声的容忍度很低但对色度细节的丢失并不敏感。这就是为什么几乎所有成熟ISP都在YUV域做降噪。锐化也一样。锐化的本质是增强边缘处的局部对比度但这个增强如果作用在RGB三通道上很容易在边缘两侧形成过冲产生彩色边纹。正确做法是在Y通道上做锐化因为人眼的边缘感知几乎完全来自亮度信息UV通道不需要做额外增强。饱和度调整则主要作用于UV分量。UV幅值越大颜色越浓郁UV幅值越小颜色越清淡。这个调节看起来直观但调过头会让颜色溢出、肤色失真。特别是肤色它是人眼最敏感的颜色之一饱和度稍微超标就会被用户评价为“假”。4.3 调试YUV域的实用方法YUV域的图看起来最“正常”反而最容易麻痹人。我的经验是在调试工具里一定要把Y通道和UV通道拆开来看。只显示Y通道你会看到一张黑白图这时候检查亮度噪声、边缘过渡、纹理细节最清楚。如果Y通道看着很干净但整体画面发闷那可能是对比度或锐化没调好如果Y通道有颗粒状噪声说明降噪没压住亮度噪声。再显示UV通道也就是色度通道这时候画面上出现大量彩色噪点的区域会非常抢眼。UV的伪彩色显示在这种检查里特别好用。调降噪和锐化时要有耐心它们是一对需要平衡的组合。我自己总结的经验是先让降噪把明显的噪声压到“不干扰观看”的程度然后让锐化把纹理细节拉回来一次调一档反复对比。千万不要把降噪拉到最猛那样画面确实干净得像镜子但纹理也全磨平了走近看就像一张塑料。5. 三域边界与最常踩的坑5.1 处理放错域会出什么问题我前面反复强调每个算法要在对的域里做这不是洁癖而是处理效果的天壤之别。下面举几个真实发生过的案例。镜头阴影校正放错域是我见过最典型的例子。有人图省事不校正Raw域的lens shading而是把整个画面在RGB域直接乘一个增益图想着也能把四周提亮。结果因为代码运行在gamma之后的数据上靠近画面边缘的地方高光区域因为增益过大直接过曝还出现了明显的色偏。本来一个线性问题在非线性域里硬做就变成了一个亮度相关的非线性病。锐化放错域也很常见。如果把锐化加在RGB三通道上在物体的高对比边缘RGB三个通道的过渡起点和终点不一样锐化的过冲会放大这种差异形成非常难看的彩色边纹。而同样的锐化强度放到Y通道上边缘就干净利落没有彩边。这个对比我做过很多次演示每次都能让新人直观地理解“域”的重要性。白平衡放到gamma之后做表现则更加隐蔽。画面整体色温看着正常了但高光区域出现了粉色或者青色的晕染暗部区域的色偏却怎么都拉不回来。这就是因为gamma已经改变了通道间的比例关系你在非线性域乘增益不同亮度区域得到的颜色变化是不均匀的。遇到这种“亮度相关偏色”第一个排查方向永远是pipeline里有没有哪个处理被错误地放到了非线性域。5.2 一图定位偏色、噪点、白边到底哪个域的问题实战中拿到一张有问题的图怎么快速定位我整理了一张速查表平时查问题基本靠它。现象优先怀疑的域常见原因全图暗部发绿、整体偏色Raw / RGB黑电平不准、AWB增益异常固定位置亮点或暗点RawDPC失效、坏点表未加载四周发暗暗角RawLSC参数不佳灰卡下RGB直方图不重合RGB线性AWB增益不对特定色块偏色明显RGBCCM系数需要重新标定高ISO彩色噪点多YUVUV降噪强度不足物体边缘出现彩色边YUV / RGB锐化加错通道、demosaic伪彩画面清楚但颜色发闷YUV饱和度过低或UV范围被压缩这张表的核心价值不是给你标准答案而是帮你把排查范围缩小。很多ISP问题不是单一原因但如果你能先锁定“哪个域最可疑”再去翻那一级的中间图像效率会高很多。5.3 三域速查表最后送你一张我是真的倒背如流的速查表建议存下来或者贴显示器边上。特性Raw域RGB域YUV域数据形态Bayer单通道马赛克每像素3通道YUV分离典型位深10/12/14bit8/10/12bit8/10bit常有子采样亮度关系线性光前段线性、后段非线性接近人眼感知人眼观感暗、绿、花有色彩可能偏暗/偏亮最接近最终成片核心算法黑电平、坏点矫正、镜头阴影去马赛克、白平衡、CCM、gamma降噪、锐化、饱和度、编码前置调试重点数据是否干净、排布是否正确中性色是否准确、色卡是否达标噪点平衡、锐化是否引入伪影这张表看着简单但每次我遇到一个复杂问题都会回来扫一眼。它帮我避免了很多“在错误的地方找问题”的时间浪费。再分享一个我个人的习惯拿到任何一张有问题的图我从来不靠猜而是会打开全链路每一级输出的中间图像从Raw、demosaic后的RGB、gamma后的RGB、YUV域的Y和UV一路看下来问题在哪一级开始出现就锁定了哪个域。这个习惯帮我少调了无数冤枉参数也让我在带新人的时候能非常快速地指出他们的问题到底出在pipeline的哪一段。希望你们也能养成这个“顺着链路找问题”的调试习惯。
返回列表