ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

一文读懂RAW、RGB、YUV:采样、存储与格式转换的工程实战

一文读懂RAW、RGB、YUV:采样、存储与格式转换的工程实战 传感器输出的明明是彩色的景为什么一存下来就成了矩阵数字十年前我刚接触图像采集卡时被RAW、RGB、YUV这三兄弟折腾得够呛——拿着RAW格式的拜耳数据当RGB去显示画面偏绿、偏色、出现网格纹最后查了一周原因发现是对“采样”和“存储”这两个环节的理解出了问题。这篇文章就围绕这三个图像格式展开我把这个主题拆成三件事来聊传感器到底采了什么回来RAW人眼和屏幕需要什么颜色结构RGB以及为了压缩和传输我们怎么“聪明”地丢掉信息YUV。同时会给出每种格式的真实存储计算公式、格式转换时的经典坑以及嵌入式采集链路里采样与缓冲对齐的实操经验。无论你是在调摄像头、写ISP还是研究视频编码、做存储系统这三类格式都是绕不开的建议收藏后边看边动手验证。1. 三种格式到底在解决什么问题1.1 RAW传感器物理采样的原始账本图像传感器本质上是一堆光电二极管阵列每个像素把光转换成电荷再由ADC转成数字量。这个数字量就是这个像素在某一时刻接收到的光子强度的量化值。RAW文件保存的就是这些未经任何后期处理的ADC原始输出。打个比方RAW等于你在菜市场买的带皮原生态土豆土没有洗、皮没有削什么加工痕迹都没有。它的优点是信息量最大动态范围保留得最完整后期处理的弹性极高缺点是它根本不能直接显示因为每个像素只记录了“明暗”而没有真正意义上的“颜色”颜色需要靠后续插值算法脑补出来。所以RAW格式的关键在于“忠实采样”它的位深决定了ADC把光强细分到了什么程度。常见的传感器有10bit、12bit、14bit少数工业相机能做到16bit。位深越大量化台阶越细暗部细节越不容易出现色阶断层。1.2 RGB给人眼和屏幕准备的“完整颜色”RGB是为显示设备设计的颜色模型它的思路是加色法红绿蓝三束光按不同比例叠加产生各种颜色。屏幕上的每一个像素都由红、绿、蓝三个子像素组成所以RGB格式天然适合“直接点亮屏幕”。在采样层面RGB格式要求每个像素同时记录R、G、B三个通道的数值也就是说一个像素需要采样三次——分别对红光、绿光、蓝光敏感的三个位置取样。如果做成硬件就是常见的三传感器分光棱镜相机或者3CCD摄像机成本极高。普通民用设备只有一片传感器那这个“三通道采样”通常是通过色彩插值算法从RAW数据里“计算”出来的并非真正物理采样。RGB的优势简单粗暴就是颜色结构完整处理逻辑简单做图像识别、界面渲染、截图保存时特别方便。但代价也很直白数据量几乎是所有格式里最大的。RGB888单个像素就得3个字节一帧1080P图像光内存就吃掉6MB多视频场景根本存不起。1.3 YUV给带宽和压缩准备的“聪明格式”YUV严格讲视频编码里常用的是YCbCr把颜色拆成一路亮度Y和两路色度Cb、Cr。亮度代表灰阶明暗信息色度代表颜色偏离灰色的程度。这样做最大的好处是人眼对亮度变化非常敏感对色度变化相对迟钝所以色度通道是可以降低采样密度的。于是就有了色度下采样chroma subsampling最典型的就是4:2:0。视频编码标准H.264、H.265、JPEG等几乎清一色采用这种格式作为原始编码输入。相比RGB8884:2:0格式的YUV能省一半的数据量而观感损失非常小这就是它能在视频传输、直播、监控、手机录像领域独占鳌头的原因。YUV的聪明之处在于它把“人眼主观感受”纳入了格式设计用最小的数据量换取尽量高的视觉质量。这个思路和RAW“忠实记录一切”形成鲜明对比。2. 采样原理从传感器到像素的每一级2.1 拜耳阵列为什么一个像素只有一种颜色单传感器相机要拍彩色照片必须在传感器表面覆盖一层彩色滤波阵列CFA最经典的是拜耳阵列Bayer Array。它以2x2为基本单元排列通常是RGGB右下和左上各一个绿色右上一个红色左下一个蓝色。为什么绿色占了一半因为在可见光谱中人眼对绿色最敏感而且植物、人脸的绿色分量占比也大让更多采样点给绿色能显著提升视觉分辨率和信噪比。但代价是RAW数据里每个像素只有一个通道的强度值不存在三个通道这就是“单通道采样”的本质。这个细节对很多新手特别容易造成误解。Raw格式并非“没处理过的RGB”而是“每个像素只记录一个颜色分量的强度”。你直接把它当灰度图看图像会偏暗且发绿直接按RGB三通道去解码一定会出现大量伪色和摩尔纹。真正得到完整彩色图像必须经过去马赛克Demosaic插值把RGBG四个像素合成出一个三通道像素。2.2 RGB全采样与单传感器插值理论上RGB三通道全采样要求每个像素位置真实获取三种颜色的光强这需要三个传感器分别加红、绿、蓝滤光片再用分光棱镜把入射光分成三路。这种“3CCD/3CMOS”结构只在专业广电摄像机和部分医疗相机上出现。因为光路复杂、体积大、成本高民用品根本不会用。单传感器相机要生成RGB只能靠插值。最常见的是双线性插值目标像素缺哪种颜色就取周围同样颜色的像素求平均。这带来两个后果第一高频细节处的颜色会产生伪彩色也就是所谓的“彩色摩尔纹”第二图像边缘会变软锐度下降。所以现代ISP会用更复杂的自适应插值算法比如结合边缘方向的插值以及去摩尔纹处理。采样层面的结论是RGB格式虽好但它的“全采样”往往只是屏幕端的显示格式而采样源头有很大概率还是拜耳阵列。理解这一点才明白为什么很多工业相机宁愿输出RAW也不输出RGB——一旦在相机内做插值信息就回不来了后期无法再调整。2.3 YUV色度子采样与4:2:0的真相YUV的采样本质是两个步骤的叠加先把传感器数据经ISP转换成亮度和色度分量然后对色度分量做下采样。下采样不是简单的“把某些像素扔掉”而是让多个相邻像素共享一份色度值。用4:4:4、4:2:2、4:2:0来标记采样关系。这个表示法源自数字视频采样标准其中第一个数表示水平方向的亮度采样点参考基准4第二个数表示第一行中每4个亮度像素对应的色度样本数第三个数表示第二行中每4个亮度像素对应的色度样本数。具体来说4:4:4每个亮度像素都有独立的Cb和Cr色度全保留数据量约等于RGB。4:2:2水平方向每两个亮度像素共享一对Cb/Cr每行的色度采样数减半。4:2:0水平方向采样减半垂直方向也减半即每4个2x2亮度像素共享一对Cb/Cr。第二行的色度样本数和第一行一样所以记为“0”而不是“2:1”这是初学者最容易混淆的地方。计算一下不难发现4:2:2平均每像素2字节4:2:0平均每像素1.5字节而4:4:4是3字节。所以4:2:0是压缩率和质量权衡后的主流选择。2.4 采样格式怎么选人眼观看与机器视觉的不同逻辑不要以为4:2:0是万能答案机器视觉场景往往对画面质量有完全不同的要求。AI识别、车牌识别、OCR字符识别这类任务对彩色边缘细节、文字锐度敏感4:2:0下采样会让字符周围出现色渗和边缘锯齿直接影响识别率。我在做安防算法时测过同样的文字样本4:4:4转4:2:0之后中文字符的笔画边缘会出现一圈彩色光晕特别是红底白字、蓝底黄字这类高饱和场景。人眼看着还能接受但交给OCR模型后小字号字符的准确率掉了好几个点。所以工业上的选择准则其实是这样的以人眼观看为主直播、视频会议、娱乐视频优先用4:2:0以算法分析为主机器视觉、医学影像、自动驾驶则要考虑4:4:4甚至直接从RAW开始处理。很多工业相机宁可传输RAW也不提前转YUV就是不想让插值和下采样在源头就损失信息。3. 存储原理位深、布局与真实数据量3.1 位深决定了RAW能存下多少细节图像传感器ADC的采样精度直接决定了RAW的位深。8bit ADC只能把光强分成256级10bit是1024级12bit是4096级14bit是16384级。级数越多亮度变化越细腻暗部渐变越平滑。很多人以为RAW位深越高只是“文件越大”其实它决定的是采样的量化分辨率。高动态范围场景下亮部到暗部的亮度跨度很大8bit容易在暗部出现色阶断层和条带噪点12bit以上才能保证平滑过渡。这也是为什么手机厂商在宣传计算摄影时总强调“12bit RAW”多帧融合——只有12bit以上的采样精度才能给后期算法留出充足的处理余量。存储时还有一个容易被忽略的点很多RAW并非按整数个字节对齐存储。比如12bit数据2个像素共占3个字节10bit是4个像素共占5个字节。这就导致DMA搬运和内存寻址时必须做位操作处理不当就会出现数据错位、图像撕裂。3.2 一帧图到底占多少字节三类格式算给你看这是我觉得最实用的部分把手边的计算器拿出来一次算明白。公式很简单字节数 像素总数 × 每像素平均位数 ÷ 8。以1920×10801080P为例RAW光算12bit拜耳数据每个像素12 bit一帧大小就是1920×1080×12÷8 3110400字节约2.97MiB。如果传感器是10bit那就是2592000字节约2.47MiB。注意RAW的“每像素”只有一个分量不是三个。RGB888是每像素3字节一帧就是1920×1080×3 6220800字节约5.93MiB。RGB565是每像素2字节约3.96MiB多用在低成本嵌入式屏显。YUV420平均每像素1.5字节一帧也是3110400字节约2.97MiB。YUV422是每像素2字节约4.14MiB。你会发现YUV420和12bit RAW在文件大小上巧合地一致但前者包含完整的彩色信息且可直接显示后者还只是一堆拜耳数据二者不是一回事。4K分辨率下这三个数字得翻四倍3840×2160的12bit RAW约11.87MiBRGB888约23.73MiBYUV420约11.87MiB。如果按30fps视频流算每秒钟的数据量分别是356MiB、711MiB、356MiB写入存储设备的压力非常大这就解释了为什么视频系统缓存和存储带宽必须提前规划。3.3 NV12/NV21与打包格式YUV的存放姿势YUV除了采样模式还有内存排列方式这一步在实际工程里踩坑极多。按排列方式分三类打包格式packed、平面格式planar、半平面格式semi-planar。打包格式如YUYV、UYVYY和UV交错排在同一块内存里适合USB采集卡、SDI采集等边采边传的场景因为每个像素点都能直接顺序读到。平面格式如I420、YV12把所有Y排一块、所有U排一块、所有V排一块适合视频编码器的输入因为编码器往往希望把亮度平面单独读取。半平面格式如NV12、NV21是Y平面后面紧跟着一个YUV交织的UV平面Android相机默认输出和主流视频编码器最常用这种。存储顺序的坑主要在NV12的UV平面是CbCr交替排列NV21是CrCb交替排列二者转换时如果搞反画面会明显偏红或偏蓝。很多人在Linux上调V4L2摄像头相机输出NV12结果预览偏色查了半天是UV交换的问题。3.4 大码流场景下的存储与带宽规划实际项目中图像数据往往要落到本机、NAS、对象存储或者分布式存储集群里。我遇到过不少团队算法模型调通了结果采集端往服务器写数据时带宽爆了。这就是前期没算好存储压力。用上面的公式往实际需求里套假设一台设备输出1080P的RGB88830fps裸流写入是每秒186MB。即便按一天开工8小时算也有5.3TB数据量。这时候如果不对原始流做YUV/压缩转换直接上普通NAS或者对象存储性能和容量都会出大问题。所以监控、视频采集系统的常规方案都是先转YUV420再走H.264/H.265压缩把码率压到几Mbps以内才敢谈长期归档。如果你做的是存储系统选型一定先把输入流的“格式、分辨率、帧率、压缩比”四个参数拿全算好单路和多路的带宽总和再决定NAS的万兆网卡、缓存、磁盘阵列怎么配。这个计算逻辑别偷懒默认“差不多够用”的存储方案最容易在半路翻车。4. 格式转换与工程落地从RAW到YUV的完整路径4.1 YUV与RGB互转公式、色域与常见的偏色事故YUV和RGB互转是图像处理工程师几乎天天要写的代码。经典BT.601公式是这样的R Y 1.402 × (V - 128)G Y - 0.344136 × (U - 128) - 0.714136 × (V - 128)B Y 1.772 × (U - 128)但这里有一个极易忽略的坑就是“数值范围”。视频标准的YUV分full range和limited range两种full range的Y范围是0~255limited range的Y范围是16~235色度范围也不同。如果你把limited range的数据按full range公式去转RGB图像就会“发灰发白”黑不够黑白不够白。很多人在写好转换代码后遇到画面发雾八成就是范围没对齐。还有一个高频事故是通道顺序。OpenCV读取图像时用的是BGR不是RGBRGB转成YUV时如果你不小心把通道顺序弄反转换结果就是偏色的而且这种偏色特别隐蔽因为画面的边缘和明暗依然是对的只差颜色不对。建议工程里统一封装好转换函数并在函数入口明确标注输入输出格式从根上杜绝这类问题。4.2 从RAW到RGB再到YUVISP流水线的关键环节如果完整走一遍从RAW到YUV的路径你会看到一幅图像在相机内部经历的链条黑电平校准去偏置、坏点校正补缺陷、去马赛克生成RGB三通道、白平衡矫正色温、色彩校正矩阵让颜色更准、Gamma矫正适配人眼非线性感知最后再做RGB到YUV的转换和色度下采样。每一步都和采样、存储直接相关。黑电平校准时减掉的偏移量如果去不干净RAW数据整体偏色去马赛克算法会在RGB阶段引入伪色这个伪色在后面的YUV下采样阶段还可能被放大Gamma和色彩校正矩阵的每个系数都改变最终RGB的数值分布进而影响压缩编码的码率分配。所以如果你是做ISP或者摄像头调试的不能把RAW、RGB、YUV当成三个独立概念去理解它们是一条流水线上的不同阶段。调试时应该从RAW开始逐级检查我用过最笨也最有效的办法就是在每一级处理后面把当前中间结果单独存一帧图肉眼对比差异很快就能定位问题出在哪个环节。4.3 嵌入式采集链路中的采样对齐与缓冲规划嵌入式联调中最大的痛点是内存对齐。很多摄像头的DMA控制器按32字节对齐输出而图像宽度不一定正好是32的整数倍。如果只按宽度去分配缓冲区不做行对齐stride/pitchDMA搬运时下一行的起点就会错位画面出现斜向的撕裂条纹。以1920宽、RGB888为例每行占用5760字节。如果DMA要求32字节对齐一行实际占用的是ceil(5760/32)*325792字节多了32字节这个差值必须靠硬件“行尾填充”补上。在后续做检测、裁剪、缩放时也千万不能用width去计算行的偏移而要用stride否则内存越界访问会让你排查到怀疑人生。另一个常见问题是RAW位深和寄存器的对齐。假设你拿到12bit RAWCPU按16bit读一个像素没问题但如果你按字节读就涉及跨字节拆位。特别是在STM32或DSP这类MCU环境做ADC采集配合DMA时采样数据的位宽定义、DMA缓冲区大小、中断触发阈值都必须和格式位深严格对齐任何一个环节对不上图像就会变成碎片。5. 常见问题排查与避坑实录5.1 高频问题速查表我整理了一张在实际项目里反复遇到过的问题表直接对照排查能省下很多翻论坛的时间。症状常见原因排查方向RAW图像整体偏绿且发暗把Bayer数据当灰度或RGB直接显示先按单通道显示确认再做去马赛克图像出现反复的彩色斜纹内存行对齐不对stride计算错误检查DMA pitch分配时按32字节或64字节对齐YUV转RGB后画面发灰、发白full range和limited range没对齐先明确源YUV取值范围再选对应转换公式转换后颜色偏红或偏蓝NV12/NV21的UV顺序搞反检查CbCr与CrCb排列交换UV平面验证RGB图像比原图模糊、边缘有色边RAW去马赛克后未做锐化或边缘插值方向判断错误改用方向自适应插值确认后级锐化参数视频压缩后文字识别率下降4:2:0的色度下采样损伤小字边缘考虑用4:4:4或4:2:2近端处理后再压缩读取图片时颜色偏蓝偏绿OpenCV读入是BGR通道顺序用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)5.2 几条实测出的避坑经验做图像采集和视频存储这几年我踩了不少坑挑几条值得说的分享给同行。第一Bayer排列必须在硬件阶段就确认清楚不要靠猜。很多传感器厂家提供多档Bayer模式切换代码里默认设置是RGGB但实际模组焊的是GRBG导致整体图像偏绿带严重摩尔纹。最稳妥的办法是拿标准色卡在固定光源下拍一帧分别用RGGB、GRBG、BGGR、GBRG四种排列做去马赛克看哪个输出颜色正常一锤定音。这个操作能免去后面所有环节的连锁排查。第二RGB和YUV的内存布局转换宁可多写一个拷贝函数也不要相信“反正都是几个数组”这种侥幸心理。planar、semi-planar、packed三种布局在内存里的排列方式完全不同我见过不止一次因为直接强转指针类型做转换导致的内存越界和段错误。正确做法是写清楚输入输出布局按布局循环拷贝并用小分辨率测试图先验证。第三存储数据量估算时别忽略协议开销和文件系统块大小。比如按上一节算好的裸流大小落到本地实际磁盘占用还要考虑文件系统最小分配单元、RAID校验开销、集群副本数。如果走对象存储3副本就等于总数据量翻3倍。这些都要在带宽和容量规划时一并算进去否则上线没多久存储就爆了。最后的一点体会我把RAW、RGB、YUV三条线掰开揉碎讲清楚之后你可能会发现它们其实各司其职RAW是传感器对物理光的忠实采样记录RGB是显示端的全彩呈现YUV是传输压缩时对人眼视觉特性的巧妙利用。在实际项目中它仨不是“谁更好”的关系而是必须放在同一个更长的链路里去理解。我个人做调试时最受益的习惯是在数据流图的每个转换节点都打上“格式标签位宽布局”一眼看出当前是什么、下一级要什么。遇到问题先算一帧数据的理论大小是否对得上再回头检查采样格式和内存布局大部分疑难杂症其实都能这样顺藤摸瓜找到。希望你读完这篇文章后面对这些格式时能少走一些我当年走过的弯路。
返回列表