一、简介
YUV是一种表示颜色的模型。基于人眼对亮度高度敏感,对颜色敏感度低于亮度的生理特征 YUV在对照片或视频编码时候完整保存了像素的亮度分量(Y),根据不同的采样要求保存UV分量。
YUV可跟RBGA互转。但是我们常说的 YUV ,其实指的是 YCbCr,其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量,这里用 YUV 指代 YCbCr 。
二、YUV的采样和存储
由于人眼对 Y 的敏感度远超于对 U 和 V 的敏感,所以有时候可以多个 Y 分量共用一组 UV,这样既可以极大得节省空间,又可以不太损失质量。因此才会出现YUV 420,YUV 422,YUV 444的格式。
2.1 YUV采样方式
YUV 4:4:4:
表示 Y、U、V 三分量采样率相同,即每个像素的三分量信息完整,都是 8bit,每个像素占用 3 个字节。如果水平方向有 100 个像素点,那么采样了 100个 Y 分量,采样了 100 个 UV 分量。这种采样方式如图所示,图中以叉表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量。
YUV 4:2:2
YUV 4:2:2 采样,意味着 UV 分量是 Y 分量采样的一半,Y 分量和 UV 分量按照 2 : 1 的比例采样。如果水平方向有 100 个像素点,那么采样了 100个 Y 分量,而只采样了 50 个 UV 分量。采样方式如图所示:
YUV 4:2:0
YUV 4:2:0 采样,并不是指只采样 U 分量而不采样 V 分量。而是指,在每一行扫描时,只扫描一种色度分量(U 或者 V),和 Y 分量按照 2 : 1 的方式采样。比如,第一行扫描时,YU 按照 2 : 1 的方式采样,那么第二行扫描时,YV 分量按照 2:1 的方式采样。对于每个色度分量来说,它的水平方向和竖直方向的采样和 Y 分量相比都是 2:1 。假设第一行扫描了 U 分量,第二行扫描了 V 分量,那么需要扫描两行才能够组成完整的 UV 分量,则YUV 4:2:0采样方式如图所示:
采样方式比较
对于一张 1920*1280大小的图片,根据前面所述采样方式我们可以得出:
在 YUV 4:4:4 采样时的大小为:(19201280 * 8 + 19201280 * 1 * 8 * 2)/ 8 / 1024 / 1024 = 7.03 MB 。
在 YUV 4:2:2 采样时的大小为:(19201280 * 8 + 19201280 * 0.5 * 8 * 2)/ 8 / 1024 / 1024 = 4.69 MB 。
在 YUV 4:2:0 采样时的大小为:(19201280 * 8 + 19201280 * 0.25 * 8 * 2)/ 8 / 1024 / 1024 = 3.52 MB 。
由此可见YUV 4:4:4采样方式相比 RGB 模型图像并没有节省存储空间,YUV 4:2:2节省了三分之一的存储空间,在传输时占用的带宽也会随之减少;YUV 4:2:0 采样节省了一半的存储空间,因此它也是比较主流的采样方式。
2.2 YUV存储格式
YUV 数据有两种存储格式:
- 平面格式(planar format):先连续存储所有像素点的 Y,紧接着存储所有像素点的 U,随后是所有像素点的 V。从字面意思上来看,planar是平面的意思,对应到存储方式上就是把YUV三种分量分别存储,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。这种在解析时很方便。(该存储方式简称p,如420p)
- 打包格式(packed format):每个像素点的 Y、U、V 是连续交错存储的。从字面意思来看,packed是打包的意思,对应到存储方式上就是把YUV三种分量连续交叉存储,这种方式在解析时比较麻烦。
- 半平面格式(semi-planar format):是前两者的混合,一部分分量用 planar 方式存储,另一部分分量用 packed 分量存储。也就是先存储Y分量,之后UV分量连续存储。
以yuv为例,三种存储方式如下图所示:
代码中部分与YUV相关的数据格式:
mialgoengine
| enum | value |
|---|---|
| CAM_FORMAT_YUV_420_NV21 | 17 |
| CAM_FORMAT_YUV_420_NV12 | 35 |
| CAM_FORMAT_Y16 | 540422489 |
| CAM_FORMAT_YV12 | 842094169 |
camxhal3
| enum | value |
|---|---|
| HAL_PIXEL_FORMAT_YCBCR_422_SP | 16 |
| HAL_PIXEL_FORMAT_YCRCB_420_SP | 17 |
| HAL_PIXEL_FORMAT_YCBCR_422_I | 20 |
| HAL_PIXEL_FORMAT_YCBCR_420_888 | 35 |
| HAL_PIXEL_FORMAT_Y8 | 538982489 |
| HAL_PIXEL_FORMAT_Y16 | 540422489 |
| HAL_PIXEL_FORMAT_YV12 | 842094169 |
注:预览的格式是HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED 34,不会经过算法框架后处理(可能是处理时间的原因)
以上格式是依据采样方式和存储方式,以使用较多的YUV_420_NV12为例(HAL_PIXEL_FORMAT_YCBCR_420_888)
采样方式为:每个像素有一个Y值、4个像素共用一对U、V值(4:2:0 4:0:2)
存储方式为:NV12则表明以planer+packed方式存储,Y单独存储、UV间隔存储,且先U后V。
2.3 常见的几种YUV格式分析
下面以一张8*4分辨率的单帧图像分析几种常见格式的yuv图像。
YV12 /YU12
YV12/YU12(也称 I420) 属于 YUV420P ,即 YUV420 采样方式的plane模式,YUV 三个分量分别存储于 3 个不同的矩阵(平面)。YV12储存方式如下图所示:
这幅图可以看出 Y1、Y2、Y9、Y10 共用V1 和 U1,其他未列出的均类似。
相对应的码流为(篇幅过长省略了Y17-Y32,V5-V8,U5-U8):
| Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 | Y9 | Y10 | Y11 | Y12 | Y13 | Y14 | Y15 | Y16 | ... | V1 | V2 | V3 | V4 | ... | U1 | U2 | U3 | U4 | ... |
|---|
线性数组为其存储顺序,可以看出 Y、U 和 V 都是顺序存储的,往外写的时候,先按顺序将 Y 分量写出,然后再根据 V、U 分别将它们依次写出即可。
NV21 和 NV21
NV12 和 NV21 格式都属于 YUV420SP 类型,手机摄像头采集预览数据就为这两种格式。YUV420SP 格式有 2 个平面,Y 分量存储于一个平面,UV 分量交错存储于另一个平面。
NV12 和 NV21 格式都先存储了 Y 分量,但接下来并不是再存储所有的 U 或者 V 分量,而是把 UV 分量交替连续存储。NV12 是 IOS 中有的模式,它的存储顺序是先存 Y 分量,再 UV 进行交替存储,按照[YYUV]格式进行存放;NV21 是 安卓 中有的模式,它的存储顺序是先存 Y 分量,在 VU 交替存储,按照[YYVU]格式进行存放。NV21储存方式如下图:
这幅图可以看出与 YV12 不同的时,它的 Y 虽然也是顺序存储,但 U、V 却是交错存储的。同时可以看出 Y1、Y2、Y9、Y10 共用V1 和 U1,其他未列出的均类似。
相对应的码流为(篇幅过长省略了Y17-Y32,V5U5-V8U8):
| Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 | Y9 | Y10 | Y11 | Y12 | Y13 | Y14 | Y15 | Y16 | ... | V1 | U1 | V2 | U2 | V3 | U3 | V4 | U4 | ... |
|---|
这种方式存储在往外写出时则先直接顺序写出 Y,然后对 VU 交错写出。
常用格式
| 格式名 | 存储方式 |
|---|---|
| YU12(I420格式、420P) | 先把全部的Y分量存完,再存U分量,最后存V分量。 |
| YV21(420P) | 先把全部的Y分量存完,再存V分量,最后存U分量。 |
| NV12(420sp) | (planer+packed)先存储全部的Y分量,然后UV分量交叉存储。(半平面(Semi-Planar)) |
| NV21(420sp) | (planer+packed)先存储全部的Y分量,然后VU分量交叉存储。 |
| YUV422P | planer存储,与YU12存储类似,只是422是两组Y分量共用一组UV分量(4:2:2、4:2:2) |
| YUYV/YVYU/UYVY | 间隔存储,先Y、再U、再Y、再V(后面两个类似) |
高通的P010 format官方描述
同:存放的数据都是4:2:0 10bit YUV数据
异:Android的数据是16字节对齐的,而高通的对齐方式不太标准,具体差异如图所示: