大家好,又见面了,我是你们的朋友全栈君。
简介
YUV是视频、图片、相机等应用中使用的一类图像格式,实际上是所有“YUV”像素格式共有的颜色空间的名称。 与RGB格式(红 – 绿 – 蓝)不同,YUV是用一个称为Y(相当于灰度)的“亮度”分量和两个“色度”分量表示,分别称为U(蓝色投影)和V(红色投影),由此得名。
YUV也可以称为YCbCr,虽然这些术语意味着略有不同,但它们往往会混淆并可互换使用。
Y表示亮度分量:如果只显示Y的话,图像看起来会是一张黑白照。
U(Cb)表示色度分量:是照片蓝色部分去掉亮度(Y)。
V(Cr)表示色度分量:是照片红色部分去掉亮度(Y)。
要说清楚YUV,得分别说清楚以下两点:
- YUV的采样格式:即我们在采集图片、视频帧时,是如何获取每个像素的Y、U、V三个分量的。
- YUV的存储格式:即Y、U、V三个分量的值,是以什么方式存储在内存或者文件中的。
为了理解这两点,破费功夫,只因没有在网上找到比较让人满意的解读。最后找到了两篇文档:
YUV采样格式
什么是扫描线(scan line)
为了说明采样格式,先说明一下待会儿会用的的概念:扫描线
什么是扫描线?这是关于电视显示的术语,用来描述电视是如何显示画面的。wiki中是这么解释的:
电视萤幕由电子枪射出的电子,经由磁场偏向后打在屏幕上而发光,因此每一个图框都由电子枪的扫描线画出来。
大概意思如下图:图片来源
电子枪的扫描线从左上角像素点到右下角像素点顺序移动,喷射电子显像。
我猜,这种像素的显示方式也对像素的采样方式产生了影响,YUV采样格式中就大量提到了扫描线,至于这中间是否有什么历史”恩怨”,大家如果知道,不妨留言分享。
宏像素 (macropixels)
像素是视频显示的基本单位,因为它代表了屏幕上一个”点”的色彩,通常也会被形象地称为”像素点”。通常RGB格式像素点,会有Red、Green、Blue三个基本像素分量组成。也就是说,只要确定了红、绿、蓝三个像素分量就能确定这个像素将要显示什么。
同理,YUV格式也可以分为三个分量,即Y、U、V一一对应。
但和RGB不一样的是,利用人体眼睛对亮度分量(Y)敏感,而对色度分量(U和V)不敏感的原理,视频可以通过降低色度分量的采样数据,达到降低视频数据量而人眼很难分辨的目的。所以,目前流行的YUV采样,基本都是降低色度分量的采集。
也就是说,一个视频帧中,亮度分量Y的采样数不会被改变,但色度分量U和V会被降低采样数(downsampling)。如此一来,Y、U、V三个分量将无法达到和RGB一样一一对应的效果。
好在YUV所有的格式中,U、V分量的采样数是相等的,只是不同的Y分量之间,需要共享数量不足的UV分量,为了让这个共享更好的表达,YUV出现了宏像素的概念。即:当前格式下,至少需要x个像素点的采样数据,才能将这x个像素点完整表达,这几个像素点组成了一个宏像素,每个像素点称为宏像素点。所谓的完整表达,也就是让所有的Y分量都有对应的UV分量可以使用。
如果看到这里,还不是很懂,你可以先跳过这节,这对后文的阅读影响不是很大。
宏像素的概念,是从微软家的那个文档看到的,但他家没做任何解释,网上也没有。这一节的内容,实际上是本人自己琢磨了好久才总结出来的。受限知识水平,请大家谨慎参考,如果有大神发现有误,请留言帮帮小弟,一拜……再拜……
YUV4:4:4
YUV格式,采用A:B:C表示法用于描述UV色度分量相对于Y分量的采样率。这怎么理解呢,以YUV4:4:4为例。
YUV4:4:4的采样方式表示:各采样分量在扫面每个像素点时,都不会降低采样率。
如图,一个方格表示一个像素点,方格中的YUV分别表示有在该像素点采YUV分量。之所以用四个方格显示,是因为YUV格式中,UV分量最小时需要四个像素共享一个UV分量对。同时,共享一个UV分量对的像素点,在平面上和UV分量都有临近的关系,所以这四个像素点不会是同一条扫面线上的点,而是分布在两条扫描线上。
所以,一个宏像素最多容纳四个宏像素点。而在YUV4:X:X的表示法中,的4表达的也是这个意思。
从图可以看出,YUV4:4:4的采样方式,是对每个像素点进行Y、U、V分量的全采样。
关于内存占用,因为YUV模式的每个分量都是存储在一个字节(8bit)中的。
所以,对于四个像素,YUV4:4:4格式需要4*8 + 4*8 + 4*8 = 96位,因此,每个像素深度为24位。
YUV4:2:2
YUV4:2:2的采样方式表示:水平方向Y分量与UV分量2:1采样,垂直方向不降低采样率。也就是这样:
水平方向上的两个像素点组成了一个宏像素,两个像素点共享一对UV像素分量。
至于U和V分量是从水平方向第一个像素采集,还是分开到两个像素采集。如果是分开采集,是先采U分量还是先采集V分量,这个可能需要更专业的解释了。根据我搜索到的资料,最准确的说法只是,在扫描线上,水平方向上的UV分量是Y分量的一半。
对于四个像素,YUV4:2:2格式需要4*8 + 2*8 + 2*8 = 64位,每个像素深度为16位。
YUV4:2:0
YUV4:2:2的采样方式表示:水平和垂直方向上Y分量和UV分量对的采样比都是2:1。
目前YUV4:2:0有两种变体,一种用于MPEG-1标准如下图:
另一个常用语MPEG-2标准,我们经常见到的4:2:0通常都是这种。如下图:
对于四个像素,YUV4:2:0格式需要4*8 + 8 + 8 = 48位,每个像素深度为12位。
YUV存储格式
YUV的存储格式分为打包格式(packet formats)和平面格式(planar formats)。
在打包格式中,Y,U和V组件存储在单个数组中,YUV三个分量是顺序交错存储。 像素被组织成宏像素组,其布局取决于采样格式。
在平面格式中,Y,U和V分量存储在三个不同的平面(数组)中。YUV三个分量被分开存储在三个不同的数组中。
4:4:4,24位像素深度
YUV4:4:4实际上表达的是:采样模式位4:4:4的打包存储的数据。它的存储方式如图:
一个小方格代表一个字节,一组连续的小方格代表一个像素。
4:2:2,16位像素深度
4:2:2的采样格式共有两种存储方式
- YUY2
- UYVY
它们的存储方式都是打包格式,其中每个宏像素是两个像素,编码为四个连续字节。
YUY2
在YUY2格式中,中第一个字节包含第一个Y样本,第二个字节包含第一个U(Cb)样本,第三个字节包含第二个Y样本,以及 第四个字节包含第一个V(Cr)样本,如图所示:
UYVY
这种格式与YUY2相同,只是字节顺序颠倒了 – 也就是说,色度和亮度字节被翻转,如图:
4:2:0,12位像素深度
下面要介绍的4:2:0格式都采用了平面存储模式,共有四种:
- IMC2
- IMC4
- YV12
- NV12
所有的4:2:0模式,色度分量无论是在水平还是垂直方向上,采样数都是亮度分量的1/4。
IMC2
IMC2格式的存储方式如图:
每个分量以一个字节存储,平面存储格式的意思就是,先存储视频帧中所有的Y分量。Y分量存储完之后,才开始存储色度分量。在IMC2格式中,YUV三分量的存储关系是:先存所有的Y分量、再存所有的V分量,最后存储U分量。
为了便于处理和表达,通常在代码中会以三个数组来分别装着三个分量。
另外需要提一嘴,在IMC2格式中,存储UV分量的内存空间步长分别是存储Y分量的一半。另外因为色度分量的采样书是Y分量的1/4,所以,及时色度分量占用空间是亮度分量的一半,也会有一些空闲的内存。
IMC4
和IMC2格式类似,只是U、V两个色度分量的存储顺序对调了一下。
YV12&I420
YV12格式的存储方式又有变化,存储色度分量的内存步幅是亮度分量的一半,首先Y分量数据以unsigned char数组的形式存储,紧跟着后面存V分量,最后存U分量。
I420和YV12的存储方式差不多,区别的地方在于,I420的Y分量后,存储的是U分量,最后存V分量,色度分量的存储顺序替换了一下。另外I420也被称为YUV420P。
YV12、I420、YUV420p这三个名词在多媒体开发中,是出现频率比较高的是那个了。大家不妨记忆一下
NV12
NV12格式首先存储Y分量平面,作为具有偶数行的无符号字符值数组。 Y平面后面紧跟着一个无符号字符值数组,其中包含打包的U(Cb)和V(Cr)样本。
剧终
本文以理解为主,部分讲述并不代表事实,在生产场景这已经够用了。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160239.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...